now testing in bochs 2.0.2 with debugger and fdxm286t ps / emm38606: > ... global enable a20, local enable a20 abwechselnd ... > local_enable_a20 EPROM at c000:0000, size 32 KB using PAGEFRAME e000:0000 choosen FRAME address e000 > query_free_xms XMSlargest block 0x1bc0(7104), XMStotal mem 0x1bc0(7104) > alloc_xms > alloc_xms allocated 4352kb from XMS > lock_xms MONITOR_ADDR 110000 EMM_MEMORY_END 550000 TOTAL_MEMORY 800000 > now mode switch to v86 happens, trapped by "modebp"... (0) [0x000086f8] 0855:01a8 (unk. ctxt): mov AX, 07dd ; b8dd07 Stack: 00007dd0 [00000100] 00dd 0413 003d 9fc0 f065 f000 310e c000 ff53 f000 ff53 f000 004d 9fc0 ff53 f000 ... the switch happens after int hookings and some 32bit calc ... 000086e9: mov DS:01c0, DL ; 8816c001 000086ed: jmp 06c4:0000 ; ea0000c406 000086f2: mov AH, 09 ; b409 000086f4: int 21 ; cd21 000086f6: jmp 871f ; eb27 000086f8: mov AX, 07dd ; b8dd07 <<< 000086fb: mov DS, AX ; 8ed8 000086fd: mov SS, AX ; 8ed0 000086ff: mov SP, 2330 ; bc3023 00008702: push cs ; 0e 00008703: call 908d ; e88709 00008706: mov AX, 06f4 ; b8f406 00008709: add AX, 0200 ; 050002 0000870c: mov [CS:0068], AX ; 2ea36800 00008710: mov SS, CS:0064 ; 2e8e166400 00008715: mov SP, CS:0066 ; 2e8b266600 0000871a: mov AX, [CS:0068] ; 2ea16800 0000871e: ret_far ; cb 0000871f: ... 0000872b: jmp 8810 ; ebe3 ... 872d: ... CPU test ... xxxx: protected mode test ... ... xxxx: print decimal number ... ... 8770: ... 8792: ... CPU states: CR -> pg=1, not caching, not write through, et=1 ts=0 em=0 mp=0 pe=1, ... > info registers eax 0xe0000011 ecx edx ebx ebp esi edi all 0, also ES and FS 0. esp 0x100 0x100 eip 0x1a8 0x1a8 eflags 0x23202 cs 0x855 ss 0x7cd ds 0x413 > info gdt Global Descriptor Table (0x0000429c): GDT[0x00]=??? descriptor hi=00000000, lo=00000000 08 GDT[0x01]=LDT 10 GDT[0x02]=32-Bit TSS (Busy) at 001216a0, length 0x02069 18 GDT[0x03]=32-Bit TSS (Available) at 00004af4, length 0x00068 20 GDT[0x04]=Code segment, linearaddr=000040f0, len=0ffff by, Exec/R, 16bit 28 GDT[0x05]=Data segment, linearaddr=00000000, len=0ffff by, R/W 30 GDT[0x06]=Data segment, linearaddr=00000000, len=fffff * 4K, R/W, Accessed 38 GDT[0x07]=??? descriptor hi=00000000, lo=00000000 > info idt ... IDT[0x00]=32-Bit Interrupt Gate target=000c:000005ec, DPL=3 IDT[0x01]=32-Bit Interrupt Gate target=000c:000005f0, DPL=3 ... IDT[0x66]=32-Bit Interrupt Gate target=000c:00000784, DPL=3 IDT[0x67]=32-Bit Interrupt Gate target=000c:00000788, DPL=3 IDT[0x68]=32-Bit Interrupt Gate target=000c:0000078c, DPL=3 ... dirty phys pages: 0..0x14,0x21,0x24,0x27,0x8a..0xa1,0xb8..0xbf,0x120..0x128 ... ... (0) Caught vm mode switch breakpoint to protected mode (0) [0x0012062c] 000c:062c (unk. ctxt): call 0000 ; e8d1f9 -> int 10h 0x120000 is V86_MONITOR in emm386.asm: > disassemble 0x00120000 0x00120100 00120000: push EAX ; 6650 00120002: push EBX ; 6653 00120004: push ECX ; 6651 00120006: movzx ESP, SP ; 660fb7e4 figure out from where we are called (encodes interrupt number): 0012000a: mov CX, SS:[ESP + 0c] ; 678b4c240c 0012000f: sub CX, 05ec ; 81e9ec05 00120013: and ECX, 0000fffc ; 6681e1fcff0000 figure out how full stack is (encoded interrupt type??): 0012001a: cmp ESP, 000001ca ; 6681fcca010000 << *** TOS-36h ... ... registers: eax is 0xe000_0e20, etc., segments are 0 due to mode switch, ... cs=0x0c, ss=0x1c, esp=0x1dc, ... ... esp will be 1ce when testing (so 4 more than checked, which means no error code has to be popped...!?) ... 00120021: jz 00d6 ; 0f84b100 << *** V86_ABORT (exception) 00120025: jb 00a2 ; 727b << *** PROTECTED (monitor faulty) otherwise, simply reflect to PM task: 00120027: mov BX, 0030 ; bb3000 0012002a: mov DS, BX ; 8edb change esp of v86 task: 0012002c: sub SS:[ESP + 1a], 06 ; 67836c241a06 find linear address of stack of v86 task: 00120032: movzx EBX, SS:[ESP + 1e] ; 66670fb75c241e 00120039: shl EBX, 04 ; 66c1e304 ignore high half of ESP for finding v86 task stack: 0012003d: movzx EAX, SS:[ESP + 1a] ; 66670fb744241a 00120044: add EBX, EAX ; 6603d8 store cs:ip and flags on v86 stack: 00120047: mov AX, SS:[ESP + 0e] ; 678b44240e 0012004c: mov DS:[EBX], AX ; 678903 0012004f: mov AX, SS:[ESP + 12] ; 678b442412 00120054: mov DS:[EBX + 02], AX ; 67894302 00120058: mov AX, SS:[ESP + 16] ; 678b442416 0012005d: mov DS:[EBX + 04], AX ; 67894304 manipulate flags as appropriate: 00120061: cmp CX, 20 ; 83f920 00120064: jb 007e ; 7218 << int 0..7 00120066: cmp CX, 3c ; 83f93c 00120069: jbe 0077 ; 760c << int 8..f = IRQ 0012006b: cmp CX, 01c0 ; 81f9c001 0012006f: jb 007e ; 720d << int 10..6f 00120071: cmp CX, 01dc ; 81f9dc01 00120075: jnbe 007e ; 7707 << int 70..77 = IRQ 00120077: and SS:[ESP + 16], fdff ; 6781642416fffd << IRQ (cause CLI) 0012007e: and SS:[ESP + 16], feff ; 6781642416fffe << OTHER (end singlestep) now set CS:IP to simulate interrupt: 00120085: mov BX, DS:[ECX] ; 678b19 00120088: mov SS:[ESP + 0e], BX ; 67895c240e 0012008d: mov BX, DS:[ECX + 02] ; 678b5902 00120091: mov SS:[ESP + 12], BX ; 67895c2412 finally, return to caller: 00120096: pop ECX ; 6659 00120098: pop EBX ; 665b 0012009a: pop EAX ; 6658 why the dummy-pop of a word? must be v86 magic... 0012009c: inc ESP ; 6644 << *** ??? *** 0012009e: inc ESP ; 6644 << *** ??? *** 001200a0: iret ; 66cf << "IRETD" (using 32bit flags!?) ... the dummy-pop pops "0070" for me. Next on stack are 02f3, 0070, ff53 ... ... after the iret, we are back in v86 with ... bx=70, esp=22d8, ebp=22de, ... at c000:e6 ... eflags 0x00023202 ... (during PM, eflags upper was 0) ... ... for now, switching works, and emm386 displays further status ... ... it allocates and maps UMBs ... > request_umb ... it made an c800-dfff UMB block (e000 is page frame) ... ... now we try to load lbacache ... ... and hit exception D (handled at c:d6 -> cmp cx,4*0x0d...)! ... eax=0 edx=0x0c, ebx=4, esp=0x1ca, ebp=0x0db8, edi=0, ... *** "protected" (not used normally) IF ERROR IN V86 MONITOR: commented with "put new Intr.Nr. ..." (???): 001200a2: mov AX, SS:[ESP + 0c] ; 678b44240c 001200a7: mov SS:[ESP + 18], AX ; 6789442418 commented with "move up EAX EBX ECX" (???): 001200ac: mov EAX, SS:[ESP + 08] ; 66678b442408 001200b2: mov SS:[ESP + 14], EAX ; 666789442414 001200b8: mov EAX, SS:[ESP + 04] ; 66678b442404 001200be: mov SS:[ESP + 10], EAX ; 666789442410 001200c4: mov EAX, SS:[ESP] ; 66678b0424 001200c9: mov SS:[ESP + 0c], EAX ; 66678944240c commented with "throw away PM eflags, CS, IP" (???): 001200cf: add ESP, 0c ; 6683c40c reflect to v86 task!?: 001200d3: jmp 0027 ; e951ff ... 001200d6: cmp CX, 34 ; 83f934 << *** 001200d9: jnz 0140 ; 7565 we have hit a GPF error 001200db: mov AX, 0030 ; b83000 001200de: mov DS, AX ; 8ed8 001200e0: movzx EAX, SS:[ESP + 16] ; 66670fb7442416 001200e7: shl EAX, 04 ; 66c1e004 001200eb: add EAX, SS:[ESP + 12] ; 666703442412 001200f1: mov BL, DS:[EAX] ; 678a18 now BL is the 1st byte of the offending opcode 001200f4: cmp BL, f4 ; 80fbf4 << HLT 001200f7: jz 0113 ; 741a 001200f9: cmp BL, e4 ; 80fbe4 001200fc: jb 0140 ; 7242 001200fe: cmp BL, e7 ; 80fbe7 00120101: jbe 01a1 ; 0f869c00 << e4..e7 (i/o immediate) 00120105: cmp BL, ec ; 80fbec 00120108: jb 0140 ; 7236 0012010a: cmp BL, ef ; 80fbef 0012010d: jbe 020e ; 0f86fd00 << ec..ef (i/o DX) 00120111: jmp 0140 ; eb2d case f4, hlt: 00120113: cmp SS:[ESP + 16], 0413 ; 67817c24161304 0012011a: jnz 012f ; 7513 << in emm386 itself is magic 0012011c: mov AX, SS:[ESP + 12] ; 678b442412 00120121: cmp AX, 00d1 ; 3dd100 << magic HLT pos 1 00120124: jz 021b ; 0f84f300 00120128: cmp AX, 0114 ; 3d1401 << magic HLT pos 2 0012012b: jz 021b ; 0f84ec00 just skip this single byte opcode...: 0012012f: inc SS:[ESP + 12] ; 67ff442412 00120134: pop ECX ; 6659 00120136: pop EBX ; 665b 00120138: pop EAX ; 6658 commented with "thow away error code and return address": 0012013a: add ESP, 06 ; 6683c406 0012013e: sti ; fb ...and do the HLT for the user: 0012013f: hlt ; f4 *** will be left by an IRQ which causes us to fall back into the generic handler which will reflect the IRQ back into the v86 task - program execution is continued there. "V86_ABORT_IT" in emm386.asm -> simulate int 6 (invalid opcode)...: usual stuff, handles some generic GPF!?: 00120140: mov BX, 0030 ; bb3000 00120143: mov DS, BX ; 8edb 00120145: movzx EBX, SS:[ESP + 22] ; 66670fb75c2422 0012014c: shl EBX, 04 ; 66c1e304 00120150: add EBX, SS:[ESP + 1e] ; 6667035c241e 00120156: sub SS:[ESP + 1e], 06 ; 6667836c241e06 0012015d: mov AX, SS:[ESP + 12] ; 678b442412 00120162: mov DS:[EBX + fa], AX ; 678943fa 00120166: mov AX, SS:[ESP + 16] ; 678b442416 0012016b: mov DS:[EBX + fc], AX ; 678943fc 0012016f: mov AX, SS:[ESP + 1a] ; 678b44241a 00120174: mov DS:[EBX + fe], AX ; 678943fe 00120178: mov BX, DS:0018 ; 8b1e1800 << hardcoded: INT 6 0012017c: mov SS:[ESP + 12], BX ; 67895c2412 00120181: mov BX, DS:001a ; 8b1e1a00 << hardcoded: INT 6 00120185: mov SS:[ESP + 16], BX ; 67895c2416 0012018a: and SS:[ESP + 1a], feff ; 678164241afffe 00120191: pop ECX ; 6659 00120193: pop EBX ; 665b 00120195: pop EAX ; 6658 00120197: inc ESP ; 6644 00120199: inc ESP ; 6644 remove error code? - according to emm386.asm, indeed... 0012019b: add ESP, 04 ; 6683c404 0012019f: iret ; 66cf << return to v86 task I/O immediate commands: 001201a1: push EDX ; 6652 001201a3: push ESI ; 6656 001201a5: push EDI ; 6657 001201a7: inc EAX ; 6640 001201a9: movzx DX, DS:[EAX] ; 670fb610 001201ad: add SS:[ESP + 1e], 02 ; 678344241e02 001201b3: mov AX, 0014 ; b81400 001201b6: mov DS, AX ; 8ed8 001201b8: test BL, 02 ; f6c302 001201bb: jnz 01e2 ; 7525 001201bd: test BL, 01 ; f6c301 001201c0: jnz 01da ; 7518 001201c2: in AL, DX ; ec << IN AL 001201c3: mov SS:[ESP + 14], AL ; 6788442414 001201c8: pop EDI ; 665f 001201ca: pop ESI ; 665e 001201cc: pop EDX ; 665a 001201ce: pop ECX ; 6659 001201d0: pop EBX ; 665b 001201d2: pop EAX ; 6658 001201d4: add ESP, 06 ; 6683c406 001201d8: iret ; 66cf ... 001201da: in AX, DX ; ed << IN AX 001201db: mov SS:[ESP + 14], AX ; 6789442414 001201e0: jmp 02c8 ; ebe6 ... 001201e2: mov AL, SS:[ESP + 14] ; 678a442414 001201e7: push BX ; 53 001201e8: push DX ; 52 001201e9: call 01fe ; e81200 001201ec: pop DX ; 5a 001201ed: pop BX ; 5b 001201ee: test BL, 01 ; f6c301 001201f1: jz 02c8 ; 74d5 001201f3: inc DX ; 42 001201f4: mov AL, SS:[ESP + 15] ; 678a442415 001201f9: call 01fe ; e80200 001201fc: jmp 02c8 ; ebca ... 001201fe: cmp DX, 0080 ; 81fa8000 00120202: jb 028a ; 0f828400 << I/O below 80 00120206: cmp DX, 008f ; 81fa8f00 0012020a: jbe 026d ; 7661 << I/O in 80..8f region 0012020c: jmp 028a ; eb7c << other I/O I/O DX commands: 0012020e: push EDX ; 6652 00120210: push ESI ; 6656 00120212: push EDI ; 6657 00120214: inc SS:[ESP + 1e] ; 67ff44241e 00120219: jmp 02b3 ; eb98 *** BUG: No "IN EAX" etc. supported! *** Only a problem if I/O permission bitmap causes virtualization of hardware which actually uses 32bit I/O... MAGIC HLT handler (flat block copy): 0012021b: inc SS:[ESP + 12] ; 67ff442412 00120220: push ds ; 1e 00120221: push es ; 06 00120222: push ESI ; 6656 00120224: push EDI ; 6657 use LDT segment 00120226: mov AX, 0014 ; b81400 00120229: mov DS, AX ; 8ed8 get a few magical values 0012022b: mov ESI, DS:0072 ; 668b367200 00120230: mov EDI, DS:006e ; 668b3e6e00 00120235: mov ECX, DS:0076 ; 668b0e7600 flat 4gb segment 0012023a: mov AX, 0030 ; b83000 0012023d: mov DS, AX ; 8ed8 0012023f: mov ES, AX ; 8ec0 00120241: cld ; fc 00120242: mov EAX, ECX ; 668bc1 00120245: and ECX, 03 ; 6683e103 00120249: REP: movsb ES:[EDI], DS:[ESI] ; f367a4 0012024c: nop ; 6790 0012024e: mov ECX, EAX ; 668bc8 00120251: shr ECX, 02 ; 66c1e902 00120255: REP: movsd ES:[EDI], DS:[ESI] ; f36667a5 00120259: nop ; 6790 0012025b: pop EDI ; 665f 0012025d: pop ESI ; 665e 0012025f: pop es ; 07 00120260: pop ds ; 1f 00120261: pop ECX ; 6659 00120263: pop EBX ; 665b 00120265: pop EAX ; 6658 00120267: add ESP, 06 ; 6683c406 0012026b: iret ; 66cf 0012026d: out DX, AL ; ee 0012026e: mov BX, DX ; 8bda 00120270: movzx EDI, DS:[BX+fffa] ; 660fb6bffaff 00120276: mov DS:[EDI + 00000054], AL ; 67888754000000 0012027d: btr DS:[0000005c + EDI<<1], 02 ; 670fba347d5c00000002 00120287: jmp 0340 ; e9b600 0012028a: out DX, AL ; ee ... some case DX switch collection ... etc. etc. etc. ... in our case the offending command is EE (out dx,al) ... ... out 0x0c,0 ... -> we hit the simulation of the floppy DMA thing ... ... int 1a ... all segments f9, cs f000, esp e30, ebp e38 ... > info break Num Type Disp Enb Address 1 lbreakpoint keep y 0x001200a2 2 lbreakpoint keep y 0x001200d6 3 lbreakpoint keep y 0x00120140 4 lbreakpoint keep y 0x0012021b > del 2 ... f000:466 - db4 > modebp mode switch break disabled ... ... lots of enter/exit v86 ... LBAcache starts up... > query_free_xms ... XMS error 0800 ... giving up ... > alloc_xms > move_xms ... now hitting c:a2 ... cx=4*0x0e eax=0x8737 edx=0x726e0030 ebx=9 esp=0x1b0 ebp=0x55, esi=0x6c4e002e edi=0x726e696f cs=0x0c ss=0x1c ds=es=0x30 fs=0x14 gs=0 ... which happens inside an int 0x0e ... ... after the iret we are still in PM ... eax 0x8737 34615 ecx 0x800 2048 edx 0x726e0030 1919811632 ebx 0x9 9 esp 0x1b8 0x1b8 ebp 0x55 0x55 esi 0x6c4e002e 1817051182 edi 0x726e696f 1919838575 eip 0x0 0x0 eflags 0x3006 12294 cs 0xc 12 ss 0x1c 28 ds 0x30 48 es 0x30 48 fs 0x14 20 gs 0x0 0 CR2=page fault linear address=0x6c4e002e -> in handler, esp is 1ac, now handling a GPF ... ... so we jump to c:a2 yet again ... ... at linear 1007a3 ... (fffa:803 ?) ... trying to put 0x007002bd3006 at 0x30:0x1007a3 ... (in 3 steps 16bit steps) using handler at 70:2b7 ... at iret, we are yet again in PM ... ... same situation as before but now with esp being 4 less! ... repeats infinitely until PM stack overflows. Maybe this? -> 00073716618i[CPU ] selector->index*8 + 7 = 119 00073716618i[CPU ] gdtr.limit = 56 00073716618i[CPU ] fetch_raw_descriptor: GDT: index > limit 00073716618i[CPU ] | EAX=00008737 EBX=00000009 ECX=00000800 EDX=726e0030 00073716618i[CPU ] | ESP=000001ca EBP=00000055 ESI=6c4e002e EDI=726e696f 00073716618i[CPU ] | IOPL=3 NV UP DI PL NZ NA PE NC 00073716618i[CPU ] | SEG selector base limit G D 00073716618i[CPU ] | SEG sltr(index|ti|rpl) base limit G D 00073716618i[CPU ] | DS:0030( 0006| 0| 0) 00000000 000fffff 1 1 00073716618i[CPU ] | ES:0030( 0006| 0| 0) 00000000 000fffff 1 1 00073716618i[CPU ] | FS:0014( 0002| 1| 0) 00004130 00000a2c 0 0 00073716618i[CPU ] | GS:0000( 0002| 1| 3) 00000000 0000ffff 0 0 00073716618i[CPU ] | SS:001c( 0003| 1| 0) 00003ef0 00000200 0 0 00073716618i[CPU ] | CS:000c( 0001| 1| 0) 00120000 00000e9d 0 0 00073716618i[CPU ] | EIP=000000a2 (000000a0) 00073716618i[CPU ] | CR0=0xe0000011 CR1=0x00000000 CR2=0x6c4e002e 00073716618i[CPU ] | CR3=0x00124000 CR4=0x00000000 00073716618i[CPU ] >> 66 00073716618i[CPU ] >> cf 00073716618i[CPU ] >> : iret ... related to SS 1c ...? Maybe this should not be in LDT? ... ... finally, handler crashes because initial esp 16 is not enough ... Decoding CR2 bits: ... high word would be "Nl" in RAM ... LSB = 110 = user (not pl 0), write (not read), not present (not protected) ... checking emm386.asm: selectors 0x0c, 0x14 and 0x1c are CS, DS and SS of the v86 monitor. 0/8/0x10/0x18 are NULL, LDT, TSS of the v86 monitor, 0x20/0x28/0x30 are back-to-real-CS/DS and flat 4gb segment ... idea: int handler returns to wrong task, which has no LDT, ... ... by the way, I/O permission bitmask only traps ports 0..7,b..c, 81..83,87,89..8b,c0..cf,d6,d8 (correct?) ...