From e76655a48f0452eb31760097c61889d9004a29c4 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Wed, 15 Jul 2015 14:32:20 -0700 Subject: [PATCH] Fixed I/O port handling --- blog/2015/07/14/README.md | 406 +++++++++++++++++++++++++++++++++++ modules/pcjs/lib/debugger.js | 20 +- modules/pcjs/lib/x86ops.js | 32 +-- 3 files changed, 438 insertions(+), 20 deletions(-) create mode 100644 blog/2015/07/14/README.md diff --git a/blog/2015/07/14/README.md b/blog/2015/07/14/README.md new file mode 100644 index 000000000..6ef22118c --- /dev/null +++ b/blog/2015/07/14/README.md @@ -0,0 +1,406 @@ +Windows 95 +--- + +First off, let me just say: + +> Happy Windows 95 RTM Day! + +because today, July 14, 2015, is the 20th anniversary of Windows 95 RTM ("Release To Manufacturing"). + +Now, to business. Today is also the first day I tried running Windows 95 SETUP inside a PCjs machine. And it +immediately failed: + + Please wait while Setup initializes. + Windows requires a computer with an 80386 processor or higher. + +The failing code: + + 0E36:08FD 06 PUSH ES + 0E36:08FE 1E PUSH DS + 0E36:08FF 9C PUSHF + 0E36:0900 33C0 XOR AX,AX + 0E36:0902 50 PUSH AX + 0E36:0903 9D POPF + 0E36:0904 9C PUSHF + 0E36:0905 58 POP AX + 0E36:0906 A90080 TEST AX,8000 + 0E36:0909 7517 JNZ 0922 + 0E36:090B B80070 MOV AX,7000 + 0E36:090E 50 PUSH AX + 0E36:090F 9D POPF + 0E36:0910 FB STI + 0E36:0911 9C PUSHF + 0E36:0912 58 POP AX + 0E36:0913 A90070 TEST AX,7000 + 0E36:0916 7405 JZ 091D + 0E36:0918 B88603 MOV AX,0386 + 0E36:091B EB08 JMP 0925 + 0E36:091D B88602 MOV AX,0286 + 0E36:0920 EB03 JMP 0925 + 0E36:0922 B88600 MOV AX,0086 + 0E36:0925 9D POPF + 0E36:0926 1F POP DS + 0E36:0927 07 POP ES + 0E36:0928 C3 RET + +was easily fixed with a change to [x86cpu.js](/modules/pcjs/lib/x86cpu.js), allowing the IOPL bits to be +modified in real-mode on an 80386. When I had previously tweaked setPS() to accomodate 80286/80386 discrimination +logic in OS/2 1.0, there was no 80386 support in PCjs at that time, so it was sufficient to *never* allow the +IOPL bits to change in real-mode. + +Following the CPU test, Setup proceeded a bit farther: + + EAX=00000001 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:0E4F E8D412 CALL 2126 ;cycles=7 + + 0E36:2126 E877E7 CALL 08A0 + 0E36:2129 0BC0 OR AX,AX + 0E36:212B 741D JZ 214A + 0E36:212D 6A00 PUSH 0000 + 0E36:212F 6A00 PUSH 0000 + 0E36:2131 68C700 PUSH 00C7 + 0E36:2134 E8C1F8 CALL 19F8 + 0E36:2137 83C406 ADD SP,0006 + + EAX=00000001 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:2126 E877E7 CALL 08A0 ;cycles=7 + + EAX=00000001 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33A EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08A0 56 PUSH SI + + EAX=00000001 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C338 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08A1 57 PUSH DI ;cycles=3 + + EAX=00000001 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08A2 B80016 MOV AX,1600 ;cycles=3 (WIN386CHECK) + + EAX=00001600 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08A5 CD2F INT 2F ;cycles=2 + + EAX=00001600 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08A7 A87F TEST AL,7F ;cycles=133 + + EAX=00001600 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08A9 B80300 MOV AX,0003 ;cycles=3 + + EAX=00000003 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08AC 752A JNZ 08D8 ;cycles=2 + + EAX=00000003 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08AE B80A16 MOV AX,160A ;cycles=3 (INSTALLCHECK) + + EAX=0000160A EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08B1 CD2F INT 2F ;cycles=2 + + EAX=0000160A EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08B3 0BC0 OR AX,AX ;cycles=133 + + EAX=0000160A EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08B5 740E JZ 08C5 ;cycles=2 + + EAX=0000160A EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08B7 B88046 MOV AX,4680 ;cycles=3 (WINOLDAP30CHECK) + + EAX=00004680 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08BA CD2F INT 2F ;cycles=2 + + EAX=00004680 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08BC 0BC0 OR AX,AX ;cycles=133 + + EAX=00004680 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08BE 7516 JNZ 08D6 ;cycles=2 + + EAX=00004680 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000202 V0 D0 I1 T0 S0 Z0 A0 P0 C0 + 0E36:08D6 33C0 XOR AX,AX ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08D8 5F POP DI ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C338 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08D9 5E POP SI ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33A EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08DA C3 RET ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2129 0BC0 OR AX,AX ;cycles=11 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:212B 741D JZ 214A ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:214A E88EE7 CALL 08DB ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33A EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08DB 1E PUSH DS ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C338 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08DC 06 PUSH ES ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08DD 57 PUSH DI ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C334 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08DE 56 PUSH SI ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C332 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08DF 53 PUSH BX ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C330 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08E0 52 PUSH DX ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08E1 B81116 MOV AX,1611 ;cycles=3 (WIN386GETSHELL) + + EAX=00001611 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08E4 33DB XOR BX,BX ;cycles=2 + + EAX=00001611 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08E6 CD2F INT 2F ;cycles=2 + + EAX=00001611 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:08E8 0BC0 OR AX,AX ;cycles=133 + + EAX=00001611 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08EA B80000 MOV AX,0000 ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08ED 7507 JNZ 08F6 ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08F6 5A POP DX ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C330 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08F7 5B POP BX ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C332 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08F8 5E POP SI ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C334 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08F9 5F POP DI ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08FA 07 POP ES ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C338 EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08FB 1F POP DS ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33A EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:08FC C3 RET ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:214D 0BC0 OR AX,AX ;cycles=11 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:214F 7415 JZ 2166 ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2166 33C0 XOR AX,AX ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2168 C3 RET ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:0E52 0BC0 OR AX,AX ;cycles=11 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:0E54 7406 JZ 0E5C ;cycles=2 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33E EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:0E5C E80B13 CALL 216A ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C33C EBP=0000C444 ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:216A C8040000 ENTER 0004,00 ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C336 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:216E 57 PUSH DI ;cycles=11 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C334 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:216F 56 PUSH SI ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C332 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2170 52 PUSH DX ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C330 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2171 50 PUSH AX ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2172 B80030 MOV AX,3000 ;cycles=3 + + EAX=00003000 EBX=00000000 ECX=00000018 EDX=00000000 + ESP=0000C32E EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2175 CD21 INT 21 ;cycles=2 + + EAX=00001E03 EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C32E EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2177 86E0 XCHG AH,AL ;cycles=551 + + EAX=0000031E EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C32E EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:2179 A3F697 MOV [97F6],AX ;cycles=3 + + EAX=0000031E EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C32E EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:217C 58 POP AX ;cycles=3 + + EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C330 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:217D 5A POP DX ;cycles=5 + + EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C332 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0 + 0E36:217E 813EF697000A CMP [97F6],0A00 ;cycles=5 + 1A4F:97F6 031E 0000 0000 0001 1A4F 0000 0000 1A4F ........O.....O. + + EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C332 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000287 V0 D0 I1 T0 S1 Z0 A0 P1 C1 + 0E36:2184 7210 JC 2196 ;cycles=7 + + EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C332 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000287 V0 D0 I1 T0 S1 Z0 A0 P1 C1 + 0E36:2196 813EF6971403 CMP [97F6],0314 ;cycles=7 (DOS 3.20 is the MINIMUM supported DOS version) + + EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 + ESP=0000C332 EBP=0000C33A ESI=00004748 EDI=00004748 + SS=1A4F DS=1A4F ES=0000 FS=0000 GS=0304 PS=00000206 V0 D0 I1 T0 S0 Z0 A0 P1 C0 + 0E36:219C 7308 JNC 21A6 ;cycles=7 + +So far, so good, since I was running PC-DOS 3.30. However, the next error message I received was: + + Not enough free Extended/XMS memory to run Setup. + Setup needs approximately 2816000 bytes of free Extended/XMS memory. + +I was running a machine with only 1Mb of extended memory. Time to install more memory and try again. + +--- + +OK, that was easy. The next problem was triggered by the CAB ("Diamond") decompression code in Windows 95 Setup, +which uses all 32 bits of the 80386's 32-bit registers. That was not a problem, but by leaving stray bits in the +upper halves of registers like EDX, it exposed a bug in the PCjs I/O instruction handlers, which neglected to mask +EDX with 0xFFFF before performing port lookup, causing mysterious I/O failures that usually manifested themselves +as hard disk I/O errors. + +More later. + +*[@jeffpar](http://twitter.com/jeffpar)* +*July 14, 2015* diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 179f281f0..83011b85f 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1241,13 +1241,13 @@ if (DEBUGGER) { 0x3A: "remove subdirectory $%DS:%DX", 0x3B: "set current directory $%DS:%DX", 0x3C: "create or truncate file $%DS:%DX with attributes %CX", - 0x3D: "open existing file $%DS:%DX with mode %AL", + 0x3D: "open file $%DS:%DX with mode %AL", 0x3E: "close file %BX", 0x3F: "read %CX bytes from file %BX into buffer %DS:%DX", 0x40: "write %CX bytes to file %BX from buffer %DS:%DX", 0x41: "delete file $%DS:%DX", 0x42: "set position %CX:%DX of file %BX relative to %AL", - 0x43: "get(0)/set(1) attributes %CX of file %DS:%DX (%AL)", + 0x43: "get(0)/set(1) attributes %CX of file $%DS:%DX (%AL)", 0x44: "get device information (IOCTL)", 0x45: "duplicate file handle %BX", 0x46: "force file handle %CX to duplicate file handle %BX", @@ -1267,12 +1267,16 @@ if (DEBUGGER) { 0x54: "get verify flag (AL)", 0x55: "create child PSP at segment %DX", 0x56: "rename file $%DS:%DX to $%ES:%DI", - 0x57: "get(0)/set(1) file date %DX and time %CX (%AL)", + 0x57: "get(0)/set(1) file %BX date %DX and time %CX (%AL)", 0x58: "get(0)/set(1) memory allocation strategy (%AL)", // DOS 2.11+ 0x59: "get extended error information", // DOS 3.00+ 0x5A: "create temporary file $%DS:%DX with attributes %CX", // DOS 3.00+ 0x5B: "create file $%DS:%DX with attributes %CX", // DOS 3.00+ (doesn't truncate existing files like 0x3C) - 0x5C: "lock(0)/unlock(1) file %BX region %CX:%DX length %SI:%DI (%AL)" // DOS 3.00+ + 0x5C: "lock(0)/unlock(1) file %BX region %CX:%DX length %SI:%DI (%AL)", // DOS 3.00+ + 0x5D: "critical error information (%AL)", // DOS 3.00+ (undocumented) + 0x60: "get fully-qualified filename from $%DS:%SI", // DOS 3.00+ (undocumented) + 0x63: "get lead byte table (%AL)", // DOS 2.25 and 3.20+ + 0x6C: "extended open file $%DS:%SI" // DOS 4.00+ } }; @@ -2226,7 +2230,7 @@ if (DEBUGGER) { sChar = s.substr(i+1, 2); b = str.parseInt(sChar, 16); if (b != null && b >= 32 && b < 128) { - sReplace = '#' + sChar + " '" + String.fromCharCode(b) + "'"; + sReplace = sChar + " '" + String.fromCharCode(b) + "'"; s = s.replace('#' + sChar, sReplace); i += sReplace.length; continue; @@ -2833,10 +2837,10 @@ if (DEBUGGER) { return true; } /* - * Halt whenever ring 3 code is running with interrupts disabled, because that's likely an - * error (TODO: we should also check the IOPL, too, because if IOPL is 3, then this is OK). + * Halt if running with interrupts disabled and IOPL < CPL, because that's likely an error */ - if (this.cpu.segCS.cpl == 3 && !(this.cpu.regPS & X86.PS.IF)) { + if (!(this.cpu.regPS & X86.PS.IF) && this.cpu.nIOPL < this.cpu.segCS.cpl) { + this.printMessage("interrupts disabled at IOPL " + this.cpu.nIOPL + " and CPL " + this.cpu.segCS.cpl, true); return true; } } diff --git a/modules/pcjs/lib/x86ops.js b/modules/pcjs/lib/x86ops.js index 0e44ece11..fde03e0d8 100644 --- a/modules/pcjs/lib/x86ops.js +++ b/modules/pcjs/lib/x86ops.js @@ -1347,7 +1347,6 @@ X86.opFS = function FS() this.opFlags |= X86.OPFLAG.SEG | X86.OPFLAG.NOINTR; this.segData = this.segStack = this.segFS; this.nStepCycles -= this.cycleCounts.nOpCyclesPrefix; - this.stopCPU(); }; /** @@ -1364,7 +1363,6 @@ X86.opGS = function GS() this.opFlags |= X86.OPFLAG.SEG | X86.OPFLAG.NOINTR; this.segData = this.segStack = this.segGS; this.nStepCycles -= this.cycleCounts.nOpCyclesPrefix; - this.stopCPU(); }; /** @@ -1475,7 +1473,7 @@ X86.opINSb = function INSb() } if (nReps--) { - var b = this.bus.checkPortInputNotify(this.regEDX, this.regLIP - nDelta - 1); + var b = this.bus.checkPortInputNotify(this.regEDX & 0xffff, this.regLIP - nDelta - 1); if (BACKTRACK) this.backTrack.btiMemLo = this.backTrack.btiIO; this.setSOByte(this.segES, this.regEDI & this.addrMask, b); this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask); @@ -1524,7 +1522,7 @@ X86.opINSw = function INSw() var addrFrom = this.regLIP - nDelta - 1; var w = 0, shift = 0; for (var n = 0; n < this.dataSize; n++) { - w |= this.bus.checkPortInputNotify(this.regEDX, addrFrom) << shift; + w |= this.bus.checkPortInputNotify(this.regEDX & 0xffff, addrFrom) << shift; shift += 8; if (BACKTRACK) { if (!n) { @@ -1581,7 +1579,7 @@ X86.opOUTSb = function OUTSb() this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask); this.nStepCycles -= nCycles; if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMemLo; - this.bus.checkPortOutputNotify(this.regEDX, b, this.regLIP - nDelta - 1); + this.bus.checkPortOutputNotify(this.regEDX & 0xffff, b, this.regLIP - nDelta - 1); this.regECX = (this.regECX & ~this.addrMask) | ((this.regECX - nDelta) & this.addrMask); if (nReps) { if (BUGS_8086) { @@ -1634,7 +1632,7 @@ X86.opOUTSw = function OUTSw() this.backTrack.btiIO = this.backTrack.btiMemHi; } } - this.bus.checkPortOutputNotify(this.regEDX, (w >> shift) & 0xff, addrFrom); + this.bus.checkPortOutputNotify(this.regEDX & 0xffff, (w >> shift) & 0xff, addrFrom); shift += 8; } this.regECX = (this.regECX & ~this.addrMask) | ((this.regECX - nDelta) & this.addrMask); @@ -3623,7 +3621,12 @@ X86.opINw = function INw() var port = this.getIPByte(); this.regEAX = this.bus.checkPortInputNotify(port, this.regLIP - 2); if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO; - this.regEAX |= (this.bus.checkPortInputNotify((port + 1) & 0xffff, this.regLIP - 2) << 8); + /* + * TODO: Specs are clear that bits 8-15 of the port address for the FIRST byte of I/O will be zero, but + * what about the SECOND byte? If the port is 0xff, will the SECOND byte of I/O use port 0x00 or 0x100? + * Our code (below) assumes the latter. Mask (port + 1) with 0xff if it turns out the former is true. + */ + this.regEAX |= (this.bus.checkPortInputNotify(port + 1, this.regLIP - 2) << 8); if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiIO; this.nStepCycles -= this.cycleCounts.nOpCyclesInP; }; @@ -3649,7 +3652,12 @@ X86.opOUTw = function OUTw() { var port = this.getIPByte(); this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 2); - this.bus.checkPortOutputNotify((port + 1) & 0xffff, this.regEAX >> 8, this.regLIP - 2); + /* + * TODO: Specs are clear that bits 8-15 of the port address for the FIRST byte of I/O will be zero, but + * what about the SECOND byte? If the port is 0xff, will the SECOND byte of I/O use port 0x00 or 0x100? + * Our code (below) assumes the latter. Mask (port + 1) with 0xff if it turns out the former is true. + */ + this.bus.checkPortOutputNotify(port + 1, this.regEAX >> 8, this.regLIP - 2); this.nStepCycles -= this.cycleCounts.nOpCyclesOutP; }; @@ -3711,7 +3719,7 @@ X86.opJMPs = function JMPs() */ X86.opINDXb = function INDXb() { - this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(this.regEDX, this.regLIP - 1); + this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(this.regEDX & 0xffff, this.regLIP - 1); if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO; this.nStepCycles -= this.cycleCounts.nOpCyclesInDX; }; @@ -3723,7 +3731,7 @@ X86.opINDXb = function INDXb() */ X86.opINDXw = function INDXw() { - this.regEAX = this.bus.checkPortInputNotify(this.regEDX, this.regLIP - 1); + this.regEAX = this.bus.checkPortInputNotify(this.regEDX & 0xffff, this.regLIP - 1); if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO; this.regEAX |= (this.bus.checkPortInputNotify((this.regEDX + 1) & 0xffff, this.regLIP - 1) << 8); if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiIO; @@ -3738,7 +3746,7 @@ X86.opINDXw = function INDXw() X86.opOUTDXb = function OUTDXb() { if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiAL; - this.bus.checkPortOutputNotify(this.regEDX, this.regEAX & 0xff, this.regLIP - 1); + this.bus.checkPortOutputNotify(this.regEDX & 0xffff, this.regEAX & 0xff, this.regLIP - 1); this.nStepCycles -= this.cycleCounts.nOpCyclesOutDX; }; @@ -3750,7 +3758,7 @@ X86.opOUTDXb = function OUTDXb() X86.opOUTDXw = function OUTDXw() { if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiAL; - this.bus.checkPortOutputNotify(this.regEDX, this.regEAX & 0xff, this.regLIP - 1); + this.bus.checkPortOutputNotify(this.regEDX & 0xffff, this.regEAX & 0xff, this.regLIP - 1); if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiAH; this.bus.checkPortOutputNotify((this.regEDX + 1) & 0xffff, this.regEAX >> 8, this.regLIP - 1); this.nStepCycles -= this.cycleCounts.nOpCyclesOutDX;