📄 load.asm
字号:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; load.asm - load and run kernel inside M攂ius-format initial RAM disk
; Copyright (C) 2000 - Christopher Giese <geezer@execpc.com>
; http://www.execpc.com/~geezer/os/
;
; Tim Robinson's M攂ius OS: http://www.gaat.freeserve.co.uk/
;
; Assemble this file with NASM:
; nasm -f bin -o load.com load.asm
; put your kernel into a Mobius initial RAM disk:
; rdsk -o krnl.dsk krnl.x <other_files_here>
; then boot it:
; load krnl.dsk
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BITS 16
ORG 100h ; .COM file
mov ax,cs
mov ds,ax
mov ss,ax
mov es,ax
mov [real_mode_cs],ax
mov sp,stack ; move the stack somewhere safe
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; before using 32-bit instructions, check for 32-bit CPU (386SX or better)
; I (Chris Giese) have not tested this code with 8088/'286 systems
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pushf
pushf
pop bx ; old FLAGS -> BX
mov ax,bx
xor ah,70h ; try changing b14 (NT)...
push ax ; ... or b13:b12 (IOPL)
popf
pushf
pop ax ; new FLAGS -> AX
popf
xor ah,bh ; 32-bit CPU if we changed NT...
mov si,cpu_msg
and ah,70h ; ...or IOPL
je near die
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; OK for pmode code to use DOS stack, but zero the top 16 bits of ESP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor eax,eax
mov ax,sp
mov esp,eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; we'll use this value a lot:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor ebp,ebp
mov bp,cs
shl ebp,4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; patch things that depend on the load adr
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax,ebp
mov [gdt3 + 2],ax ; CODE_SEL32
mov [gdt4 + 2],ax ; DATA_SEL32
mov [gdt5 + 2],ax ; CODE_SEL16
mov [gdt6 + 2],ax ; DATA_SEL16
shr eax,16
mov [gdt3 + 4],al
mov [gdt4 + 4],al
mov [gdt5 + 4],al
mov [gdt6 + 4],al
mov [gdt3 + 7],ah
mov [gdt4 + 7],ah
; mov [gdt5 + 7],ah ; no, these are 16-bit
; mov [gdt6 + 7],ah
mov eax,tss
add eax,ebp
mov [gdt7 + 2],ax ; TSS_SEL
shr eax,16
mov [gdt7 + 4],al
mov [gdt7 + 7],ah
add [gdt_ptr + 2],ebp
add [idt_ptr + 2],ebp
add [vcpi_gdtr],ebp
add [vcpi_idtr],ebp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; get memory sizes from CMOS
; xxx - use BIOS calls
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor eax,eax
mov al,18h
out 70h,al
in al,71h
mov ah,al
mov al,17h
out 70h,al
in al,71h
shl eax,10 ; Kbytes -> bytes
mov [ext_mem],eax
xor eax,eax
mov al,16h
out 70h,al
in al,71h
mov ah,al
mov al,15h
out 70h,al
in al,71h
shl eax,10 ; Kbytes -> bytes
mov [conv_mem],eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; grind the command line
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov si,80h
lodsb
xor ch,ch
mov cl,al
or cl,cl ; zero length means no command-line arg
je usage_err
skip_spaces:
lodsb
cmp al,' '
jne found_arg_start
loop skip_spaces
usage_err: ; all spaces? how'd that happen?
mov si,usage_msg
jmp die
found_arg_start:
lea dx,[si - 1] ; save ptr to arg in DX for use by OPEN
find_end:
lodsb
cmp al,' '
je found_arg_end
cmp al,0Dh
loopne find_end
found_arg_end:
xor al,al
mov [si - 1],al ; convert 1st arg to ASCIZ (0-terminated)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open the file named on the command line
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ax,3D00h ; DOS "OPEN"; for read
int 21h
mov si,open_msg ; CY=1 if error
jc near die
mov bx,ax ; BX=file handle
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; validate file format
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ah,3Fh ; DOS "READ"
mov cx,32 ; 32 bytes
mov dx,end ; read to buffer that's just beyond this file
int 21h
jc read_error
cmp ax,32
je validate
read_error:
mov si,read_msg
close_and_error:
mov ah,3Eh ; DOS "CLOSE"
int 21h
jmp die
validate: ; Mobius-format initial RAM disk
cmp dword [end],"RDSK"
mov si,invalid_msg
jne close_and_error
cmp dword [end + 4],1 ; number of files in RAM disk; must be >= 1
jb close_and_error
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; get file size
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ax,4202h ; DOS "LSEEK"; from end of file
xor cx,cx
xor dx,dx
int 21h
mov si,seek_msg
jc close_and_error
mov [file_len + 0],ax
mov [file_len + 2],dx
mov ax,4200h ; DOS "LSEEK"; from start of file
xor cx,cx
xor dx,dx
int 21h
jc close_and_error
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; see if enough conventional memory to load initial RAM disk
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax,ebp
add eax,end ; linear adr of end of this .COM file
add eax,[file_len] ; linear adr of end of loaded RAM disk
cmp eax,[conv_mem] ; is it still within conventional mem?
mov si,mem_msg
jae close_and_error
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; load it
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov dx,end
%if 0
mov cx,(32768 - end) ; ** sigh **
%else
mov cx,end
neg cx
add cx,32768
%endif
push ds
jmp load2
load1:
xor dx,dx
mov ax,ds
add ax,(32768 / 16)
mov ds,ax
mov cx,32768
load2:
mov ah,3Fh ; DOS "READ"
int 21h
jnc load3
pop ds
jmp read_error
load3:
or ax,ax
jne load1 ; ...until EOF
pop ds
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; close input file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ah,3Eh ; DOS "CLOSE"
int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; point to 1st file in initial RAM disk; see if it's DJGPP COFF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ebx,[end + 8]
add ebx,end ; offset of end of this .COM file
COFF_MAGIC EQU 0 ; 0x014C
COFF_NUM_SECTS EQU 2 ; number of sections
COFF_OPTHDR_SIZE EQU 16 ; "optional" (aout) header size
COFF_FLAGS EQU 18
AOUT_MAGIC EQU 20 + 0 ; 0x010B
AOUT_ENTRY_POINT EQU 20 + 16
COFF_TEXT_VIRT EQU 20 + 28 + 40 * 0 + 12
COFF_TEXT_SIZE EQU 20 + 28 + 40 * 0 + 16
COFF_TEXT_OFFSET EQU 20 + 28 + 40 * 0 + 20
COFF_DATA_VIRT EQU 20 + 28 + 40 * 1 + 12
COFF_DATA_SIZE EQU 20 + 28 + 40 * 1 + 16
COFF_DATA_OFFSET EQU 20 + 28 + 40 * 1 + 20
COFF_BSS_VIRT EQU 20 + 28 + 40 * 2 + 12
COFF_BSS_SIZE EQU 20 + 28 + 40 * 2 + 16
COFF_BSS_OFFSET EQU 20 + 28 + 40 * 2 + 20
cmp word [bx + COFF_MAGIC],014Ch
jne not_coff
cmp word [bx + COFF_NUM_SECTS],3
jne not_coff
cmp word [bx + COFF_OPTHDR_SIZE],28
jne not_coff
test word [bx + COFF_FLAGS],2
je not_coff
cmp word [bx + AOUT_MAGIC],010Bh
je coff_ok
; xxx - make sure all sections in same 4 meg address space
; xxx - make sure .text section doesn't overlap others
not_coff:
mov si,coff_msg
jmp die
coff_ok:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; get sizes of .text, .data, and .bss sections; sum is kernel size
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edx,[bx + COFF_TEXT_SIZE]
add edx,[bx + COFF_DATA_SIZE]
add edx,[bx + COFF_BSS_SIZE]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; see if enough extended memory to copy kernel to 1 meg
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edi,100000h
cmp edx,[ext_mem]
jb mem_ok
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; see if enough conventional memory to copy kernel beyond loaded file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edi,ebp
add edi,end ; linear adr of end of this .COM file
add edi,[file_len] ; linear adr of end of initial RAM disk
add edi,4095
and di,0F000h ; round up to page (4K) boundary
mov eax,edi
add eax,edx
cmp eax,[conv_mem]
mov si,mem_msg
jae near close_and_error
mem_ok:
mov [load_adr],edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; enable A20 line using 'AT' ('Linux') method, then test if it worked
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cli
call kbd
mov al,0D1h
out 64h,al
call kbd
mov al,0DFh
out 60h,al
call kbd
call test_a20
jne a20_ok
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; oop, try the 'Vectra' method
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call kbd
mov al,0DFh
out 64h,al
call kbd
mov si,a20_msg
call test_a20
je near die
a20_ok:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; no more errors are possible, and we're done with DOS,
; so move to unreal mode. But first, check for virtual 8086 mode:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
smsw ax
test al,1 ; look at PE bit of MSW (CR0)
je near real
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; in V86 mode; check for VCPI (e.g. DOS with EMM386 loaded)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ax,0DE00h
int 67h
cmp ah,0
mov si,v86_msg
jne near die
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; use VCPI to switch from V86 mode to paged pmode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edi,ebp ; find 4K-aligned mem for page table
add edi,(page_info + 4095)
and di,0F000h ; EDI=linear adr of page table
mov eax,edi
add eax,4096 ; linear adr of page dir, 4K above table
mov [vcpi_cr3],eax
mov eax,edi
sub edi,ebp ; DI=offset of page table
add di,4096 ; point to page dir
or al,7 ; ring 3, writable, present
mov [di + 0],eax ; page dir[0] -> linear adr of page table
sub di,4096 ; back to page table; VCPI will fill it
mov si,gdt8 ; get 3 VCPI descriptors to here
mov ax,0DE01h
int 67h
cmp ah,0
mov si,vcpi_err_msg
jne near die
push dword 0 ; disable interrupts (set IF=0)...
popfd ; ...set IOPL=0, and clear the NT bit
mov esi,ebp
add esi,vcpi_control_block
mov ax,0DE0Ch ; switch from V86 mode to paged pmode
int 67h ; jump to vcpi_to_pmode32
BITS 32
vcpi_to_pmode32: ; now in ring 0 paged pmode
mov eax,cr0
and eax,7FFFFFFFh ; turn off paging
mov cr0,eax
xor eax,eax
mov cr3,eax ; flush TLB
jmp CODE_SEL16:pmode32_to_pmode16
BITS 16
pmode32_to_pmode16: ; finish switching to 16-bit pmode
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -