📄 load.asm
字号:
mov ax,DATA_SEL16
mov ss,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov eax,cr0
and al,0FEh ; pmode off
mov cr0,eax
jmp far [real_mode_ip]
pmode16_to_real: ; finish switching to real mode
lidt [real_idt_ptr]
mov ax,cs
mov ss,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
real:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; enable unreal mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cli
push ds
lgdt [gdt_ptr]
mov eax,cr0
or al,1
mov cr0,eax ; partial switch to pmode
mov ax,LINEAR_DATA_SEL
mov ds,ax ; selector to segment w/ 4G limit
mov es,ax ; set seg limits in descriptor caches
mov fs,ax
mov gs,ax ; (do NOT change CS nor SS)
mov eax,cr0
and al,0FEh
mov cr0,eax ; back to (un)real mode
nop
pop ds ; segment regs back to old values,
xor ax,ax ; but now 32-bit addresses are OK
mov es,ax
mov fs,ax
mov gs,ax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; get virt-to-phys conversion value to EDX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ebx,end ; offset of end of this .COM file
add ebx,[end + 8] ; offset of DJGPP kernel in initial RAM disk
mov edi,[load_adr] ; physical (load) adr of .text
mov edx,edi
sub edx,[bx + COFF_TEXT_VIRT] ; virtual adr of .text
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; copy kernel .text and .data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ecx,[bx + COFF_TEXT_SIZE]
mov esi,[bx + COFF_TEXT_OFFSET]
add esi,ebx
mov edi,[bx + COFF_TEXT_VIRT]
add edi,edx
a32
rep movsb
mov ecx,[bx + COFF_DATA_SIZE]
mov esi,[bx + COFF_DATA_OFFSET]
add esi,ebx
mov edi,[bx + COFF_DATA_VIRT]
add edi,edx
a32
rep movsb
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; zero kernel .bss
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ecx,[bx + COFF_BSS_SIZE]
mov edi,[bx + COFF_BSS_VIRT]
add edi,edx
xor eax,eax
push edi
a32
rep stosb
pop edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; store machine state in kernel BSS and registers:
; BSS + 0 conventional memory size (bytes)
; BSS + 4 extended memory size (bytes)
; BSS + 8 linear address of initial RAM disk (RDSK file)
; BSS + 12 size of initial RAM disk file
; BSS + 16 kernel command line
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax,[conv_mem] ; conventional memory size
mov [es:edi + 0],eax
mov eax,[ext_mem] ; extended memory size
mov [es:edi + 4],eax
mov eax,end
add eax,ebp
mov [es:edi + 8],eax ; initial RAM disk address
mov eax,[file_len] ; RDSK file length
mov [es:edi + 12],eax
xor eax,eax
mov [es:edi + 16],eax ; kernel command line (xxx - implement)
mov eax,[bx + AOUT_ENTRY_POINT] ; virtual entry point
add eax,edx ; physical entry point
; stash the entry point. This is self-modifying code,
; but it's the only way I can see of jumping to the kernel
; with all of the data segment registers already loaded
mov [entry + 2],eax
; interrupts off
push dword 0
popfd
; convert SS:SP to ESP
xor eax,eax
mov ax,ss
shl eax,4
xor ebx,ebx
mov bx,sp
add eax,ebx
mov esp,eax
; set PE bit
mov ebx,cr0
inc bx
mov cr0,ebx
; load data segment registers
mov eax,LINEAR_DATA_SEL
mov ds,eax
mov ss,eax
mov es,eax
mov fs,eax
mov gs,eax
entry:
; 2-byte JMP at [entry+0]: 66 EA
; 4-byte offset at [entry+2]: 00 00 00 00
; 2-byte selector at [entry+6]: 08 00
jmp LINEAR_CODE_SEL:dword 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; exit to DOS with error code and message
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
die:
mov ah,0Eh ; INT 10h: teletype output
xor bx,bx ; video page 0
jmp die3
die2:
int 10h
die3:
lodsb
or al,al
jne die2
mov ax,4C00h ; DOS terminate
int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; await keyboard controller ready
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
kbd0:
jmp short $+2
in al,60h
kbd:
jmp short $+2
in al,64h
test al,1
jnz kbd0
test al,2
jnz kbd
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; verify A20 is on
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
test_a20:
push ax
push ds
push es
xor ax,ax
mov ds,ax ; DS=0
dec ax
mov es,ax ; ES=0FFFFh
mov ax,[es:10h] ; read word at FFFF:0010 (1 meg)
not ax ; 1's complement
push word [0] ; save word at 0000:0000
mov [0],ax ; word at 0 = ~(word at 1 meg)
mov ax,[0] ; read it back
pop word [0]
cmp ax,[es:10h] ; fail if word at 0 == word at 1 meg
pop es
pop ds
pop ax
ret ; if ZF=1, the A20 gate is NOT enabled
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; handler for VCPI exceptions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BITS 32
unhand:
mov ax,LINEAR_DATA_SEL
mov ds,ax
mov byte [dword 0B8000h],'!'
jmp $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
page_info:
times 1024 dd 0 ; padding to 4K boundary
times 1024 dd 0 ; page table somewhere in here
dd 0 ; a page dir with one entry
tss:
dw 0, 0 ; back link
dd 0 ; ESP0
dw DATA_SEL32, 0 ; SS0, reserved
dd 0 ; ESP1
dw 0, 0 ; SS1, reserved
dd 0 ; ESP2
dw 0, 0 ; SS2, reserved
dd 0 ; CR3
dd 0, 0 ; EIP, EFLAGS
dd 0, 0, 0, 0 ; EAX, ECX, EDX, EBX
dd 0, 0, 0, 0 ; ESP, EBP, ESI, EDI
dw 0, 0 ; ES, reserved
dw 0, 0 ; CS, reserved
dw 0, 0 ; SS, reserved
dw 0, 0 ; DS, reserved
dw 0, 0 ; FS, reserved
dw 0, 0 ; GS, reserved
dw 0, 0 ; LDT, reserved
dw 0, 0 ; debug, IO perm. bitmap
gdt:
dw 0 ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0 ; type
db 0 ; limit 19:16, flags
db 0 ; base 31:24
LINEAR_CODE_SEL equ $-gdt
dw 0FFFFh
dw 0
db 0
db 9Ah ; present, ring 0, code, non-conforming, readable
db 0CFh ; page-granular, 32-bit
db 0
LINEAR_DATA_SEL equ $-gdt
dw 0FFFFh
dw 0
db 0
db 92h ; present, ring 0, data, expand-up, writable
db 0CFh ; page-granular, 32-bit
db 0
CODE_SEL32 equ $-gdt
gdt3:
dw 0FFFFh
dw 0
db 0
db 9Ah ; present, ring 0, code, non-conforming, readable
db 0CFh ; page-granular, 32-bit
db 0
DATA_SEL32 equ $-gdt
gdt4:
dw 0FFFFh
dw 0
db 0
db 92h ; present, ring 0, data, expand-up, writable
db 0CFh ; page-granular, 32-bit
db 0
CODE_SEL16 equ $-gdt
gdt5:
dw 0FFFFh
dw 0
db 0
db 9Ah ; present, ring 0, code, non-conforming, readable
db 0 ; byte-granular, 16-bit
db 0
DATA_SEL16 equ $-gdt
gdt6:
dw 0FFFFh
dw 0
db 0
db 92h ; present, ring 0, data, expand-up, writable
db 0 ; byte-granular, 16-bit
db 0
TSS_SEL equ $-gdt
gdt7:
dw 103
dw 0
db 0
db 089h ; Ring 0 available 32-bit TSS
db 0
db 0
VCPI_CODE_SEL equ $-gdt
gdt8: ; these are set by INT 67h AX=DE01h
dd 0, 0
VCPI_DATA_SEL equ $-gdt
dd 0, 0
VCPI_LINEAR_SEL equ $-gdt
dd 0, 0
gdt_end:
idt:
%rep 32
dw unhand ; low 16 bits of ISR offset
dw CODE_SEL32 ; selector
db 0
db 8Eh ; present, ring 0, 32-bit intr gate
dw 0 ; high 16 bits of ISR (unhand >> 16)
%endrep
idt_end:
gdt_ptr:
dw gdt_end - gdt - 1 ; GDT limit
dd gdt ; linear, physical adr of GDT
idt_ptr:
dw idt_end - idt - 1 ; IDT limit
dd idt ; linear, physical address of IDT
real_idt_ptr:
dw 3FFh ; limit 1023
dd 0 ; IDT (IVT, actually) at address 0
real_mode_ip:
dw pmode16_to_real
real_mode_cs:
dw 0
vcpi_control_block:
vcpi_cr3:
dd 0
vcpi_gdtr:
dd gdt_ptr
vcpi_idtr:
dd idt_ptr
;vcpi_ldtr:
dw 0
;vcpi_tr:
dw TSS_SEL
;vcpi_eip:
dd vcpi_to_pmode32
;vcpi_cs:
dw CODE_SEL32
ext_mem:
dd 0
conv_mem:
dd 0
file_len:
dd 0
load_adr:
dd 0
cpu_msg:
db "32-bit CPU (386SX or better) required", 13, 10, 0
usage_msg:
db "Loads and executes Mobius-format initial RAM disk"
db 13, 10, 0
open_msg:
db "Couldn't open file", 13, 10, 0
read_msg:
db "Error reading file", 13, 10, 0
invalid_msg:
db "This file is not a Mobius-format initial RAM disk", 13, 10, 0
seek_msg:
db "Seek failed (file may be corrupt)", 13, 10, 0
mem_msg:
db "Not enough contiguous memory to load kernel", 13, 10, 0
coff_msg:
db "First file in this RDSK file is not a DJGPP COFF file", 13, 10, 0
a20_msg:
db "Could not enable A20 gate", 13, 10, 0
v86_msg:
db "CPU is in virtual 8086 mode, but no VCPI", 13, 10
db "Are you running this code from Windows? (don't)", 13, 10, 0
vcpi_err_msg:
db "VCPI call (INT 67h AX=DE01h) failed (?)", 13, 10, 0
success_msg:
db "Success!", 13, 10, 0
times 512 dw 0
stack:
end:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -