pcjs/tests/pc/80386/tests.nasm
2015-05-05 18:26:19 -07:00

193 lines
4.2 KiB
NASM

;
; This file is designed to run as a ROM replacement, but it has a .COM extension because it's
; also designed to run as a COM file under DOS (hence the "org 0x100").
;
cpu 386
org 0x100
section .text
bits 16
DPL0 equ 0
DPL1 equ 1
DPL2 equ 2
DPL3 equ 3
ACC_TYPE_SEG equ 0x1000
ACC_PRESENT equ 0x8000
ACC_TYPE_CODE equ 0x0800
ACC_TYPE_READABLE equ 0x0200
ACC_TYPE_WRITABLE equ 0x0200
ACC_TYPE_CODE_READABLE equ (0x1a00 | ACC_PRESENT)
ACC_TYPE_DATA_WRITABLE equ (0x1200 | ACC_PRESENT)
EXT_NONE equ 0x0000
EXT_BIG equ 0x0040
;
; We build some data structures in the first page (0x0000-0x0fff) of RAM:
;
; 0x0000-0x03ff Real-mode IDT (256*4)
; 0x0400-0x0bff Prot-mode IDT (256*8)
; 0x0c00-0x0cff GDT (enough room for 32 selectors)
; 0x0d00-0x0d07 IDTR
; 0x0d08-0x0d0f GDTR
; 0x0d10-0x0fff reserved
;
; And in the second page (0x1000-0x1fff), we build a page directory, followed by a single page table that
; will allow us to map up to 4Mb (although we'll only create entries for the first 1Mb).
;
RAM_GDT equ 0x0c00
RAM_IDTR equ 0x0d00
RAM_GDTR equ 0x0d08
CSEG_REAL equ 0xf000
CSEG_PROT equ 0x0008
DSEG_PROT equ 0x0010
CR0_MSW_PE equ 0x0001
;
; set initializes a register to the specified value (eg, "set eax,0")
;
%macro set 2
%ifnum %2
%if %2 = 0
xor %1,%1
%else
mov %1,%2
%endif
%else
mov %1,%2
%endif
%endmacro
;
; defDesc defines a descriptor, given a base (%1), limit (%2), type (%3), dpl (%4), and ext (%5)
;
%macro defDesc 1-5 0,0,0,0,0
dw (%2 & 0x0000ffff)
dw (%1 & 0x0000ffff)
dw ((%1 & 0x00ff0000) >> 16) | %3 | (%4 << 13)
dw ((%2 & 0x000f0000) >> 16) | %5 | ((%1 & 0xff000000) >> 16)
%endmacro
;
; setDesc creates a descriptor, given a base (%1), limit (%2), type (%3), ext (%4), and selector (%5)
;
%assign selDesc 0
%macro setDesc 1-5 0,0,0,0,none
set ebx,%1
set ecx,%2
set dx,%3
set ax,%4
call storeDesc
%assign %5 selDesc
%assign selDesc selDesc+8
%endmacro
start: cli ; disable all interrupts
mov al,0xff ; and ensure that no hardware interrupts can sneak in
out 0x21,al ; if interrupts become enabled later
out 0xa1,al
sub ax,ax
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x1000
mov eax,0x44332211
mov ebx,eax
mov ecx,0x88776655
mul ecx
div ecx
cmp eax,ebx
je near initRAM ; apparently we have to tell NASM "near" because this is a forward reference
times 32768 nop ; lots of NOPs to force a 16-bit conditional jump
;
; storeDesc(EBX=base, ECX=limit, DX=type, AX=ext, DI=address of descriptor)
;
storeDesc:
cld
push ax
mov ax,cx
stosw ; store the low 16 bits of limit from ECX
mov ax,bx
stosw ; store the low 16 bits of base from EBX
mov ax,dx
shr ebx,16
mov al,bl
stosw
pop ax
shr ecx,16
and cl,0xf
or al,cl
mov ah,bh
stosw
ret
;
; The following ROM-based data structures are obsolete, because we build these data structures in RAM now.
;
addrGDT:dw romGDTEnd - romGDT - 1 ; 16-bit limit of romGDT
dw romGDT, 0xffff ; 32-bit base address of romGDT (works as long as we're aliased at 0xffff0000)
romGDT: defDesc 0 ; the first descriptor in any descriptor table is always a dud (it corresponds to the null descriptor)
defDesc 0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE
defDesc 0x00000000,0x000fffff,ACC_TYPE_DATA_WRITABLE
romGDTEnd:
;
; End of ROM-based data structures
;
initRAM:
set edi,RAM_GDT
mov [RAM_GDTR+2],edi
setDesc 0,0,0,0,NULL
mov eax,cs
shl eax,4
setDesc eax,0x0000ffff,ACC_TYPE_CODE_READABLE,EXT_BIG,CSEG_PROT
setDesc 0x0,0x000fffff,ACC_TYPE_DATA_WRITABLE,EXT_BIG,DSEG_PROT
sub edi,RAM_GDT
dec edi
mov [RAM_GDTR],di
goProt: o32 lgdt [RAM_GDTR]
mov eax,cr0
or eax,CR0_MSW_PE
mov cr0,eax
jmp CSEG_PROT:inProt
inProt:
bits 32
mov ax,DSEG_PROT
mov ds,ax
mov es,ax
mov ss,ax
;
; Do some protected-mode tests now...
;
goReal: mov eax,cr0
and eax,~CR0_MSW_PE
mov cr0,eax
bits 16
jmp CSEG_REAL:inReal
inReal:
or ax,1
jnz start ; apparently we do NOT have to say "near" here since this is a backward reference
;
; Fill the remaining space with NOPs until we get to target offset 0xFFF0.
; Note that we subtract 0x100 from the target offset because we're ORG'ed at 0x100.
;
times 0xfff0-0x100-($-$$) nop
jmp CSEG_REAL:start
db 0x20
db '04/04/15'
db 0xFC ; 0000FFFE FC (Model ID byte)
db 0x00 ; 0000FFFF 00 (location of checksum byte)