80386 tests now pass when running both as a ROM and as a DOS .COM file
This commit is contained in:
parent
0ae5ab13a9
commit
dd12198e62
1 changed files with 34 additions and 19 deletions
|
|
@ -15,19 +15,26 @@
|
|||
;
|
||||
; REAL32 Notes
|
||||
; ------------
|
||||
; REAL32 is NOT enabled by default, because based on what I've seen in VirtualBox (and notes
|
||||
; at http://geezer.osdevbrasil.net/johnfine/segments.htm), if CS is loaded with a 32-bit code segment
|
||||
; REAL32 is NOT enabled by default, because based on what I've seen in VirtualBox (and notes at
|
||||
; 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
|
||||
; 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
|
||||
; 16-bit real-mode code, because it's being misinterpreted as 32-bit code, and there doesn't appear
|
||||
; to be anything you can do about it from real-mode.
|
||||
; the 32-bit EXT_BIG attribute, remain unchanged. As a result, the processor will crash as soon as
|
||||
; it starts executing 16-bit real-mode code, because it's being misinterpreted as 32-bit code, and
|
||||
; 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
|
||||
; returning to real-mode -- just not CS. SS shouldn't be set to a 32-bit segment either, because
|
||||
; that causes implicit pushes to use ESP instead of SP, even in real-mode.
|
||||
; "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 probably shouldn't be set to a 32-bit segment either,
|
||||
; 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
|
||||
org 0x100
|
||||
|
|
@ -230,7 +237,7 @@ exitErr:nop
|
|||
jmp exitErr
|
||||
|
||||
allocPages:
|
||||
mov bx,0x1000 ; 4K paragraphs == 64K bytes
|
||||
mov bx,0x2000 ; 8K paragraphs == 128K bytes
|
||||
mov ah,DOS_ALLOC
|
||||
int INT_DOS
|
||||
jc errDOSMem
|
||||
|
|
@ -248,7 +255,7 @@ initPages:
|
|||
xor edi,edi
|
||||
;
|
||||
; 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
|
||||
mov eax,esi
|
||||
|
|
@ -291,20 +298,20 @@ toProt32:
|
|||
mov ds,ax
|
||||
mov es,ax
|
||||
;
|
||||
; Of the 64Kb of scratch memory we allocated, the first 8Kb (0x2000) is being used for a
|
||||
; page directory and a single page table, so we have at least another 56Kb, at ESI+0x2000,
|
||||
; to play with.
|
||||
; Of the 128Kb of scratch memory we allocated, we may have lost as much as 4Kb-1 rounding
|
||||
; up to the first physical 4Kb page; the next 8Kb (0x2000) was used for a page directory and a
|
||||
; 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
|
||||
; that guarantees ESI will be be greater than 0xffff, so as long as SS contains a 16-bit data
|
||||
; segment, pushes will NOT be occurring where you'd normally expect.
|
||||
; We'll set the top of our stack to ESI+0xe000. This guarantees an ESP greater than 0xffff,
|
||||
; and so for the next few tests, with a 16-bit data segment in SS, we expect all pushes/pops
|
||||
; will occur at SP rather than ESP.
|
||||
;
|
||||
add esi,0x2000 ; ESI -> bottom of scratch memory
|
||||
mov ss,ax
|
||||
lea esp,[esi+0xe000] ; set ESP to bottom of scratch + 56K
|
||||
lea ebp,[esp-4]
|
||||
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
|
||||
push eax
|
||||
cmp [ebp],eax ; did the push use SP instead of ESP?
|
||||
|
|
@ -314,7 +321,7 @@ toProt32:
|
|||
cmp [ebp+2],ax
|
||||
jne near error
|
||||
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 ss,ax
|
||||
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
|
||||
|
||||
doneProt:
|
||||
mov ax,DSEG_PROT16
|
||||
mov ss,ax
|
||||
sub esp,esp
|
||||
|
||||
%ifndef REAL32
|
||||
;
|
||||
|
|
@ -392,6 +402,11 @@ jmpReal:
|
|||
|
||||
toReal:
|
||||
mov ax,cs
|
||||
mov ds,ax
|
||||
mov es,ax
|
||||
mov ss,ax
|
||||
sub sp,sp
|
||||
|
||||
cmp ax,CSEG_REAL ; is CS equal to 0xf000?
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue