一个操作系统的实现4——Loader
loader.asm
org 10000h
jmp Della_Start
%include "Fat12.inc"
BaseOfKernelFile equ 0x00
OffsetOfKernelFile equ 0x100000 ;1048576=1024*1024
BaseTempOfKernelAddr equ 0x00
OffsetTempOfKernelFile equ 0x7E00
MemoryStructBufferAddr equ 0x7E00
RootDirSizeForLoop dw RootDirSectors
SectorNo dw 0
Odd db 0
DisplayPosition dd 0
LoaderMessage: db "Della Loader"
NoKernelMessage: db "No kernel!"
HasKernelMessage: db "Has kernel"
StartGetMemStructMessage: db "Start Get Memory Struct."
GetMemStructErrMessage: db "Get Memory Struct ERROR"
GetMemStructOKMessage: db "Get Memory Struct SUCCESSFUL!"
StartGetSVGAVBEInfoMessage: db "Start Get SVGA VBE Info"
GetSVGAVBEInfoErrMessage: db "Get SVGA VBE Info ERROR"
GetSVGAVBEInfoOKMessage: db "Get SVGA VBE Info SUCCESSFUL!"
StartGetSVGAModeInfoMessage: db "Start Get SVGA Mode Info"
GetSVGAModeInfoErrMessage: db "Get SVGA Mode Info ERROR"
GetSVGAModeInfoOKMessage: db "Get SVGA Mode Info SUCCESSFUL!"
ProtectModeMessage db "Protect Mode Ready!"
KernelFileName: db "KERNEL BIN",0
OffsetOfKernelFileCount dd OffsetOfKernelFile
[SECTION gdt] ;保护模式数据结构
LABEL_GDT: dd 0,0
LABEL_DESC_CODE32: dd 0x0000FFFF,0x00CF9A00
LABEL_DESC_DATA32: dd 0x0000FFFF,0x00CF9200
GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
dd LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorData32 equ LABEL_DESC_DATA32 - LABEL_GDT
[SECTION gdt64]
LABEL_GDT64: dq 0x0000000000000000
LABEL_DESC_CODE64: dq 0x0020980000000000
LABEL_DESC_DATA64: dq 0x0000920000000000
GdtLen64 equ $ - LABEL_GDT64
GdtPtr64 dw GdtLen64 - 1
dd LABEL_GDT64
SelectorCode64 equ LABEL_DESC_CODE64 - LABEL_GDT64
SelectorData64 equ LABEL_DESC_DATA64 - LABEL_GDT64
[SECTION .s16]
[BITS 16]
Della_Start:
;重置寄存器
mov ax, cs
mov ds, ax
mov es, ax
mov ax, 0x00
mov ss, ax
mov sp, 0x7c00
;打印字符串
mov ax, 1301h
mov bx, 000fh
mov dx, 0000h
mov cx, 12
mov bp, LoaderMessage
int 10h
;打开A20地址线
push ax
in al, 92h
or al, 00000010b
out 92h, al
pop ax
;初始化保护模式数据结构
cli ;禁止中断
db 0x66
lgdt [GdtPtr]
mov eax, cr0
or eax, 1
mov cr0, eax
mov ax, SelectorData32
mov fs, ax
mov eax, cr0
and al, 11111110b
mov cr0, eax
sti ;允许中断
;软驱复位
xor ah, ah
xor dl, dl
int 13h
;寻找kernel.bin
mov word [SectorNo], SectorNumOfRootDirStart
;遍历目录
Search_In_Root_Dir:
cmp word [RootDirSizeForLoop], 0
jz No_Kernel
dec word [RootDirSizeForLoop]
mov ax, 00h
mov es, ax
mov bx, 8000h
mov ax, [SectorNo]
mov cl, 1
call ReadSector
mov si, KernelFileName
mov di, 8000h
cld
mov dx, 10h
;查找kernel
Search_Kernel:
cmp dx, 0
jz Next_Sector_In_Root_Dir
dec dx
mov cx, 11
;比较文件名
Compare_FileName:
cmp cx, 0
jz Has_Loader
dec cx
lodsb
cmp al, byte [es:di]
jz Go_On
jmp FileName_Different
Go_On:
inc di
jmp Compare_FileName
FileName_Different:
and di, 0FFE0h
add di, 20h
mov si, KernelFileName
jmp Search_Kernel
Next_Sector_In_Root_Dir:
add word [SectorNo], 1
jmp Search_In_Root_Dir
;kernel未找到
No_Kernel:
mov ax, 1301h
mov bx, 008Ch
mov dx, 0300h ;row 3
mov cx, 10
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, NoKernelMessage
int 10h
jmp $
;找到了kernel
Has_Loader:
mov ax, RootDirSectors
and di, 0FFE0h
add di, 01Ah
mov cx, word [es:di]
push cx
add cx, ax
add cx, SectorBalance
mov eax, BaseTempOfKernelAddr ;BaseOfKernelFile
mov es, eax
mov bx, OffsetTempOfKernelFile ;OffsetOfKernelFile
mov ax, cx
On_Loading:
push ax
push bx
mov ah, 0Eh
mov al, '.'
mov bl, 0Fh
int 10h
pop bx
pop ax
mov cl, 1
call ReadSector
pop ax
push cx
push eax
push fs
push edi
push ds
push esi
mov cx, 200h
mov ax, BaseOfKernelFile
mov fs, ax
mov edi, dword [OffsetOfKernelFileCount]
mov ax, BaseTempOfKernelAddr
mov ds, ax
mov esi, OffsetTempOfKernelFile
;移动内核
Mov_Kernel:
mov al, byte [ds:esi]
mov byte [fs:edi], al
inc esi
inc edi
loop Mov_Kernel
mov eax, 0x1000
mov ds, eax
mov dword [OffsetOfKernelFileCount], edi
pop esi
pop ds
pop edi
pop fs
pop eax
pop cx
call FATEntry
cmp ax, 0FFFh
jz On_Loaded
push ax
mov dx, RootDirSectors
add ax, dx
add ax, SectorBalance
jmp On_Loading
On_Loaded:
mov ax, 0B800h
mov gs, ax
mov ah, 0Fh
mov al, 'D'
mov [gs:((80 * 0 + 39) * 2)], ax
;关闭软驱
KillMotor:
push dx
mov dx, 03F2h
mov al, 0
out dx, al
pop dx
;开始获取内存信息
mov ax, 1301h
mov bx, 000Fh
mov dx, 0400h ;row 4
mov cx, 24
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, StartGetMemStructMessage
int 10h
mov ebx, 0
mov ax, 0x00
mov es, ax
mov di, MemoryStructBufferAddr
;内存结构
Mem_Struct:
mov eax, 0x0E820
mov ecx, 20
mov edx, 0x534D4150
int 15h
jc Mem_Fail
add di, 20
cmp ebx, 0
jne Mem_Struct
jmp Mem_Loaded
;获取内存信息完失败
Mem_Fail:
mov ax, 1301h
mov bx, 008Ch
mov dx, 0500h ;row 5
mov cx, 23
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetMemStructErrMessage
int 10h
jmp $
;获取内存信息完毕
Mem_Loaded:
mov ax, 1301h
mov bx, 000Fh
mov dx, 0600h ;row 6
mov cx, 29
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetMemStructOKMessage
int 10h
;开始获取SVGA信息
mov ax, 1301h
mov bx, 000Fh
mov dx, 0800h ;row 8
mov cx, 23
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, StartGetSVGAVBEInfoMessage
int 10h
mov ax, 0x00
mov es, ax
mov di, 0x8000
mov ax, 4F00h
int 10h
cmp ax, 004Fh
jz .SVGA_Loaded
;获取SVGA信息失败
mov ax, 1301h
mov bx, 008Ch
mov dx, 0900h ;row 9
mov cx, 23
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetSVGAVBEInfoErrMessage
int 10h
jmp $
;获取SVGA信息成功
.SVGA_Loaded:
mov ax, 1301h
mov bx, 000Fh
mov dx, 0A00h ;row 10
mov cx, 29
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetSVGAVBEInfoOKMessage
int 10h
;开始获取SVGA显示模式信息
mov ax, 1301h
mov bx, 000Fh
mov dx, 0C00h ;row 12
mov cx, 24
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, StartGetSVGAModeInfoMessage
int 10h
mov ax, 0x00
mov es, ax
mov si, 0x800e
mov esi, dword [es:si]
mov edi, 0x8200
;获取SVGA显示模式信息
SVGA_Mode_Info:
mov cx, word [es:esi]
;打印SVGA显示模式信息
push ax
mov ax, 00h
mov al, ch
call DispAL
mov ax, 00h
mov al, cl
call DispAL
pop ax
cmp cx, 0FFFFh
jz SVGA_Mode_Info_Finish
mov ax, 4F01h
int 10h
cmp ax, 004Fh
jnz SVGA_Mode_Info_FAIL
add esi, 2
add edi, 0x100
jmp SVGA_Mode_Info
;获取SVGA显示模式信息失败
SVGA_Mode_Info_FAIL:
mov ax, 1301h
mov bx, 008Ch
mov dx, 0D00h
mov cx, 24
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetSVGAModeInfoErrMessage
int 10h
;设置SVGA显示模式信息失败
SET_SVGA_Mode_VESA_VBE_FAIL:
jmp $
;获取SVGA显示模式信息成功
SVGA_Mode_Info_Finish:
mov ax, 1301h
mov bx, 000Fh
mov dx, 0E00h ;row 14
mov cx, 30
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetSVGAModeInfoOKMessage
int 10h
;设置SVGA显示模式信息
mov ax, 4F02h
mov bx, 4180h ;========================mode : 0x180 or 0x143
int 10h
cmp ax, 004Fh
jnz SET_SVGA_Mode_VESA_VBE_FAIL
;初始化IDT、GDT
cli
db 0x66
lgdt [GdtPtr]
; db 0x66
; lidt [IDT_POINTER]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword SelectorCode32:Protect_Mode
[SECTION .s32]
[BITS 32]
Protect_Mode:
;为长模式作准备
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov ss, ax
mov esp, 7E00h
call Test_Long_Mode
test eax, eax
jz No_Support_Long_Mode
;初始化页表
mov dword [0x90000], 0x91007
mov dword [0x90800], 0x91007
mov dword [0x91000], 0x92007
mov dword [0x92000], 0x000083
mov dword [0x92008], 0x200083
mov dword [0x92010], 0x400083
mov dword [0x92018], 0x600083
mov dword [0x92020], 0x800083
mov dword [0x92028], 0xa00083
;加载GDTR
db 0x66
lgdt [GdtPtr64]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 7E00h
;打开PAE
mov eax, cr4
bts eax, 5
mov cr4, eax
;打开cr3
mov eax, 0x90000
mov cr3, eax
;启用长模式
mov ecx, 0C0000080h ;IA32_EFER
rdmsr
bts eax, 8
wrmsr
;打开PE和分页
mov eax, cr0
bts eax, 0
bts eax, 31
mov cr0, eax
jmp SelectorCode64:OffsetOfKernelFile
;测试是否支持长模式
Test_Long_Mode:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
setnb al
jb Support_Long_Mode
mov eax, 0x80000001
cpuid
bt edx, 29
setc al
;支持长模式
Support_Long_Mode:
movzx eax, al
ret
;不支持长模式
No_Support_Long_Mode:
jmp $
[SECTION .s16lib]
[BITS 16]
;读取扇区
ReadSector:
push bp
mov bp, sp
sub esp, 2
mov byte [bp - 2], cl
push bx
mov bl, [BPB_SecPerTrk]
div bl
inc ah
mov cl, ah
mov dh, al
shr al, 1
mov ch, al
and dh, 1
pop bx
mov dl, [BS_DrvNum]
On_Reading:
mov ah, 2
mov al, byte [bp - 2]
int 13h
jc On_Reading
add esp, 2
pop bp
ret
;获取FAT项值
FATEntry:
push es
push bx
push ax
mov ax, 00
mov es, ax
pop ax
mov byte [Odd], 0
mov bx, 3
mul bx
mov bx, 2
div bx
cmp dx, 0
jz EvenNumber
mov byte [Odd], 1
EvenNumber:
xor dx, dx
mov bx, [BPB_BytesPerSec]
div bx
push dx
mov bx, 8000h
add ax, SectorNumOfFAT1Start
mov cl, 2
call ReadSector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [Odd], 1
jnz OddNumber
shr ax, 4
OddNumber:
and ax, 0fffh
pop bx
pop es
ret
;打印16进制数字
DispAL:
push ecx
push edx
push edi
mov edi, [DisplayPosition]
mov ah, 0Fh
mov dl, al
shr al, 4
mov ecx, 2
.begin:
and al, 0Fh
cmp al, 9
ja .1
add al, '0'
jmp .2
.1:
sub al, 0Ah
add al, 'A'
.2:
mov [gs:edi], ax
add edi, 2
mov al, dl
loop .begin
mov [DisplayPosition], edi
pop edi
pop edx
pop ecx
ret
可以搭配kernel.asm测试以下,bochs窗口会变大,也可阶段测试,查看打印信息
|