80386 tests now pass when running both as a ROM and as a DOS .COM file

This commit is contained in:
Jeff Parsons 2015-05-14 09:03:03 -07:00 • committed by jeffpar
commit dd12198e62

View file

@ -15,19 +15,26 @@
; ;
; REAL32 Notes ; REAL32 Notes
; ------------ ; ------------
; REAL32 is NOT enabled by default, because based on what I've seen in VirtualBox (and notes ; REAL32 is NOT enabled by default, because based on what I've seen in VirtualBox (and notes at
; at http://geezer.osdevbrasil.net/johnfine/segments.htm), if CS is loaded with a 32-bit code segment ; http://geezer.osdevbrasil.net/johnfine/segments.htm), if CS is loaded with a 32-bit code segment
; while in protected-mode and we then return to real-mode, even if we immediately perform a FAR jump ; while in protected-mode and we then return to real-mode, even if we immediately perform a FAR jump
; with a real-mode CS, the base of CS will be updated, but all the other segment attributes, like ; with a real-mode CS, the base of CS will be updated, but all the other segment attributes, like
; EXT_BIG, remain unchanged. As a result, the processor will crash as soon as it starts executing ; the 32-bit EXT_BIG attribute, remain unchanged. As a result, the processor will crash as soon as
; 16-bit real-mode code, because it's being misinterpreted as 32-bit code, and there doesn't appear ; it starts executing 16-bit real-mode code, because it's being misinterpreted as 32-bit code, and
; to be anything you can do about it from real-mode. ; there doesn't appear to be anything you can do about it from real-mode.
; ;
; The work-around: load CS with a 16-bit code segment BEFORE returning to real-mode. ; The work-around: you MUST load CS with a 16-bit code segment BEFORE returning to real-mode.
; ;
; "Unreal mode" works by setting other segment registers (eg, DS, ES) to 32-bit segments before ; "Unreal mode" works by setting OTHER segment registers, like DS and ES, to 32-bit segments before
; returning to real-mode -- just not CS. SS shouldn't be set to a 32-bit segment either, because ; returning to real-mode -- just not CS. SS probably shouldn't be set to a 32-bit segment either,
; that causes implicit pushes to use ESP instead of SP, even in real-mode. ; because that causes implicit pushes to use ESP instead of SP, even in real-mode.
;
; The code below ensures that, before returning to real-mode, all of CS, DS, ES, and SS contain
; 16-bit protected-mode selectors; note, however, that my 16-bit protected-mode data descriptor uses
; a full 20-bit limit, so DS, ES, and SS will still have a limit of 1Mb instead of the usual 64Kb,
; even after returning to real-mode. I use the larger limit because it's convenient to have access
; to the first 1Mb in protected-mode, with or without a 32-bit data segment, and the larger data
; segment limit shouldn't affect any 16-bit real-mode operations.
; ;
cpu 386 cpu 386
org 0x100 org 0x100
@ -230,7 +237,7 @@ exitErr:nop
jmp exitErr jmp exitErr
allocPages: allocPages:
mov bx,0x1000 ; 4K paragraphs == 64K bytes mov bx,0x2000 ; 8K paragraphs == 128K bytes
mov ah,DOS_ALLOC mov ah,DOS_ALLOC
int INT_DOS int INT_DOS
jc errDOSMem jc errDOSMem
@ -248,7 +255,7 @@ initPages:
xor edi,edi xor edi,edi
; ;
; Build a page directory at ES:EDI with only 1 valid PDE (the first one), ; Build a page directory at ES:EDI with only 1 valid PDE (the first one),
; because we're not going to access any memory outside the first 4Mb. ; because we're not going to access any memory outside the first 1Mb (of the first 4Mb).
; ;
cld cld
mov eax,esi mov eax,esi
@ -291,20 +298,20 @@ toProt32:
mov ds,ax mov ds,ax
mov es,ax mov es,ax
; ;
; Of the 64Kb of scratch memory we allocated, the first 8Kb (0x2000) is being used for a ; Of the 128Kb of scratch memory we allocated, we may have lost as much as 4Kb-1 rounding
; page directory and a single page table, so we have at least another 56Kb, at ESI+0x2000, ; up to the first physical 4Kb page; the next 8Kb (0x2000) was used for a page directory and a
; to play with. ; single page table, leaving us with a minimum of 116Kb to play with, starting at ESI+0x2000.
; ;
; Let's use the top of that memory, ESI+0xe000, as the top of our stack. Note, however, that ; We'll set the top of our stack to ESI+0xe000. This guarantees an ESP greater than 0xffff,
; that guarantees ESI will be be greater than 0xffff, so as long as SS contains a 16-bit data ; and so for the next few tests, with a 16-bit data segment in SS, we expect all pushes/pops
; segment, pushes will NOT be occurring where you'd normally expect. ; will occur at SP rather than ESP.
; ;
add esi,0x2000 ; ESI -> bottom of scratch memory add esi,0x2000 ; ESI -> bottom of scratch memory
mov ss,ax mov ss,ax
lea esp,[esi+0xe000] ; set ESP to bottom of scratch + 56K lea esp,[esi+0xe000] ; set ESP to bottom of scratch + 56K
lea ebp,[esp-4] lea ebp,[esp-4]
and ebp,0xffff ; EBP now mirrors SP instead of ESP and ebp,0xffff ; EBP now mirrors SP instead of ESP
mov edx,[ebp] mov edx,[ebp] ; save dword about to be trashed by pushes
mov eax,0x11223344 mov eax,0x11223344
push eax push eax
cmp [ebp],eax ; did the push use SP instead of ESP? cmp [ebp],eax ; did the push use SP instead of ESP?
@ -314,7 +321,7 @@ toProt32:
cmp [ebp+2],ax cmp [ebp+2],ax
jne near error jne near error
pop ax pop ax
mov [ebp+2],edx ; restore dword trashed by the above pushes mov [ebp],edx ; restore dword trashed by the above pushes
mov ax,DSEG_PROT32 mov ax,DSEG_PROT32
mov ss,ax mov ss,ax
lea esp,[esi+0xe000] ; SS:ESP should now be a valid 32-bit pointer lea esp,[esi+0xe000] ; SS:ESP should now be a valid 32-bit pointer
@ -374,6 +381,9 @@ test5: movzx eax,word [0xffffe]
error: nop error: nop
doneProt: doneProt:
mov ax,DSEG_PROT16
mov ss,ax
sub esp,esp
%ifndef REAL32 %ifndef REAL32
; ;
@ -392,6 +402,11 @@ jmpReal:
toReal: toReal:
mov ax,cs mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
sub sp,sp
cmp ax,CSEG_REAL ; is CS equal to 0xf000? cmp ax,CSEG_REAL ; is CS equal to 0xf000?
je near jmpStart ; yes, so loop around, only because we have nowhere else to go je near jmpStart ; yes, so loop around, only because we have nowhere else to go
int INT_DOSEXIT ; no, so assume we're running under DOS and exit int INT_DOSEXIT ; no, so assume we're running under DOS and exit