简介
在上篇中从初始启动文件中加载了loader文件进行执行,本篇将在loader进行CPU模式切换,进入64位模式
工具添加
迫于无奈,在N次尝试后,需要在《30天自制操作系统》书中的一些工具进行辅助,清单大致如下:
- edimg.exe : 类似一个修改iso文件的工具,可以将文件添加到已经生成的iso文件中,缺点就是只能添加单个文件(在书中看目前作者意思是将C编译处理后得到的汇编码和loader汇编码进行合并,如果能添加多个文件,那也不用合并吧,哎,目前尝试下来是不能添加多个)
- fdimg0at.tek: edimg.exe 的辅助文件,具体作用不详
上个两个工具都会同步到仓库中
关于为什么要进行模式切换
在看两本书和查资料总结下来,个人感觉核心是内存地址映射问题:
CPU虽然有寄存器,但也就只有有限的几个,而我们的程序数据很大,不可能都放到寄存器中,所以大部分数据都放到了内存中
而CPU访问内存中的数据需要数据所在的地址,这个数据的内存地址是用CPU的寄存器进行保存的
寄存器的每一位是用0和1表示,那16位寄存器能表示的最大的地址范围是:2的16次方,32位就是2的32次方,64位就是2的64次方
32位大约是4G,64位很大很大了(学到这解了我以前老电脑为啥只能支持4G内存,而新电脑现在都能加到32G的疑惑)
构建脚本修改
如果使用图形化的工具,比如winiso,手动修改iso文件进行添加的话,也能达到目的,但不能写完代码后一键运行,太影响效率了(目前感觉还是一键运行比较好,也尝试了通过python脚本修改,但在window11下有点问题,哎,令人发愁的环境问题)
目前改为如下:编译两个asm文件,然后用edimg将文件制作成iso镜像,最后运行
运行结果如下:
相关代码修改
每天早上起来一个小时就在折腾,然而并没有什么用,要不就是不运行,要不就是一直闪屏,最后就是一直循环,搞的我都崩溃了
自己参考并抄他们一部分代码跑不动,没有办法,只能直接抄全部了,所以myOS.asm和loader.asm都进行了修改,把《一个64位系统的设计和实现》中的前3章关于CPU模式切换的部分给抄了下来,具体的详情都在下面进行说明
myOS.asm
所有代码如下:
org 0x7c00
BaseOfStack equ 0x7c00
BaseOfLoader equ 0x1000
OffsetOfLoader equ 0x00
RootDirSectors equ 14
SectorNumOfRootDirStart equ 19
SectorNumOfFAT1Start equ 1
SectorBalance equ 17
jmp short Label_Start
nop
BS_OEMName db 'MINEboot'
BPB_BytesPerSec dw 512
BPB_SecPerClus db 1
BPB_RsvdSecCnt dw 1
BPB_NumFATs db 2
BPB_RootEntCnt dw 224
BPB_TotSec16 dw 2880
BPB_Media db 0xf0
BPB_FATSz16 dw 9
BPB_SecPerTrk dw 18
BPB_NumHeads dw 2
BPB_HiddSec dd 0
BPB_TotSec32 dd 0
BS_DrvNum db 0
BS_Reserved1 db 0
BS_BootSig db 0x29
BS_VolID dd 0
BS_VolLab db 'boot loader'
BS_FileSysType db 'FAT12 '
Label_Start:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
;======= clear screen
mov ax, 0600h
mov bx, 0700h
mov cx, 0
mov dx, 0184fh
int 10h
;======= set focus
mov ax, 0200h
mov bx, 0000h
mov dx, 0000h
int 10h
;======= display on screen : Start Booting......
mov ax, 1301h
mov bx, 000fh
mov dx, 0000h
mov cx, 10
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, StartBootMessage
int 10h
;======= reset floppy
xor ah, ah
xor dl, dl
int 13h
;======= search loader.bin
mov word [SectorNo], SectorNumOfRootDirStart
Lable_Search_In_Root_Dir_Begin:
cmp word [RootDirSizeForLoop], 0
jz Label_No_LoaderBin
dec word [RootDirSizeForLoop]
mov ax, 00h
mov es, ax
mov bx, 8000h
mov ax, [SectorNo]
mov cl, 1
call Func_ReadOneSector
mov si, LoaderFileName
mov di, 8000h
cld
mov dx, 10h
Label_Search_For_LoaderBin:
cmp dx, 0
jz Label_Goto_Next_Sector_In_Root_Dir
dec dx
mov cx, 11
Label_Cmp_FileName:
cmp cx, 0
jz Label_FileName_Found
dec cx
lodsb
cmp al, byte [es:di]
jz Label_Go_On
jmp Label_Different
Label_Go_On:
inc di
jmp Label_Cmp_FileName
Label_Different:
and di, 0ffe0h
add di, 20h
mov si, LoaderFileName
jmp Label_Search_For_LoaderBin
Label_Goto_Next_Sector_In_Root_Dir:
add word [SectorNo], 1
jmp Lable_Search_In_Root_Dir_Begin
;======= display on screen : ERROR:No LOADER Found
Label_No_LoaderBin:
mov ax, 1301h
mov bx, 008ch
mov dx, 0100h
mov cx, 21
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, NoLoaderMessage
int 10h
jmp $
;======= found loader.bin name in root director struct
Label_FileName_Found:
mov ax, RootDirSectors
and di, 0ffe0h
add di, 01ah
mov cx, word [es:di]
push cx
add cx, ax
add cx, SectorBalance
mov ax, BaseOfLoader
mov es, ax
mov bx, OffsetOfLoader
mov ax, cx
Label_Go_On_Loading_File:
push ax
push bx
mov ah, 0eh
mov al, '.'
mov bl, 0fh
int 10h
pop bx
pop ax
mov cl, 1
call Func_ReadOneSector
pop ax
call Func_GetFATEntry
cmp ax, 0fffh
jz Label_File_Loaded
push ax
mov dx, RootDirSectors
add ax, dx
add ax, SectorBalance
add bx, [BPB_BytesPerSec]
jmp Label_Go_On_Loading_File
Label_File_Loaded:
jmp BaseOfLoader:OffsetOfLoader
;======= read one sector from floppy
Func_ReadOneSector:
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]
Label_Go_On_Reading:
mov ah, 2
mov al, byte [bp - 2]
int 13h
jc Label_Go_On_Reading
add esp, 2
pop bp
ret
;======= get FAT Entry
Func_GetFATEntry:
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 Label_Even
mov byte [Odd], 1
Label_Even:
xor dx, dx
mov bx, [BPB_BytesPerSec]
div bx
push dx
mov bx, 8000h
add ax, SectorNumOfFAT1Start
mov cl, 2
call Func_ReadOneSector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [Odd], 1
jnz Label_Even_2
shr ax, 4
Label_Even_2:
and ax, 0fffh
pop bx
pop es
ret
;======= tmp variable
RootDirSizeForLoop dw RootDirSectors
SectorNo dw 0
Odd db 0
;======= display messages
StartBootMessage: db "Start Boot"
NoLoaderMessage: db "ERROR:No LOADER Found"
LoaderFileName: db "LOADER BIN",0
;======= fill zero until whole sector
times 510 - ($ - $$) db 0
dw 0xaa55
看着很多,但主要的作用就是进行一些初始化,然后搜索找到loader.bin文件,加载后执行
loader.asm
具体代码如下:
org 10000h
jmp Label_Start
%include "fat12.inc"
BaseOfKernelFile equ 0x00
OffsetOfKernelFile equ 0x100000
BaseTmpOfKernelAddr equ 0x00
OffsetTmpOfKernelFile equ 0x7E00
MemoryStructBufferAddr equ 0x7E00
[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]
Label_Start:
mov ax, cs
mov ds, ax
mov es, ax
mov ax, 0x00
mov ss, ax
mov sp, 0x7c00
;======= display on screen : Start Loader......
mov ax, 1301h
mov bx, 000fh
mov dx, 0200h ;row 2
mov cx, 12
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, StartLoaderMessage
int 10h
;======= open address 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
;======= reset floppy
xor ah, ah
xor dl, dl
int 13h
KillMotor:
push dx
mov dx, 03F2h
mov al, 0
out dx, al
pop dx
;======= get memory address size type
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
Label_Get_Mem_Struct:
mov eax, 0x0E820
mov ecx, 20
mov edx, 0x534D4150
int 15h
jc Label_Get_Mem_Fail
add di, 20
cmp ebx, 0
jne Label_Get_Mem_Struct
jmp Label_Get_Mem_OK
Label_Get_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 fin
Label_Get_Mem_OK:
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
;======= get SVGA information
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 .KO
;======= Fail
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 fin
.KO:
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
;======= Get SVGA Mode Info
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
Label_SVGA_Mode_Info_Get:
mov cx, word [es:esi]
;======= display SVGA mode information
push ax
mov ax, 00h
mov al, ch
call Label_DispAL
mov ax, 00h
mov al, cl
call Label_DispAL
pop ax
;=======
cmp cx, 0FFFFh
jz Label_SVGA_Mode_Info_Finish
mov ax, 4F01h
int 10h
cmp ax, 004Fh
jnz Label_SVGA_Mode_Info_FAIL
add esi, 2
add edi, 0x100
jmp Label_SVGA_Mode_Info_Get
Label_SVGA_Mode_Info_FAIL:
mov ax, 1301h
mov bx, 008Ch
mov dx, 0D00h ;row 13
mov cx, 24
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, GetSVGAModeInfoErrMessage
int 10h
Label_SET_SVGA_Mode_VESA_VBE_FAIL:
jmp fin
Label_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
;======= set the SVGA mode(VESA VBE)
mov ax, 4F02h
mov bx, 4180h ;========================mode : 0x180 or 0x143
int 10h
cmp ax, 004Fh
jnz Label_SET_SVGA_Mode_VESA_VBE_FAIL
;======= init IDT GDT goto protect mode
cli ;======close interrupt
db 0x66
lgdt [GdtPtr]
; db 0x66
; lidt [IDT_POINTER]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword SelectorCode32:GO_TO_TMP_Protect
[SECTION .s32]
[BITS 32]
GO_TO_TMP_Protect:
;======= go to tmp long mode
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov ss, ax
mov esp, 7E00h
call support_long_mode
test eax, eax
jz no_support
;======= init temporary page table 0x90000
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
;======= load 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
;======= open PAE
mov eax, cr4
bts eax, 5
mov cr4, eax
;======= load cr3
mov eax, 0x90000
mov cr3, eax
;======= enable long-mode
mov ecx, 0C0000080h ;IA32_EFER
rdmsr
bts eax, 8
wrmsr
;======= open PE and paging
mov eax, cr0
bts eax, 0
bts eax, 31
mov cr0, eax
; jmp SelectorCode64:OffsetOfKernelFile
jmp fin
;======= test support long mode or not
support_long_mode:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
setnb al
jb support_long_mode_done
mov eax, 0x80000001
cpuid
bt edx, 29
setc al
support_long_mode_done:
movzx eax, al
ret
;======= no support
no_support:
jmp fin
;======= read one sector from floppy
[SECTION .s16lib]
[BITS 16]
Func_ReadOneSector:
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]
Label_Go_On_Reading:
mov ah, 2
mov al, byte [bp - 2]
int 13h
jc Label_Go_On_Reading
add esp, 2
pop bp
ret
;======= get FAT Entry
Func_GetFATEntry:
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 Label_Even
mov byte [Odd], 1
Label_Even:
xor dx, dx
mov bx, [BPB_BytesPerSec]
div bx
push dx
mov bx, 8000h
add ax, SectorNumOfFAT1Start
mov cl, 2
call Func_ReadOneSector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [Odd], 1
jnz Label_Even_2
shr ax, 4
Label_Even_2:
and ax, 0FFFh
pop bx
pop es
ret
;======= display num in al
Label_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
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
;======= tmp IDT
IDT:
times 0x50 dq 0
IDT_END:
IDT_POINTER:
dw IDT_END - IDT - 1
dd IDT
;======= tmp variable
RootDirSizeForLoop dw RootDirSectors
SectorNo dw 0
Odd db 0
OffsetOfKernelFileCount dd OffsetOfKernelFile
DisplayPosition dd 0
;======= display messages
StartLoaderMessage: db "Start Loader"
NoLoaderMessage: db "ERROR:No KERNEL Found"
KernelFileName: db "KERNEL BIN",0
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!"
fat12.inc 是FAT格式声明,如下:
RootDirSectors equ 14
SectorNumOfRootDirStart equ 19
SectorNumOfFAT1Start equ 1
SectorBalance equ 17
BS_OEMName db 'MINEboot'
BPB_BytesPerSec dw 512
BPB_SecPerClus db 1
BPB_RsvdSecCnt dw 1
BPB_NumFATs db 2
BPB_RootEntCnt dw 224
BPB_TotSec16 dw 2880
BPB_Media db 0xf0
BPB_FATSz16 dw 9
BPB_SecPerTrk dw 18
BPB_NumHeads dw 2
BPB_hiddSec dd 0
BPB_TotSec32 dd 0
BS_DrvNum db 0
BS_Reserved1 db 0
BS_BootSig db 29h
BS_VolID dd 0
BS_VolLab db 'boot loader'
BS_FileSysType db 'FAT12 '
这个文件里面的模式切换是最近搞人心态的,想抄点核心的在之前自己的代码上,但一直有问题,拖了太久了,想着还是算了,抄了过了再说吧
原来的代码是需要在loader中搜索kernel.bin,加载后跳转执行的(这个其实是我想要的方式),但这本书通看下来,更像是在写一个服务器,桌面好像不太行
鉴于这次的教训,不太敢作了......还是老老实实的跟踪写图形界面的那本走,不然后面可能不太好走
所以把搜索加载kernel执行的这部分代码给删除了,只保留了模式切换的部分
可以看到删除后依旧是500多行的代码,我也只能认输了
总结
模式切换感觉基本上也是固定的,不纠结了,先直接抄了过了再说(有点后面前面浪费的时间,应该早点这样搞的)
这次也是个教训,新手还是先做对,再做好,一直卡着太浪费时间了