mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
🆕 切换为grub2引导,能进入Start_Kernel函数(未能完成初始化)
This commit is contained in:
parent
a2aea12510
commit
0b0cce9326
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/cmake-build-debug/
|
||||
/bin/
|
||||
./DragonOS.iso
|
3
Makefile
3
Makefile
@ -1,7 +1,8 @@
|
||||
SUBDIRS = bootloader kernel
|
||||
SUBDIRS = kernel
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
mkdir -p bin/kernel/
|
||||
@list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "make all in $$subdir";\
|
||||
cd $$subdir;\
|
||||
|
13
bochsrc
13
bochsrc
@ -5,16 +5,17 @@ config_interface: textconfig
|
||||
#memory: host=2048, guest=2048
|
||||
romimage: file="/usr/local/share/bochs/BIOS-bochs-latest"
|
||||
vgaromimage: file="/usr/local/share/bochs/VGABIOS-lgpl-latest"
|
||||
boot: floppy
|
||||
floppy_bootsig_check: disabled=0
|
||||
floppya: type=1_44, 1_44="bin/boot.img", status=inserted, write_protected=0
|
||||
# ata0-master: type=disk, path="/data/home/longjin/code/hd.img", mode=flat
|
||||
|
||||
boot: cdrom
|
||||
|
||||
# no floppyb
|
||||
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata0-master: type=none
|
||||
ata0-slave: type=none
|
||||
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata1-master: type=none
|
||||
ata1-slave: type=none
|
||||
|
||||
ata1-master: type=cdrom, path="DragonOS.iso", status=inserted
|
||||
|
||||
ata2: enabled=0
|
||||
ata3: enabled=0
|
||||
pci: enabled=1, chipset=i440fx
|
||||
|
BIN
boot(empty).img
BIN
boot(empty).img
Binary file not shown.
@ -1,11 +0,0 @@
|
||||
all: boot.bin loader.bin
|
||||
|
||||
boot.bin: boot.asm
|
||||
nasm boot.asm -o ../bin/bootloader/boot.bin
|
||||
|
||||
loader.bin: loader.asm
|
||||
nasm loader.asm -o ../bin/bootloader/loader.bin
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf *.asm~ Makefile~
|
@ -1,299 +0,0 @@
|
||||
;将程序开始位置设置为0x7c00处,并给BaseOfStack赋值为0x7c00
|
||||
org 0x7c00
|
||||
|
||||
BaseOfStack equ 0x7c00
|
||||
BaseOfLoader equ 0x1000
|
||||
OffsetOfLoader equ 0x00
|
||||
|
||||
RootDirSectors equ 14 ;根目录占用的扇区数
|
||||
SectorNumOfRootDirStart equ 19 ; 根目录的起始扇区号
|
||||
SectorNumOfFAT1Start equ 1 ; FAT1表的起始扇区号 (因为前面有一个保留扇区(引导扇区))
|
||||
SectorBalance equ 17 ;平衡文件/目录的起始簇号与数据区域的起始簇号的差值。
|
||||
|
||||
|
||||
jmp short Label_Start
|
||||
nop
|
||||
BS_OEMName db 'DragonOS'
|
||||
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
|
||||
|
||||
;清屏
|
||||
mov ax, 0x0600 ;AL=0时,清屏,BX、CX、DX不起作用
|
||||
mov bx, 0x0700 ;设置白色字体,不闪烁,字体正常亮度,黑色背景
|
||||
mov cx, 0
|
||||
mov dx, 0184fh
|
||||
int 0x10
|
||||
|
||||
;设置屏幕光标位置为左上角(0,0)的位置
|
||||
mov ax, 0x0200
|
||||
mov bx, 0x0000
|
||||
mov dx, 0x0000
|
||||
int 10h
|
||||
|
||||
;在屏幕上显示Start Booting
|
||||
mov ax, 0x1301 ;设置显示字符串,显示后,光标移到字符串末端
|
||||
mov bx, 0x000a ;设置黑色背景,白色字体,高亮度,不闪烁
|
||||
mov dx, 0x0000 ;设置游标行列号均为0
|
||||
mov cx, 24 ;设置字符串长度为24
|
||||
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, StartBootMessage
|
||||
int 0x10
|
||||
|
||||
;软盘驱动器复位
|
||||
xor ah, ah
|
||||
xor dl, dl
|
||||
int 0x13
|
||||
|
||||
; 在文件系统中搜索 loader.bin
|
||||
mov word [SectorNo], SectorNumOfRootDirStart ;保存根目录起始扇区号
|
||||
|
||||
Label_Search_In_Root_Dir_Begin:
|
||||
cmp word [RootDirSizeForLoop], 0 ; 比较根目录扇区数量和0的关系。 cmp实际上是进行了一个减法运算
|
||||
jz Label_No_LoaderBin ; 等于0,不存在Loader.bin
|
||||
dec word [RootDirSizeForLoop]
|
||||
|
||||
mov ax, 0x00
|
||||
mov es, ax
|
||||
mov bx, 0x8000
|
||||
mov ax, [SectorNo] ;向函数传入扇区号
|
||||
mov cl, 1
|
||||
call Func_ReadOneSector
|
||||
mov si, LoaderFileName ;向源变址寄存器传入Loader文件的名字
|
||||
mov di, 0x8000
|
||||
cld ;由于LODSB的加载方向与DF标志位有关,因此需要用CLD清零DF标志位
|
||||
|
||||
mov dx, 0x10 ; 每个扇区的目录项的最大条数是(512/32=16,也就是0x10)
|
||||
|
||||
Label_Search_For_LoaderBin:
|
||||
cmp dx, 0
|
||||
jz Label_Goto_Next_Sector_In_Root_Dir
|
||||
dec dx
|
||||
mov cx, 11 ; cx寄存器存储目录项的文件名长度, 11B,包括了文件名和扩展名,但是不包括 分隔符'.'
|
||||
|
||||
Label_Cmp_FileName:
|
||||
cmp cx, 0
|
||||
jz Label_FileName_Found
|
||||
dec cx
|
||||
lodsb ; 把si对应的字节载入al寄存器中,然后,由于DF为0,si寄存器自增
|
||||
cmp al, byte [es:di] ; 间接取址[es+di]。 也就是进行比较当前文件的名字对应字节和loader文件名对应字节
|
||||
jz Label_Go_On ; 对应字节相同
|
||||
jmp Label_Different ; 字节不同,不是同一个文件
|
||||
|
||||
Label_Go_On:
|
||||
inc di
|
||||
jmp Label_Cmp_FileName
|
||||
|
||||
Label_Different:
|
||||
and di, 0xffe0 ;将di恢复到当前目录项的第0字节
|
||||
add di, 0x20 ;将di跳转到下一目录项的第0字节
|
||||
mov si, LoaderFileName
|
||||
jmp Label_Search_For_LoaderBin ;继续搜索下一目录项
|
||||
|
||||
Label_Goto_Next_Sector_In_Root_Dir:
|
||||
add word [SectorNo], 1
|
||||
jmp Label_Search_In_Root_Dir_Begin
|
||||
|
||||
Label_No_LoaderBin:
|
||||
; 在屏幕上显示 [ERROR] No Loader Found.
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000c ; 红色闪烁高亮黑底
|
||||
mov dx, 0x0100 ; 显示在第二行(前面已经显示过一行了)
|
||||
mov cx, 24 ; 字符串长度
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, NoLoaderMessage
|
||||
int 0x10
|
||||
jmp $
|
||||
|
||||
|
||||
;========== 找到了Loader.Bin
|
||||
|
||||
Label_FileName_Found:
|
||||
mov ax, RootDirSectors
|
||||
|
||||
; 先取得目录项DIR_FstClus字段的值(起始簇号)
|
||||
and di, 0xffe0
|
||||
add di, 0x1a
|
||||
mov cx, word [es:di]
|
||||
push cx
|
||||
|
||||
|
||||
add cx, ax
|
||||
add cx, SectorBalance
|
||||
mov ax, BaseOfLoader
|
||||
mov es, ax ;配置es和bx,指定loader.bin在内存中的起始地址
|
||||
mov bx, OffsetOfLoader
|
||||
mov ax, cx
|
||||
|
||||
Label_Go_On_Loading_File:
|
||||
push ax
|
||||
push bx
|
||||
|
||||
; 显示字符.
|
||||
mov ah, 0x0e
|
||||
mov al, "."
|
||||
mov bl, 0x0f
|
||||
int 0x10
|
||||
|
||||
pop bx
|
||||
pop ax
|
||||
|
||||
|
||||
; 每读取一个扇区,就获取下一个表项,然后继续读入下一个簇的数据,直到返回的下一表项为0xfff为止,表示loader.bin完全加载完成
|
||||
mov cl, 1
|
||||
call Func_ReadOneSector
|
||||
pop ax
|
||||
call Func_GetFATEntry
|
||||
cmp ax, 0xfff
|
||||
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:
|
||||
; 跳转到loader
|
||||
; 这个指令结束后,目标段会复制到CS寄存器中
|
||||
jmp BaseOfLoader:OffsetOfLoader
|
||||
|
||||
|
||||
; 从软盘读取一个扇区
|
||||
; AX=待读取的磁盘起始扇区号
|
||||
; CL=读入的扇区数量
|
||||
; ES:BX=>目标缓冲区起始地址
|
||||
Func_ReadOneSector:
|
||||
push bp
|
||||
mov bp, sp
|
||||
sub esp, 2
|
||||
mov byte [bp-2], cl
|
||||
push bx
|
||||
mov bl, [BPB_SecPerTrk]
|
||||
div bl ;用AX寄存器中的值除以BL,得到目标磁道号(商:AL)以及目标磁道内的起始扇区号(余数:AH)
|
||||
inc ah ; 由于磁道内的起始扇区号从1开始计数,因此将余数+1
|
||||
mov cl, ah
|
||||
mov dh, al
|
||||
shr al, 1 ;计算出柱面号
|
||||
mov ch, al
|
||||
and dh, 1;计算出磁头号
|
||||
|
||||
pop bx
|
||||
mov dl, [BS_DrvNum]
|
||||
;最终,dh存储了磁头号,dl存储驱动器号
|
||||
; ch存储柱面号,cl存储起始扇区号
|
||||
|
||||
Label_Go_On_Reading:
|
||||
; 使用BIOS中断服务程序INT13h的主功能号AH=02h实现软盘读取操作
|
||||
mov ah, 2
|
||||
mov al, byte [bp-2]
|
||||
int 0x13
|
||||
jc Label_Go_On_Reading ;当CF标志位被复位时,说明数据读取完成,恢复调用现场
|
||||
|
||||
add esp, 2
|
||||
pop bp
|
||||
ret
|
||||
|
||||
|
||||
; 解析FAT表项,根据当前FAT表项索引出下一个FAT表项
|
||||
Func_GetFATEntry:
|
||||
; AX=FAT表项号(输入、输出参数)
|
||||
; 保存将要被修改的寄存器
|
||||
push es
|
||||
push bx
|
||||
push ax
|
||||
|
||||
; 扩展段寄存器
|
||||
mov ax, 00
|
||||
mov es, ax
|
||||
|
||||
pop ax
|
||||
mov byte [Odd], 0 ;将奇数标志位置0
|
||||
|
||||
; 将FAT表项号转换为总的字节号
|
||||
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 ;把dx置0
|
||||
|
||||
; 计算得到扇区号(商)和扇区内偏移(余数)
|
||||
mov bx, [BPB_BytesPerSec]
|
||||
div bx
|
||||
push dx
|
||||
|
||||
; 读取两个扇区到[es:bx]
|
||||
mov bx, 0x8000
|
||||
add ax, SectorNumOfFAT1Start
|
||||
mov cl, 2 ; 设置读取两个扇区,解决FAT表项跨扇区的问题
|
||||
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, 0x0fff ; 确保表项号在正确的范围内 0x0003~0x0fff
|
||||
pop bx
|
||||
pop es
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; 临时变量
|
||||
RootDirSizeForLoop dw RootDirSectors
|
||||
SectorNo dw 0
|
||||
Odd db 0
|
||||
|
||||
|
||||
; 显示的文本
|
||||
StartBootMessage: db "[DragonOS] Start Booting"
|
||||
NoLoaderMessage: db "[ERROR] No LOADER Found."
|
||||
LoaderFileName: db "LOADER BIN",0 ;最后这个0是为了填满12字节的宽度
|
||||
|
||||
;填满整个扇区的512字节
|
||||
times 510 - ( $ - $$ ) db 0
|
||||
dw 0xaa55 ;===确保以0x55 0xaa为结尾
|
||||
|
@ -1,25 +0,0 @@
|
||||
; === 这是FAT12文件系统的信息 ===
|
||||
RootDirSectors equ 14 ;根目录占用的扇区数
|
||||
SectorNumOfRootDirStart equ 19 ; 根目录的起始扇区号
|
||||
SectorNumOfFAT1Start equ 1 ; FAT1表的起始扇区号 (因为前面有一个保留扇区(引导扇区))
|
||||
SectorBalance equ 17 ;平衡文件/目录的起始簇号与数据区域的起始簇号的差值。
|
||||
|
||||
BS_OEMName db 'DragonOS'
|
||||
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 '
|
@ -1,846 +0,0 @@
|
||||
; |==================|
|
||||
; | 这是loader程序 |
|
||||
; |==================|
|
||||
; Created by longjin, 2022/01/17
|
||||
|
||||
; 由于实模式下,物理地址为CS<<4+IP,而从boot的定义中直到,loader的CS为0x1000, 因此loader首地址为0x10000
|
||||
org 0x10000
|
||||
jmp Label_Start
|
||||
|
||||
%include 'fat12.inc' ; 将fat12文件系统的信息包含进来
|
||||
|
||||
Base_Of_Kernel_File equ 0x00
|
||||
Offset_Of_Kernel_File equ 0x100000 ; 设置内核文件的地址空间从1MB处开始。(大于实模式的寻址空间)
|
||||
|
||||
Base_Tmp_Of_Kernel_Addr equ 0x00
|
||||
Offset_Tmp_Of_Kernel_File equ 0x7e00 ; 内核程序的临时转存空间
|
||||
|
||||
Memory_Struct_Buffer_Addr equ 0x7e00 ; 内核被转移到最终的内存空间后,原来的临时空间就作为内存结构数据的存储空间
|
||||
|
||||
; ==== 临时的全局描述符表 =====
|
||||
[SECTION gdt]
|
||||
|
||||
LABEL_GDT: dd 0,0
|
||||
LABEL_DESC_CODE32: dd 0x0000FFFF,0x00CF9A00 ; 代码段和数据段的段基地址都设置在0x00000000处, 把段限长设置为0xffffffff,可以索引32位地址空间
|
||||
LABEL_DESC_DATA32: dd 0x0000FFFF,0x00CF9200
|
||||
|
||||
GdtLen equ $ - LABEL_GDT
|
||||
; GDTR寄存器是一个6B的结构,低2B保存GDT的长度, 高4B保存GDT的基地址
|
||||
GdtPtr dw GdtLen - 1
|
||||
dd LABEL_GDT
|
||||
|
||||
; 这是两个段选择子,是段描述符在GDT表中的索引号
|
||||
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
|
||||
SelectorData32 equ LABEL_DESC_DATA32 - LABEL_GDT
|
||||
|
||||
; === IA-32e模式的临时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] ;定义一个名为.s16的段
|
||||
[BITS 16] ; 通知nasm,将要运行在16位宽的处理器上
|
||||
|
||||
Label_Start:
|
||||
mov ax, cs
|
||||
mov ds, ax ; 初始化数据段寄存器
|
||||
mov es, ax ; 初始化附加段寄存器
|
||||
mov ax, 0x00
|
||||
mov ss, ax ;初始化堆栈段寄存器
|
||||
mov sp, 0x7c00
|
||||
|
||||
;在屏幕上显示 start Loader
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0100 ;在第2行显示
|
||||
mov cx, 26 ;设置消息长度
|
||||
push ax
|
||||
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Start_Loader
|
||||
int 0x10
|
||||
;jmp $
|
||||
|
||||
; 使用A20快速门来开启A20信号线
|
||||
push ax
|
||||
in al, 0x92 ; A20快速门使用I/O端口0x92来处理A20信号线
|
||||
or al, 0x02 ; 通过将0x92端口的第1位置1,开启A20地址线
|
||||
out 0x92, al
|
||||
pop ax
|
||||
|
||||
cli ; 关闭外部中断
|
||||
|
||||
db 0x66
|
||||
lgdt [GdtPtr] ; LGDT/LIDT - 加载全局/中断描述符表格寄存器
|
||||
|
||||
; 置位CR0寄存器的第0位,开启保护模式
|
||||
mov eax, cr0
|
||||
or eax, 1
|
||||
mov cr0, eax
|
||||
|
||||
; 为fs寄存器加载新的数据段的值
|
||||
mov ax, SelectorData32
|
||||
mov fs, ax
|
||||
|
||||
; fs寄存器加载完成后,立即从保护模式退出。 这样能使得fs寄存器在实模式下获得大于1MB的寻址能力。
|
||||
mov eax, cr0
|
||||
and al, 11111110b ; 将第0位置0
|
||||
mov cr0, eax
|
||||
|
||||
sti ; 开启外部中断
|
||||
|
||||
|
||||
|
||||
|
||||
; =========在文件系统中搜索 kernel.bin==========
|
||||
mov word [SectorNo], SectorNumOfRootDirStart ;保存根目录起始扇区号
|
||||
|
||||
Label_Search_In_Root_Dir_Begin:
|
||||
cmp word [RootDirSizeForLoop], 0 ; 比较根目录扇区数量和0的关系。 cmp实际上是进行了一个减法运算
|
||||
jz Label_No_KernelBin ; 等于0,不存在kernel.bin
|
||||
dec word [RootDirSizeForLoop]
|
||||
|
||||
mov ax, 0x00
|
||||
mov es, ax
|
||||
mov bx, 0x8000
|
||||
mov ax, [SectorNo] ;向函数传入扇区号
|
||||
mov cl, 1
|
||||
call Func_ReadOneSector
|
||||
mov si, Kernel_FileName ;向源变址寄存器传入Loader文件的名字
|
||||
mov di, 0x8000
|
||||
cld ;由于LODSB的加载方向与DF标志位有关,因此需要用CLD清零DF标志位
|
||||
|
||||
mov dx, 0x10 ; 每个扇区的目录项的最大条数是(512/32=16,也就是0x10)
|
||||
|
||||
Label_Search_For_LoaderBin:
|
||||
cmp dx, 0
|
||||
jz Label_Goto_Next_Sector_In_Root_Dir
|
||||
dec dx
|
||||
mov cx, 11 ; cx寄存器存储目录项的文件名长度, 11B,包括了文件名和扩展名,但是不包括 分隔符'.'
|
||||
|
||||
Label_Cmp_FileName:
|
||||
cmp cx, 0
|
||||
jz Label_FileName_Found
|
||||
dec cx
|
||||
lodsb ; 把si对应的字节载入al寄存器中,然后,由于DF为0,si寄存器自增
|
||||
cmp al, byte [es:di] ; 间接取址[es+di]。 也就是进行比较当前文件的名字对应字节和loader文件名对应字节
|
||||
jz Label_Go_On ; 对应字节相同
|
||||
jmp Label_Different ; 字节不同,不是同一个文件
|
||||
|
||||
Label_Go_On:
|
||||
inc di
|
||||
jmp Label_Cmp_FileName
|
||||
|
||||
Label_Different:
|
||||
and di, 0xffe0 ;将di恢复到当前目录项的第0字节
|
||||
add di, 0x20 ;将di跳转到下一目录项的第0字节
|
||||
mov si, Kernel_FileName
|
||||
jmp Label_Search_For_LoaderBin ;继续搜索下一目录项
|
||||
|
||||
Label_Goto_Next_Sector_In_Root_Dir:
|
||||
add word [SectorNo], 1
|
||||
jmp Label_Search_In_Root_Dir_Begin
|
||||
|
||||
Label_No_KernelBin:
|
||||
; 在屏幕上显示 [ERROR] No Kernel Found.
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000c ; 红色闪烁高亮黑底
|
||||
mov dx, 0x0200 ; 显示在第3行(前面已经显示过2行了)
|
||||
mov cx, 24 ; 字符串长度
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_No_Loader
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
|
||||
; ========= 找到了 kernel.bin ===========
|
||||
; 将内核加载到内存中
|
||||
Label_FileName_Found:
|
||||
mov ax, RootDirSectors
|
||||
|
||||
; 先取得目录项DIR_FstClus字段的值(起始簇号)
|
||||
and di, 0xffe0
|
||||
add di, 0x1a
|
||||
mov cx, word [es:di]
|
||||
push cx
|
||||
|
||||
|
||||
add cx, ax
|
||||
add cx, SectorBalance
|
||||
mov eax, Base_Tmp_Of_Kernel_Addr ; 内核放置的临时地址
|
||||
mov es, eax ;配置es和bx,指定kernel.bin在内存中的起始地址
|
||||
mov bx, Offset_Tmp_Of_Kernel_File
|
||||
mov ax, cx
|
||||
|
||||
Label_Go_On_Loading_File:
|
||||
;push ax
|
||||
;push bx
|
||||
|
||||
; 显示字符.
|
||||
;mov ah, 0x0e
|
||||
;mov al, "."
|
||||
;mov bl, 0x0f
|
||||
;int 0x10
|
||||
|
||||
;pop bx
|
||||
;pop ax
|
||||
|
||||
|
||||
; 读取一个扇区
|
||||
mov cl, 1
|
||||
call Func_ReadOneSector
|
||||
pop ax
|
||||
|
||||
; ======逐字节将内核程序复制到临时空间,然后转存到内核空间===
|
||||
push cx
|
||||
push eax
|
||||
push fs
|
||||
push edi
|
||||
push ds
|
||||
push esi
|
||||
|
||||
mov cx, 0x0200 ; 指定计数寄存器的值为512, 为后面循环搬运这个扇区的数据做准备
|
||||
mov ax, Base_Of_Kernel_File
|
||||
mov fs, ax ; 这样在物理机上是行不通的,因为这样移动的话,fs就失去了32位寻址能力
|
||||
mov edi, dword [OffsetOfKernelFileCount] ; 指定目的变址寄存器
|
||||
|
||||
mov ax, Base_Tmp_Of_Kernel_Addr
|
||||
mov ds, ax
|
||||
mov esi, Offset_Tmp_Of_Kernel_File ; 指定来源变址寄存器
|
||||
|
||||
|
||||
|
||||
Label_Move_Kernel:
|
||||
; 真正进行数据的移动
|
||||
mov al, byte [ds:esi] ; 移动到临时区域
|
||||
mov byte [fs:edi], al ; 再移动到目标区域
|
||||
|
||||
inc esi
|
||||
inc edi
|
||||
loop Label_Move_Kernel
|
||||
|
||||
; 当前扇区数据移动完毕
|
||||
mov eax, 0x1000
|
||||
mov ds, eax
|
||||
|
||||
mov dword [OffsetOfKernelFileCount], edi ; 增加偏移量
|
||||
|
||||
pop esi
|
||||
pop ds
|
||||
pop edi
|
||||
pop fs
|
||||
pop eax
|
||||
pop cx
|
||||
|
||||
|
||||
call Func_GetFATEntry
|
||||
|
||||
cmp ax, 0x0fff
|
||||
jz Label_File_Loaded
|
||||
|
||||
|
||||
|
||||
push ax
|
||||
mov dx, RootDirSectors
|
||||
add ax, dx
|
||||
add ax, SectorBalance
|
||||
|
||||
|
||||
|
||||
; 继续读取下一个簇
|
||||
jmp Label_Go_On_Loading_File
|
||||
|
||||
Label_File_Loaded:
|
||||
|
||||
|
||||
;在屏幕上显示 kernel loaded
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0200 ;在第3行显示
|
||||
mov cx, 20 ;设置消息长度
|
||||
|
||||
push ax
|
||||
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Kernel_Loaded
|
||||
int 0x10
|
||||
|
||||
; ======直接操作显示内存=======
|
||||
; 从内存的0x0B800开始,是一段用于显示字符的内存空间。
|
||||
; 每个字符占用2bytes,低字节保存要显示的字符,高字节保存样式
|
||||
mov ax, 0xB800
|
||||
mov gs, ax
|
||||
mov ah, 0x0F ;黑底白字
|
||||
mov al, '.'
|
||||
mov [gs:((80 * 2 + 20) * 2)], ax ;在屏幕第0行,39列
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Label_Kill_Motor:
|
||||
; =====关闭软驱的马达======
|
||||
; 向IO端口0x03f2写入0,关闭所有软驱
|
||||
push dx
|
||||
mov dx, 0x03F2
|
||||
mov al, 0
|
||||
out dx, al
|
||||
pop dx
|
||||
|
||||
; =====获取物理地址空间====
|
||||
|
||||
; 显示 正在获取内存结构
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000F
|
||||
mov dx, 0x0300 ; 在第四行显示
|
||||
mov cx, 34
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Start_Get_Mem_Struct
|
||||
int 0x10
|
||||
|
||||
|
||||
mov ax, 0x00
|
||||
mov es, ax
|
||||
|
||||
mov di, Memory_Struct_Buffer_Addr ; 设置内存结构信息存储的地址
|
||||
mov ebx, 0 ;第一次调用0x15的时候,ebx要置为0 ebx存储的是下一个待返回的ARDS (Address Range Descriptor Structure)
|
||||
|
||||
Label_Get_Mem_Struct:
|
||||
;==== 获取内存物理地址信息
|
||||
; 使用0x15中断程序的功能号0xe820来获取内存信息
|
||||
; 返回信息在[es:di]指向的内存中
|
||||
; 一共要分5次才能把20个字节的信息获取完成
|
||||
; 这些信息在内核初始化内存管理单元的时候,会去解析它们。
|
||||
|
||||
mov eax, 0xe820
|
||||
mov ecx, 20 ; 指定ARDS结构的大小,是固定值20
|
||||
mov edx, 0x534d4150 ; 固定签名标记,是字符串“SMAP”的ASCII码
|
||||
int 0x15
|
||||
|
||||
jc Label_Get_Mem_Fail ; 若调用出错,则CF=1
|
||||
|
||||
add di, 20
|
||||
cmp ebx, 0
|
||||
jne Label_Get_Mem_Struct ; ebx不为0
|
||||
jmp Label_Get_Mem_OK ; 获取内存信息完成
|
||||
|
||||
Label_Get_Mem_Fail:
|
||||
; =====获取内存信息失败====
|
||||
; 显示 正在获取内存结构
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000c
|
||||
mov dx, 0x0400 ; 在第5行显示
|
||||
mov cx, 33
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Get_Mem_Failed
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
|
||||
Label_Get_Mem_OK:
|
||||
; ==== 成功获取内存信息 ===
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0400 ; 在第5行显示
|
||||
mov cx, 38
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Get_Mem_Success
|
||||
int 0x10
|
||||
|
||||
jmp Label_Get_SVGA_Info
|
||||
|
||||
Label_Get_SVGA_Info:
|
||||
; ==== 获取SVGA芯片的信息
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0500 ; 在第6行显示
|
||||
mov cx, 34
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Start_Get_SVGA_VBE_Info
|
||||
int 0x10
|
||||
|
||||
; 使用INT0x10的主功能号0x4F00获取SVGA VBE信息
|
||||
; For more information, please visit: https://longjin666.top/?p=1321
|
||||
mov ax, 0x00
|
||||
mov es, ax
|
||||
mov di, 0x8000
|
||||
mov ax, 0x4F00
|
||||
int 0x10
|
||||
|
||||
cmp ax, 0x004F ; 获取成功
|
||||
jz Label_Get_SVGA_VBE_Success
|
||||
|
||||
Label_Get_SVGA_VBE_Failed:
|
||||
; 获取SVGA VBE信息失败
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x008c
|
||||
mov dx, 0x0600 ; 在第7行显示
|
||||
mov cx, 33
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Get_SVGA_VBE_Failed
|
||||
int 0x10
|
||||
jmp $
|
||||
|
||||
Label_Get_SVGA_VBE_Success:
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0600 ; 在第7行显示
|
||||
mov cx, 38
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Get_SVGA_VBE_Success
|
||||
int 0x10
|
||||
|
||||
Label_Get_SVGA_Mode_Info:
|
||||
; ====== 获取SVGA mode信息 ======
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0700 ; 在第8行显示
|
||||
mov cx, 35
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Start_Get_SVGA_Mode_Info
|
||||
int 0x10
|
||||
|
||||
mov ax, 0x00
|
||||
mov es, ax
|
||||
mov si, 0x800e ; 根据文档可知,偏移量0Eh处, DWORD pointer to list of supported VESA and OEM video modes
|
||||
;(list of words terminated with FFFFh)
|
||||
mov esi, dword [es:si]
|
||||
mov edi, 0x8200
|
||||
|
||||
Label_SVGA_Mode_Info_Get:
|
||||
mov cx, word [es:esi]
|
||||
|
||||
|
||||
; ===========显示SVGA mode的信息
|
||||
;push ax
|
||||
|
||||
;mov ax, 0x00
|
||||
;mov al, ch
|
||||
;call Label_DispAL
|
||||
|
||||
;mov ax, 0x00
|
||||
;mov al, cl
|
||||
;call Label_DispAL
|
||||
|
||||
;pop ax
|
||||
;============
|
||||
|
||||
; 判断是否获取完毕
|
||||
cmp cx, 0xFFFF
|
||||
jz Label_SVGA_Mode_Info_Finish
|
||||
|
||||
mov ax, 0x4f01 ; 使用4f01功能,获取SVGA的模式
|
||||
int 0x10
|
||||
|
||||
cmp ax, 0x004f ; 判断是否获取成功
|
||||
jnz Label_SVGA_Mode_Info_Fail
|
||||
|
||||
add esi, 2
|
||||
add edi, 0x100 ; 开辟一个 256-byte 的 buffer
|
||||
|
||||
jmp Label_SVGA_Mode_Info_Get
|
||||
|
||||
Label_SVGA_Mode_Info_Fail:
|
||||
; === 获取信息失败 ===
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x008c
|
||||
mov dx, 0x0800 ; 在第9行显示
|
||||
mov cx, 34
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Get_SVGA_Mode_Failed
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
|
||||
Label_SVGA_Mode_Info_Finish:
|
||||
; === 成功获取SVGA mode信息 ===
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x000f
|
||||
mov dx, 0x0800 ; 在第9行显示
|
||||
mov cx, 39
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Get_SVGA_Mode_Success
|
||||
int 0x10
|
||||
jmp Label_Set_SVGA_Mode
|
||||
|
||||
Label_SET_SVGA_Mode_VESA_VBE_FAIL:
|
||||
; 设置SVGA显示模式失败
|
||||
mov ax, 0x1301
|
||||
mov bx, 0x008c
|
||||
mov dx, 0x0800 ; 在第10行显示
|
||||
mov cx, 29
|
||||
push ax
|
||||
mov ax, ds
|
||||
mov es, ax
|
||||
pop ax
|
||||
mov bp, Message_Set_SVGA_Mode_Failed
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
|
||||
|
||||
Label_Set_SVGA_Mode:
|
||||
|
||||
; ===== 设置SVGA芯片的显示模式(VESA VBE) ===
|
||||
mov ax, 0x4f02 ; 使用int0x10 功能号AX=4f02设置SVGA芯片的显示模式
|
||||
mov bx, 0x4180 ; 显示模式可以选择0x180(1440*900 32bit)或者0x143(800*600 32bit)
|
||||
int 0x10
|
||||
|
||||
cmp ax, 0x004F
|
||||
jnz Label_SET_SVGA_Mode_VESA_VBE_FAIL
|
||||
|
||||
; ===== 初始化GDT表,切换到保护模式 =====
|
||||
|
||||
cli ; 关闭外部中断
|
||||
db 0x66
|
||||
lgdt [GdtPtr]
|
||||
|
||||
db 0x66
|
||||
lidt [IDT_POINTER]
|
||||
|
||||
mov eax, cr0
|
||||
or eax, 1 ; 启用保护模式
|
||||
or eax, 0x22 ; 启用x87浮点运算单元
|
||||
mov cr0, eax
|
||||
|
||||
; 跳转到保护模式下的第一个程序
|
||||
jmp dword SelectorCode32:GO_TO_TMP_Protect
|
||||
|
||||
|
||||
[SECTION .s32]
|
||||
[BITS 32]
|
||||
GO_TO_TMP_Protect:
|
||||
; ==== 切换到长模式 =====
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov ss, ax
|
||||
mov esp, 0x7e00 ; 将栈指针设置在实模式获取到的数据的基地址上
|
||||
|
||||
call support_long_mode ; 检测是否支持长模式
|
||||
|
||||
test eax, eax ; 将eax自身相与,检测是否为0(test指令不会把结果赋值回去eax)
|
||||
jz no_support ; 不支持长模式
|
||||
|
||||
; 初始化临时页表, 基地址设置为0x90000
|
||||
; 设置各级页表项的值(页表起始地址与页属性组成)
|
||||
mov dword [0x90000], 0x91007
|
||||
mov dword [0x90004], 0x00000
|
||||
mov dword [0x90800], 0x91007
|
||||
mov dword [0x90804], 0x00000
|
||||
|
||||
mov dword [0x91000], 0x92007
|
||||
mov dword [0x91004], 0x00000
|
||||
|
||||
mov dword [0x92000], 0x000083
|
||||
mov dword [0x92004], 0x000000
|
||||
|
||||
mov dword [0x92008], 0x200083
|
||||
mov dword [0x9200c], 0x000000
|
||||
|
||||
mov dword [0x92010], 0x400083
|
||||
mov dword [0x92014], 0x000000
|
||||
|
||||
mov dword [0x92018], 0x600083
|
||||
mov dword [0x9201c], 0x000000
|
||||
|
||||
mov dword [0x92020], 0x800083
|
||||
mov dword [0x92024], 0x000000
|
||||
|
||||
mov dword [0x92028], 0xa00083
|
||||
mov dword [0x9202c], 0x000000
|
||||
|
||||
; === 加载GDT ===
|
||||
db 0x66
|
||||
lgdt [GdtPtr64] ; 加载GDT
|
||||
; 把临时gdt的数据段加载到寄存器中(cs除外)
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
mov esp, 0x7e00
|
||||
|
||||
; ====== 开启物理地址扩展 =====
|
||||
; 通过bts指令,将cr4第5位置位,开启PAE
|
||||
mov eax, cr4
|
||||
bts eax, 5
|
||||
mov cr4, eax
|
||||
|
||||
; 将临时页目录的地址设置到CR3控制寄存器中
|
||||
mov eax, 0x90000
|
||||
mov cr3, eax
|
||||
|
||||
; ==== 启用长模式 ===
|
||||
; 参见英特尔开发手册合集p4360 volume4, chapter2 页码2-60 Vol. 4
|
||||
; IA32_EFER寄存器的第8位是LME标志位,能启用IA-32e模式
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
bts eax, 8
|
||||
wrmsr
|
||||
|
||||
; === 开启分页机制 ===
|
||||
mov eax, cr0
|
||||
bts eax, 0 ; 再次开启保护模式
|
||||
bts eax, 31 ; 开启分页管理机制
|
||||
mov cr0, eax
|
||||
|
||||
;now enable SSE and the like
|
||||
mov eax, cr0
|
||||
and ax, 0xFFFB ;clear coprocessor emulation CR0.EM
|
||||
or ax, 0x2 ;set coprocessor monitoring CR0.MP
|
||||
mov cr0, eax
|
||||
mov eax, cr4
|
||||
or ax, 3 << 9 ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
|
||||
mov cr4, eax
|
||||
|
||||
|
||||
; === 通过此条远跳转指令,处理器跳转到内核文件进行执行,正式进入IA-32e模式
|
||||
|
||||
jmp SelectorCode64:Offset_Of_Kernel_File
|
||||
|
||||
|
||||
support_long_mode:
|
||||
; ===== 检测是否支持长模式 ====
|
||||
mov eax, 0x80000000
|
||||
cpuid ; cpuid指令返回的信息取决于eax的值。当前返回到eax中的是最大的输入参数值。 详见:英特尔开发人员手册卷2A Chapter3 (Page 304)
|
||||
cmp eax, 0x80000001
|
||||
setnb al ; 当cmp结果为不低于时,置位al
|
||||
jb support_long_mode_done ; 当eax小于0x80000001时,跳转
|
||||
|
||||
mov eax, 0x80000001
|
||||
cpuid ; 获取特定信息,参照开发人员手册卷2A p304
|
||||
|
||||
bt edx, 29 ; 将edx第29位的值移到CF上。该位指示了CPU是否支持IA-32e模式
|
||||
; Bit 29: Intel® 64 Architecture available if 1.
|
||||
setc al ; 若支持则al置位
|
||||
|
||||
support_long_mode_done:
|
||||
movzx eax, al ; 将al,零扩展为32位赋值给eax
|
||||
ret
|
||||
|
||||
no_support:
|
||||
; 不支持长模式
|
||||
jmp $
|
||||
|
||||
|
||||
|
||||
[SECTION .s16lib]
|
||||
[BITS 16]
|
||||
; 从软盘读取一个扇区
|
||||
; AX=待读取的磁盘起始扇区号
|
||||
; CL=读入的扇区数量
|
||||
; ES:BX=>目标缓冲区起始地址
|
||||
Func_ReadOneSector:
|
||||
|
||||
push bp
|
||||
mov bp, sp
|
||||
sub esp, 2
|
||||
mov byte [bp-2], cl
|
||||
push bx
|
||||
mov bl, [BPB_SecPerTrk]
|
||||
div bl ;用AX寄存器中的值除以BL,得到目标磁道号(商:AL)以及目标磁道内的起始扇区号(余数:AH)
|
||||
inc ah ; 由于磁道内的起始扇区号从1开始计数,因此将余数+1
|
||||
mov cl, ah
|
||||
mov dh, al
|
||||
shr al, 1 ;计算出柱面号
|
||||
mov ch, al
|
||||
and dh, 1;计算出磁头号
|
||||
|
||||
pop bx
|
||||
mov dl, [BS_DrvNum]
|
||||
;最终,dh存储了磁头号,dl存储驱动器号
|
||||
; ch存储柱面号,cl存储起始扇区号
|
||||
|
||||
Label_Go_On_Reading:
|
||||
; 使用BIOS中断服务程序INT13h的主功能号AH=02h实现软盘读取操作
|
||||
mov ah, 2
|
||||
mov al, byte [bp-2]
|
||||
int 0x13
|
||||
|
||||
jc Label_Go_On_Reading ;当CF标志位被复位时,说明数据读取完成,恢复调用现场
|
||||
|
||||
add esp, 2
|
||||
pop bp
|
||||
|
||||
ret
|
||||
|
||||
|
||||
; 解析FAT表项,根据当前FAT表项索引出下一个FAT表项
|
||||
Func_GetFATEntry:
|
||||
; AX=FAT表项号(输入、输出参数)
|
||||
; 保存将要被修改的寄存器
|
||||
|
||||
|
||||
push es
|
||||
push bx
|
||||
push ax
|
||||
|
||||
; 扩展段寄存器
|
||||
mov ax, 00
|
||||
mov es, ax
|
||||
|
||||
pop ax
|
||||
mov byte [Odd], 0 ;将奇数标志位置0
|
||||
|
||||
; 将FAT表项号转换为总的字节号
|
||||
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 ;把dx置0
|
||||
|
||||
; 计算得到扇区号(商)和扇区内偏移(余数)
|
||||
mov bx, [BPB_BytesPerSec]
|
||||
div bx
|
||||
push dx
|
||||
|
||||
; 读取两个扇区到[es:bx]
|
||||
mov bx, 0x8000
|
||||
add ax, SectorNumOfFAT1Start
|
||||
mov cl, 2 ; 设置读取两个扇区,解决FAT表项跨扇区的问题
|
||||
|
||||
|
||||
|
||||
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, 0x0fff ; 确保表项号在正确的范围内 0x0003~0x0fff
|
||||
pop bx
|
||||
pop es
|
||||
ret
|
||||
|
||||
; ==== 显示AL中的信息 ===
|
||||
Label_DispAL:
|
||||
push ecx
|
||||
push edx
|
||||
push edi
|
||||
|
||||
mov edi, [DisplayPosition]
|
||||
mov ah, 0x0F
|
||||
mov dl, al ; 为了先显示al的高4位,因此先将al暂存在dl中,然后把al往右移动4位
|
||||
shr al, 4
|
||||
mov ecx, 2 ; 计数为2
|
||||
|
||||
.begin:
|
||||
and al, 0x0F
|
||||
cmp al, 9
|
||||
ja .1 ; 大于9,跳转到.1
|
||||
add al, '0'
|
||||
jmp .2
|
||||
.1:
|
||||
sub al, 0x0a
|
||||
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
|
||||
|
||||
; === 临时的中断描述符表 ===
|
||||
; 为临时的IDT开辟空间。
|
||||
; 由于模式切换过程中已经关闭了外部中断,只要确保模式切换过程中不产生异常,就不用完整的初始化IDT。甚至乎,只要没有异常产生,没有IDT也可以。
|
||||
IDT:
|
||||
times 0x50 dq 0
|
||||
IDT_END:
|
||||
|
||||
IDT_POINTER:
|
||||
dw IDT_END - IDT - 1
|
||||
dd IDT
|
||||
|
||||
;==== 临时变量 =====
|
||||
RootDirSizeForLoop dw RootDirSectors
|
||||
SectorNo dw 0
|
||||
Odd db 0
|
||||
OffsetOfKernelFileCount dd Offset_Of_Kernel_File
|
||||
|
||||
DisplayPosition dd 0
|
||||
|
||||
; 要显示的消息文本
|
||||
Message_Start_Loader: db "[DragonOS] Start Loader..."
|
||||
Message_No_Loader: db "[ERROR] No Kernel Found."
|
||||
Message_Kernel_Loaded: db "[INFO] Kernel loaded"
|
||||
Message_Start_Get_Mem_Struct: db "[INFO] Try to get memory struct..."
|
||||
Message_Get_Mem_Failed: db "[ERROR] Get memory struct failed."
|
||||
Message_Get_Mem_Success: db "[INFO] Successfully got memory struct."
|
||||
Message_Start_Get_SVGA_VBE_Info: db "[INFO] Try to get SVGA VBE info..."
|
||||
Message_Get_SVGA_VBE_Failed: db "[ERROR] Get SVGA VBE info failed."
|
||||
Message_Get_SVGA_VBE_Success: db "[INFO] Successfully got SVGA VBE info."
|
||||
Message_Start_Get_SVGA_Mode_Info: db "[INFO] Try to get SVGA mode info..."
|
||||
Message_Get_SVGA_Mode_Failed: db "[ERROR] Get SVGA Mode info failed."
|
||||
Message_Get_SVGA_Mode_Success: db "[INFO] Successfully got SVGA Mode info."
|
||||
Message_Set_SVGA_Mode_Failed: db "[ERROR] Set SVGA Mode failed."
|
||||
|
||||
Kernel_FileName: db "KERNEL BIN", 0
|
@ -7,11 +7,13 @@ DIR_LIB=lib
|
||||
lib_patterns := *.a
|
||||
LIB_FILES := $(foreach DIR,$(DIR_LIB),$(addprefix $(DIR)/,$(lib_patterns)))
|
||||
all: kernel
|
||||
objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary kernel ../bin/kernel/kernel.bin
|
||||
#objcopy -I elf64-x86-64 -S -R ".comment" -O elf64-x86-64 kernel ../bin/kernel/kernel.elf
|
||||
cp kernel ../bin/kernel/kernel.elf
|
||||
|
||||
|
||||
kernel: head.o entry.o main.o printk.o trap.o mm.o irq.o 8259A.o process.o syscall.o
|
||||
ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o exception/8259A.o mm/mm.o process/process.o syscall/syscall.o -T link.lds
|
||||
kernel: head.o entry.o main.o printk.o trap.o mm.o irq.o 8259A.o process.o syscall.o multiboot2.o
|
||||
ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o exception/8259A.o mm/mm.o process/process.o syscall/syscall.o driver/multiboot2/multiboot2.o \
|
||||
-T link.lds
|
||||
|
||||
head.o: head.S
|
||||
gcc -E head.S > head.s # 预处理
|
||||
@ -49,5 +51,8 @@ process.o: process/process.c
|
||||
syscall.o: syscall/syscall.c
|
||||
gcc -mcmodel=large -fno-builtin -m64 -c syscall/syscall.c -o syscall/syscall.o
|
||||
|
||||
multiboot2.o: driver/multiboot2/multiboot2.c
|
||||
gcc -mcmodel=large -fno-builtin -m64 -c driver/multiboot2/multiboot2.c -o driver/multiboot2/multiboot2.o
|
||||
|
||||
clean:
|
||||
rm -rf $(GARBAGE)
|
65
kernel/common/boot_info.h
Normal file
65
kernel/common/boot_info.h
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
/**
|
||||
* @file boot_info.h
|
||||
* @brief 启动信息接口
|
||||
* @author Zone.N (Zone.Niuzh@hotmail.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-18
|
||||
* @copyright MIT LICENSE
|
||||
* https://github.com/Simple-XX/SimpleKernel
|
||||
* @par change log:
|
||||
* <table>
|
||||
* <tr><th>Date<th>Author<th>Description
|
||||
* <tr><td>2021-09-18<td>digmouse233<td>迁移到 doxygen
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef _BOOT_INFO_H_
|
||||
#define _BOOT_INFO_H_
|
||||
|
||||
#include "stdint.h"
|
||||
//#include "resource.h"
|
||||
|
||||
/**
|
||||
* @brief 启动信息接口
|
||||
* 由引导传递的机器信息处理
|
||||
* 如 grub2 传递的 multiboot2 结构
|
||||
* opensbi 传递的 dtb 结构
|
||||
* 注意这部分是通过内存传递的,在重新保存之前不能被覆盖
|
||||
* 架构专有的数据在 dtb.h 或 multiboot2.h
|
||||
* 实现在 dtb.cpp 或 multiboot2.cpp
|
||||
*/
|
||||
namespace BOOT_INFO {
|
||||
/// 声明,定义在具体的实现中
|
||||
/// 地址
|
||||
extern "C" uintptr_t boot_info_addr;
|
||||
/// 长度
|
||||
extern size_t boot_info_size;
|
||||
|
||||
/**
|
||||
* @brief 初始化,定义在具体实现中
|
||||
* @return true 成功
|
||||
* @return false 成功
|
||||
*/
|
||||
extern bool init(void);
|
||||
|
||||
/**
|
||||
* @brief 获取物理内存信息
|
||||
* @return resource_t 物理内存资源信息
|
||||
*/
|
||||
extern resource_t get_memory(void);
|
||||
|
||||
/**
|
||||
* @brief 获取 clint 信息
|
||||
* @return resource_t clint 资源信息
|
||||
*/
|
||||
extern resource_t get_clint(void);
|
||||
|
||||
/**
|
||||
* @brief 获取 plic 信息
|
||||
* @return resource_t plic 资源信息
|
||||
*/
|
||||
extern resource_t get_plic(void);
|
||||
};
|
||||
|
||||
#endif /* _BOOT_INFO_H_ */
|
225
kernel/driver/multiboot2/boot.S
Normal file
225
kernel/driver/multiboot2/boot.S
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
// 以下是来自 multiboot2 规范的定义
|
||||
// How many bytes from the start of the file we search for the header.
|
||||
#define MULTIBOOT_SEARCH 32768
|
||||
#define MULTIBOOT_HEADER_ALIGN 8
|
||||
|
||||
// The magic field should contain this.
|
||||
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||
|
||||
// This should be in %eax.
|
||||
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
|
||||
|
||||
// Alignment of multiboot modules.
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
// Alignment of the multiboot info structure.
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000008
|
||||
|
||||
// Flags set in the 'flags' member of the multiboot header.
|
||||
|
||||
#define MULTIBOOT_TAG_ALIGN 8
|
||||
#define MULTIBOOT_TAG_TYPE_END 0
|
||||
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
|
||||
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
|
||||
#define MULTIBOOT_TAG_TYPE_MODULE 3
|
||||
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
|
||||
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
|
||||
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
||||
#define MULTIBOOT_TAG_TYPE_VBE 7
|
||||
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
|
||||
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
|
||||
#define MULTIBOOT_TAG_TYPE_APM 10
|
||||
#define MULTIBOOT_TAG_TYPE_EFI32 11
|
||||
#define MULTIBOOT_TAG_TYPE_EFI64 12
|
||||
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
|
||||
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
|
||||
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
|
||||
#define MULTIBOOT_TAG_TYPE_NETWORK 16
|
||||
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
|
||||
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
|
||||
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
|
||||
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
|
||||
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
|
||||
|
||||
#define MULTIBOOT_HEADER_TAG_END 0
|
||||
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
||||
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
|
||||
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
|
||||
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
|
||||
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
|
||||
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
|
||||
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
|
||||
|
||||
#define MULTIBOOT_ARCHITECTURE_I386 0
|
||||
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
|
||||
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
|
||||
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||
|
||||
|
||||
// 直接用 -m64 编译出来的是 64 位代码,
|
||||
// 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
|
||||
// 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 编译的代码中
|
||||
// 对于 x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表
|
||||
// See https://wiki.osdev.org/Creating_a_64-bit_kernel:
|
||||
// With a 32-bit bootstrap in your kernel
|
||||
|
||||
// 这部分是从保护模式启动 long 模式的代码
|
||||
// 工作在 32bit
|
||||
// 声明这一段代码以 32 位模式编译
|
||||
.code32
|
||||
|
||||
// multiboot2 文件头
|
||||
// 计算头长度
|
||||
.SET HEADER_LENGTH, multiboot_header_end - multiboot_header
|
||||
// 计算校验和
|
||||
.SET CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + HEADER_LENGTH)
|
||||
// 8 字节对齐
|
||||
.align MULTIBOOT_HEADER_ALIGN
|
||||
// 声明所属段
|
||||
.section .multiboot_header
|
||||
multiboot_header:
|
||||
// 魔数
|
||||
.long MULTIBOOT2_HEADER_MAGIC
|
||||
// 架构
|
||||
.long MULTIBOOT_ARCHITECTURE_I386
|
||||
// 头长度
|
||||
.long HEADER_LENGTH
|
||||
// 校验和
|
||||
.long CHECKSUM
|
||||
// 添加其它内容在此,详细信息见 Multiboot2 Specification version 2.0.pdf
|
||||
.short MULTIBOOT_HEADER_TAG_END
|
||||
// 结束标记
|
||||
.short 0
|
||||
.long 8
|
||||
multiboot_header_end:
|
||||
|
||||
// 临时页表 4KB/页
|
||||
.section .data
|
||||
.align 0x1000
|
||||
pml4:
|
||||
.skip 0x1000
|
||||
pdpt:
|
||||
.skip 0x1000
|
||||
pd:
|
||||
.skip 0x1000
|
||||
pt:
|
||||
.skip 0x1000
|
||||
|
||||
// 临时 GDT
|
||||
.align 16
|
||||
gdt64:
|
||||
null_desc:
|
||||
.short 0xFFFF
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
code_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0x9A
|
||||
.byte 0x20
|
||||
.byte 0
|
||||
data_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0x92
|
||||
.byte 0
|
||||
.byte 0
|
||||
user_code_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0xFA
|
||||
.byte 0x20
|
||||
.byte 0
|
||||
user_data_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0xF2
|
||||
.byte 0
|
||||
.byte 0
|
||||
gdt64_pointer:
|
||||
.short gdt64_pointer-gdt64-1
|
||||
.quad gdt64
|
||||
gdt64_pointer64:
|
||||
.short gdt64_pointer-gdt64-1
|
||||
.quad gdt64
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
# 在 multiboot2.cpp 中定义
|
||||
.extern boot_info_addr
|
||||
.extern multiboot2_magic
|
||||
_start:
|
||||
// 关中断
|
||||
cli
|
||||
// multiboot2_info 结构体指针
|
||||
//mov %ebx, boot_info_addr
|
||||
// 魔数
|
||||
// mov %eax, multiboot2_magic
|
||||
// 从保护模式跳转到长模式
|
||||
// 1. 允许 PAE
|
||||
mov %cr4, %eax
|
||||
or $(1<<5), %eax
|
||||
mov %eax, %cr4
|
||||
// 2. 设置临时页表
|
||||
// 最高级
|
||||
mov $pml4, %eax
|
||||
mov $pdpt, %ebx
|
||||
or $0x3, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
// 次级
|
||||
mov $pdpt, %eax
|
||||
mov $pd, %ebx
|
||||
or $0x3, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
// 次低级
|
||||
mov $pd, %eax
|
||||
mov $pt, %ebx
|
||||
or $0x3, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
// 最低级
|
||||
// 循环 512 次,填满一页
|
||||
mov $512, %ecx
|
||||
mov $pt, %eax
|
||||
mov $0x3, %ebx
|
||||
.fill_pt:
|
||||
mov %ebx, 0(%eax)
|
||||
add $0x1000, %ebx
|
||||
add $8, %eax
|
||||
loop .fill_pt
|
||||
// 填写 CR3
|
||||
mov $pml4, %eax
|
||||
mov %eax, %cr3
|
||||
// 3. 切换到 long 模式
|
||||
mov $0xC0000080, %ecx
|
||||
rdmsr
|
||||
or $(1<<8), %eax
|
||||
wrmsr
|
||||
// 4. 开启分页
|
||||
mov %cr0, %eax
|
||||
or $(1<<31), %eax
|
||||
mov %eax, %cr0
|
||||
// 5. 重新设置 GDT
|
||||
mov $gdt64_pointer, %eax
|
||||
lgdt 0(%eax)
|
||||
// 6. 跳转到 64 位代码执行
|
||||
jmp $0x8, $_start64
|
||||
hlt
|
||||
ret
|
3
kernel/driver/multiboot2/multiboot2.c
Normal file
3
kernel/driver/multiboot2/multiboot2.c
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
int *boot_info_addr;
|
||||
int *multiboot2_magic;
|
104
kernel/driver/multiboot2/multiboot2.cpp
Normal file
104
kernel/driver/multiboot2/multiboot2.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file multiboot2.cpp
|
||||
* @brief multiboot2 解析实现
|
||||
* @author Zone.N (Zone.Niuzh@hotmail.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-18
|
||||
* @copyright MIT LICENSE
|
||||
* https://github.com/Simple-XX/SimpleKernel
|
||||
* @par change log:
|
||||
* <table>
|
||||
* <tr><th>Date<th>Author<th>Description
|
||||
* <tr><td>2021-09-18<td>digmouse233<td>迁移到 doxygen
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "stdio.h"
|
||||
//#include "common.h"
|
||||
#include "multiboot2.h"
|
||||
#include "boot_info.h"
|
||||
//#include "resource.h"
|
||||
//#include "pmm.h"
|
||||
|
||||
/// @todo 优化
|
||||
void MULTIBOOT2::multiboot2_iter(bool (*_fun)(const iter_data_t *, void *),
|
||||
void *_data) {
|
||||
uintptr_t addr = BOOT_INFO::boot_info_addr;
|
||||
// 下一字节开始为 tag 信息
|
||||
iter_data_t *tag = (iter_data_t *)(addr + 8);
|
||||
for (; tag->type != MULTIBOOT_TAG_TYPE_END;
|
||||
tag = (iter_data_t *)((uint8_t *)tag + COMMON::ALIGN(tag->size, 8))) {
|
||||
if (_fun(tag, _data) == true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool MULTIBOOT2::multiboot2_init(void) {
|
||||
uintptr_t addr = BOOT_INFO::boot_info_addr;
|
||||
// 判断魔数是否正确
|
||||
assert(BOOT_INFO::multiboot2_magic == MULTIBOOT2_BOOTLOADER_MAGIC);
|
||||
assert((reinterpret_cast<uintptr_t>(addr) & 7) == 0);
|
||||
// addr+0 保存大小
|
||||
BOOT_INFO::boot_info_size = *(uint32_t *)addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 读取 grub2 传递的物理内存信息,保存到 e820map_t 结构体中
|
||||
// 一般而言是这样的
|
||||
// 地址(长度) 类型
|
||||
// 0x00(0x9F000) 0x1
|
||||
// 0x9F000(0x1000) 0x2
|
||||
// 0xE8000(0x18000) 0x2
|
||||
// 0x100000(0x7EF0000) 0x1
|
||||
// 0x7FF0000(0x10000) 0x3
|
||||
// 0xFFFC0000(0x40000) 0x2
|
||||
bool MULTIBOOT2::get_memory(const iter_data_t *_iter_data, void *_data) {
|
||||
if (_iter_data->type != MULTIBOOT2::MULTIBOOT_TAG_TYPE_MMAP) {
|
||||
return false;
|
||||
}
|
||||
resource_t *resource = (resource_t *)_data;
|
||||
resource->type = resource_t::MEM;
|
||||
resource->name = (char *)"available phy memory";
|
||||
resource->mem.addr = 0x0;
|
||||
resource->mem.len = 0;
|
||||
MULTIBOOT2::multiboot_mmap_entry_t *mmap =
|
||||
((MULTIBOOT2::multiboot_tag_mmap_t *)_iter_data)->entries;
|
||||
for (; (uint8_t *)mmap < (uint8_t *)_iter_data + _iter_data->size;
|
||||
mmap = (MULTIBOOT2::multiboot_mmap_entry_t
|
||||
*)((uint8_t *)mmap +
|
||||
((MULTIBOOT2::multiboot_tag_mmap_t *)_iter_data)
|
||||
->entry_size)) {
|
||||
// 如果是可用内存或地址小于 1M
|
||||
// 这里将 0~1M 的空间全部算为可用,在 c++ 库可用后进行优化
|
||||
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE ||
|
||||
mmap->addr < 1 * COMMON::MB) {
|
||||
// 长度+
|
||||
resource->mem.len += mmap->len;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace BOOT_INFO {
|
||||
// 地址
|
||||
uintptr_t boot_info_addr;
|
||||
// 长度
|
||||
size_t boot_info_size;
|
||||
// 魔数
|
||||
uint32_t multiboot2_magic;
|
||||
|
||||
bool init(void) {
|
||||
auto res = MULTIBOOT2::multiboot2_init();
|
||||
info("BOOT_INFO init.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
resource_t get_memory(void) {
|
||||
resource_t resource;
|
||||
MULTIBOOT2::multiboot2_iter(MULTIBOOT2::get_memory, &resource);
|
||||
return resource;
|
||||
}
|
||||
};
|
334
kernel/driver/multiboot2/multiboot2.h
Normal file
334
kernel/driver/multiboot2/multiboot2.h
Normal file
@ -0,0 +1,334 @@
|
||||
/**
|
||||
* @file multiboot2.h
|
||||
* @brief multiboot2 解析
|
||||
* @author Zone.N (Zone.Niuzh@hotmail.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-18
|
||||
* @copyright MIT LICENSE
|
||||
* https://github.com/Simple-XX/SimpleKernel
|
||||
* @par change log:
|
||||
* <table>
|
||||
* <tr><th>Date<th>Author<th>Description
|
||||
* <tr><td>2021-09-18<td>digmouse233<td>迁移到 doxygen
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef _MULTIBOOT2_H_
|
||||
#define _MULTIBOOT2_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
#include "boot_info.h"
|
||||
|
||||
/// @see Multiboot2 Specification version 2.0.pdf
|
||||
// 启动后,在 32 位内核进入点,机器状态如下:
|
||||
// 1. CS 指向基地址为 0x00000000,限长为4G – 1的代码段描述符。
|
||||
// 2. DS,SS,ES,FS 和 GS 指向基地址为0x00000000,限长为4G –
|
||||
// 1的数据段描述符。
|
||||
// 3. A20 地址线已经打开。
|
||||
// 4. 页机制被禁止。
|
||||
// 5. 中断被禁止。
|
||||
// 6. EAX = 0x2BADB002
|
||||
// 7. 系统信息和启动信息块的线性地址保存在 EBX中(相当于一个指针)。
|
||||
// 以下即为这个信息块的结构
|
||||
|
||||
/**
|
||||
* @brief MULTIBOOT2 接口抽象
|
||||
*/
|
||||
class MULTIBOOT2 {
|
||||
private:
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
static constexpr const uint32_t MULTIBOOT_SEARCH = 32768;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_ALIGN = 8;
|
||||
|
||||
/* The magic field should contain this. */
|
||||
static constexpr const uint32_t MULTIBOOT2_HEADER_MAGIC = 0xe85250d6;
|
||||
|
||||
/* This should be in %eax. */
|
||||
static constexpr const uint32_t MULTIBOOT2_BOOTLOADER_MAGIC = 0x36d76289;
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
static constexpr const uint32_t MULTIBOOT_MOD_ALIGN = 0x00001000;
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
static constexpr const uint32_t MULTIBOOT_INFO_ALIGN = 0x00000008;
|
||||
|
||||
/* Flags set in the 'flags' member of the multiboot header. */
|
||||
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_ALIGN = 8;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_END = 0;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_CMDLINE = 1;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME = 2;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_MODULE = 3;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_BASIC_MEMINFO = 4;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_BOOTDEV = 5;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_MMAP = 6;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_VBE = 7;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_FRAMEBUFFER = 8;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_ELF_SECTIONS = 9;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_APM = 10;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI32 = 11;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI64 = 12;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_SMBIOS = 13;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_ACPI_OLD = 14;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_ACPI_NEW = 15;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_NETWORK = 16;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI_MMAP = 17;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI_BS = 18;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI32_IH = 19;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI64_IH = 20;
|
||||
static constexpr const uint32_t MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR = 21;
|
||||
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_END = 0;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST =
|
||||
1;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ADDRESS = 2;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS = 3;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS = 4;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_FRAMEBUFFER = 5;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_MODULE_ALIGN = 6;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_EFI_BS = 7;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 =
|
||||
8;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 =
|
||||
9;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_RELOCATABLE = 10;
|
||||
|
||||
static constexpr const uint32_t MULTIBOOT_ARCHITECTURE_I386 = 0;
|
||||
static constexpr const uint32_t MULTIBOOT_ARCHITECTURE_MIPS32 = 4;
|
||||
static constexpr const uint32_t MULTIBOOT_HEADER_TAG_OPTIONAL = 1;
|
||||
|
||||
static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_NONE = 0;
|
||||
static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_LOW = 1;
|
||||
static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_HIGH = 2;
|
||||
|
||||
static constexpr const uint32_t MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED =
|
||||
1;
|
||||
static constexpr const uint32_t MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED =
|
||||
2;
|
||||
|
||||
struct multiboot_header_t {
|
||||
// Must be MULTIBOOT_MAGIC - see above.
|
||||
uint32_t magic;
|
||||
// ISA
|
||||
uint32_t architecture;
|
||||
// Total header length.
|
||||
uint32_t header_length;
|
||||
// The above fields plus this one must equal 0 mod 2^32.
|
||||
uint32_t checksum;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_t {
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_information_request_t : multiboot_header_tag_t {
|
||||
uint32_t requests[0];
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_address_t : multiboot_header_tag_t {
|
||||
uint32_t header_addr;
|
||||
uint32_t load_addr;
|
||||
uint32_t load_end_addr;
|
||||
uint32_t bss_end_addr;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_entry_address_t : multiboot_header_tag_t {
|
||||
uint32_t entry_addr;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_console_flags_t : multiboot_header_tag_t {
|
||||
uint32_t console_flags;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_framebuffer_t : multiboot_header_tag_t {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t depth;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_module_align_t : multiboot_header_tag_t {
|
||||
;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_relocatable_t : multiboot_header_tag_t {
|
||||
uint32_t min_addr;
|
||||
uint32_t max_addr;
|
||||
uint32_t align;
|
||||
uint32_t preference;
|
||||
};
|
||||
|
||||
struct multiboot_color_t {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
|
||||
static constexpr const uint32_t MULTIBOOT_MEMORY_AVAILABLE = 1;
|
||||
static constexpr const uint32_t MULTIBOOT_MEMORY_RESERVED = 2;
|
||||
static constexpr const uint32_t MULTIBOOT_MEMORY_ACPI_RECLAIMABLE = 3;
|
||||
static constexpr const uint32_t MULTIBOOT_MEMORY_NVS = 4;
|
||||
static constexpr const uint32_t MULTIBOOT_MEMORY_BADRAM = 5;
|
||||
struct multiboot_mmap_entry_t {
|
||||
uint64_t addr;
|
||||
uint64_t len;
|
||||
uint32_t type;
|
||||
uint32_t zero;
|
||||
};
|
||||
|
||||
struct multiboot_tag_t {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct multiboot_tag_string_t : multiboot_tag_t {
|
||||
char string[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_module_t : multiboot_tag_t {
|
||||
uint32_t mod_start;
|
||||
uint32_t mod_end;
|
||||
char cmdline[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_basic_meminfo_t : multiboot_tag_t {
|
||||
uint32_t mem_lower;
|
||||
uint32_t mem_upper;
|
||||
};
|
||||
|
||||
struct multiboot_tag_bootdev_t : multiboot_tag_t {
|
||||
uint32_t biosdev;
|
||||
uint32_t slice;
|
||||
uint32_t part;
|
||||
};
|
||||
|
||||
struct multiboot_tag_mmap_t : multiboot_tag_t {
|
||||
uint32_t entry_size;
|
||||
uint32_t entry_version;
|
||||
multiboot_mmap_entry_t entries[0];
|
||||
};
|
||||
|
||||
struct multiboot_vbe_info_block_t {
|
||||
uint8_t external_specification[512];
|
||||
};
|
||||
|
||||
struct multiboot_vbe_mode_info_block_t {
|
||||
uint8_t external_specification[256];
|
||||
};
|
||||
|
||||
struct multiboot_tag_vbe_t : multiboot_tag_t {
|
||||
uint16_t vbe_mode;
|
||||
uint16_t vbe_interface_seg;
|
||||
uint16_t vbe_interface_off;
|
||||
uint16_t vbe_interface_len;
|
||||
|
||||
multiboot_vbe_info_block_t vbe_control_info;
|
||||
multiboot_vbe_mode_info_block_t vbe_mode_info;
|
||||
};
|
||||
|
||||
struct multiboot_tag_elf_sections_t : multiboot_tag_t {
|
||||
uint32_t num;
|
||||
uint32_t entsize;
|
||||
// 段字符串表索引
|
||||
uint32_t shndx;
|
||||
char sections[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_apm_t : multiboot_tag_t {
|
||||
uint16_t version;
|
||||
uint16_t cseg;
|
||||
uint32_t offset;
|
||||
uint16_t cseg_16;
|
||||
uint16_t dseg;
|
||||
uint16_t flags;
|
||||
uint16_t cseg_len;
|
||||
uint16_t cseg_16_len;
|
||||
uint16_t dseg_len;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi32_t : multiboot_tag_t {
|
||||
uint32_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi64_t : multiboot_tag_t {
|
||||
uint64_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_smbios_t : multiboot_tag_t {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
uint8_t reserved[6];
|
||||
uint8_t tables[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_old_acpi_t : multiboot_tag_t {
|
||||
uint8_t rsdp[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_new_acpi_t : multiboot_tag_t {
|
||||
uint8_t rsdp[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_network_t : multiboot_tag_t {
|
||||
uint8_t dhcpack[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi_mmap_t : multiboot_tag_t {
|
||||
uint32_t descr_size;
|
||||
uint32_t descr_vers;
|
||||
uint8_t efi_mmap[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi32_ih_t : multiboot_tag_t {
|
||||
uint32_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi64_ih_t : multiboot_tag_t {
|
||||
uint64_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_load_base_addr_t : multiboot_tag_t {
|
||||
uint32_t load_base_addr;
|
||||
};
|
||||
|
||||
// 迭代变量
|
||||
// 与 multiboot_tag_t 相同
|
||||
struct iter_data_t {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief 初始化
|
||||
* @return true 成功
|
||||
* @return false 失败
|
||||
*/
|
||||
static bool multiboot2_init(void);
|
||||
|
||||
/**
|
||||
* @brief 迭代器
|
||||
* @param _fun 迭代操作
|
||||
* @param _data 数据
|
||||
*/
|
||||
static void multiboot2_iter(bool (*_fun)(const iter_data_t *, void *),
|
||||
void *_data);
|
||||
|
||||
/**
|
||||
* @brief 获取内存信息
|
||||
* @param _iter_data 迭代变量
|
||||
* @param _data 数据
|
||||
* @return true 成功
|
||||
* @return false 失败
|
||||
*/
|
||||
static bool get_memory(const iter_data_t *_iter_data, void *_data);
|
||||
};
|
||||
|
||||
namespace BOOT_INFO {
|
||||
/// 魔数
|
||||
extern "C" uint32_t multiboot2_magic;
|
||||
};
|
||||
|
||||
#endif /* _MULTIBOOT2_H_ */
|
275
kernel/head.S
275
kernel/head.S
@ -4,11 +4,247 @@
|
||||
|
||||
#include "common/asm.h"
|
||||
|
||||
|
||||
// 以下是来自 multiboot2 规范的定义
|
||||
// How many bytes from the start of the file we search for the header.
|
||||
#define MULTIBOOT_SEARCH 32768
|
||||
#define MULTIBOOT_HEADER_ALIGN 8
|
||||
|
||||
// The magic field should contain this.
|
||||
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||
|
||||
// This should be in %eax.
|
||||
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
|
||||
|
||||
// Alignment of multiboot modules.
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
// Alignment of the multiboot info structure.
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000008
|
||||
|
||||
// Flags set in the 'flags' member of the multiboot header.
|
||||
|
||||
#define MULTIBOOT_TAG_ALIGN 8
|
||||
#define MULTIBOOT_TAG_TYPE_END 0
|
||||
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
|
||||
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
|
||||
#define MULTIBOOT_TAG_TYPE_MODULE 3
|
||||
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
|
||||
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
|
||||
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
||||
#define MULTIBOOT_TAG_TYPE_VBE 7
|
||||
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
|
||||
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
|
||||
#define MULTIBOOT_TAG_TYPE_APM 10
|
||||
#define MULTIBOOT_TAG_TYPE_EFI32 11
|
||||
#define MULTIBOOT_TAG_TYPE_EFI64 12
|
||||
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
|
||||
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
|
||||
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
|
||||
#define MULTIBOOT_TAG_TYPE_NETWORK 16
|
||||
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
|
||||
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
|
||||
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
|
||||
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
|
||||
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
|
||||
|
||||
#define MULTIBOOT_HEADER_TAG_END 0
|
||||
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
||||
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
|
||||
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
|
||||
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
|
||||
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
|
||||
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
|
||||
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
|
||||
|
||||
#define MULTIBOOT_ARCHITECTURE_I386 0
|
||||
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
|
||||
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
|
||||
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||
|
||||
|
||||
// 直接用 -m64 编译出来的是 64 位代码,
|
||||
// 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
|
||||
// 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 编译的代码中
|
||||
// 对于 x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表
|
||||
// See https://wiki.osdev.org/Creating_a_64-bit_kernel:
|
||||
// With a 32-bit bootstrap in your kernel
|
||||
|
||||
// 这部分是从保护模式启动 long 模式的代码
|
||||
// 工作在 32bit
|
||||
// 声明这一段代码以 32 位模式编译
|
||||
.code32
|
||||
|
||||
// multiboot2 文件头
|
||||
// 计算头长度
|
||||
.SET HEADER_LENGTH, multiboot_header_end - multiboot_header
|
||||
// 计算校验和
|
||||
.SET CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + HEADER_LENGTH)
|
||||
// 8 字节对齐
|
||||
.align MULTIBOOT_HEADER_ALIGN
|
||||
// 声明所属段
|
||||
.section .multiboot_header
|
||||
multiboot_header:
|
||||
// 魔数
|
||||
.long MULTIBOOT2_HEADER_MAGIC
|
||||
// 架构
|
||||
.long MULTIBOOT_ARCHITECTURE_I386
|
||||
// 头长度
|
||||
.long HEADER_LENGTH
|
||||
// 校验和
|
||||
.long CHECKSUM
|
||||
// 添加其它内容在此,详细信息见 Multiboot2 Specification version 2.0.pdf
|
||||
.short MULTIBOOT_HEADER_TAG_END
|
||||
// 结束标记
|
||||
.short 0
|
||||
.long 8
|
||||
multiboot_header_end:
|
||||
|
||||
// 临时页表 4KB/页
|
||||
.section .data
|
||||
.align 0x1000
|
||||
pml4:
|
||||
.skip 0x1000
|
||||
pdpt:
|
||||
.skip 0x1000
|
||||
pd:
|
||||
.skip 0x1000
|
||||
pt:
|
||||
.skip 0x1000
|
||||
|
||||
// 临时 GDT
|
||||
.align 16
|
||||
gdt64:
|
||||
null_desc:
|
||||
.short 0xFFFF
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
code_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0x9A
|
||||
.byte 0x20
|
||||
.byte 0
|
||||
data_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0x92
|
||||
.byte 0
|
||||
.byte 0
|
||||
user_code_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0xFA
|
||||
.byte 0x20
|
||||
.byte 0
|
||||
user_data_desc:
|
||||
.short 0
|
||||
.short 0
|
||||
.byte 0
|
||||
.byte 0xF2
|
||||
.byte 0
|
||||
.byte 0
|
||||
gdt64_pointer:
|
||||
.short gdt64_pointer-gdt64-1
|
||||
.quad gdt64
|
||||
gdt64_pointer64:
|
||||
.short gdt64_pointer-gdt64-1
|
||||
.quad gdt64
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
# 在 multiboot2.cpp 中定义
|
||||
.extern boot_info_addr
|
||||
.extern multiboot2_magic
|
||||
_start:
|
||||
// 关中断
|
||||
cli
|
||||
// multiboot2_info 结构体指针
|
||||
//mov %ebx, boot_info_addr
|
||||
// 魔数
|
||||
//mov %eax, multiboot2_magic
|
||||
/ 从保护模式跳转到长模式
|
||||
// 1. 允许 PAE
|
||||
mov %cr4, %eax
|
||||
or $(1<<5), %eax
|
||||
mov %eax, %cr4
|
||||
// 2. 设置临时页表
|
||||
// 最高级
|
||||
mov $pml4, %eax
|
||||
mov $pdpt, %ebx
|
||||
or $0x3, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
|
||||
// 次级
|
||||
mov $pdpt, %eax
|
||||
mov $pd, %ebx
|
||||
or $0x3, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
|
||||
// 次低级
|
||||
mov $pd, %eax
|
||||
mov $pt, %ebx
|
||||
or $0x3, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
|
||||
// 最低级
|
||||
// 循环 512 次,填满一页
|
||||
mov $512, %ecx
|
||||
mov $pt, %eax
|
||||
mov $0x3, %ebx
|
||||
.fill_pt:
|
||||
mov %ebx, 0(%eax)
|
||||
add $0x1000, %ebx
|
||||
add $8, %eax
|
||||
loop .fill_pt
|
||||
|
||||
// 填写 CR3
|
||||
mov $pml4, %eax
|
||||
mov %eax, %cr3
|
||||
|
||||
// 3. 切换到 long 模式
|
||||
mov $0xC0000080, %ecx
|
||||
rdmsr
|
||||
or $(1<<8), %eax
|
||||
wrmsr
|
||||
|
||||
// 4. 开启分页
|
||||
mov %cr0, %eax
|
||||
or $(1<<31), %eax
|
||||
mov %eax, %cr0
|
||||
|
||||
// 5. 重新设置 GDT
|
||||
mov $gdt64_pointer, %eax
|
||||
lgdt 0(%eax)
|
||||
|
||||
// 6. 跳转到 64 位代码执行
|
||||
jmp $0x8, $_start64
|
||||
hlt
|
||||
ret
|
||||
|
||||
.section .text
|
||||
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
.code64
|
||||
.global _start64
|
||||
.type _start64, @function
|
||||
.extern Start_Kernel
|
||||
ENTRY(_start64)
|
||||
// 初始化寄存器
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ds
|
||||
@ -28,14 +264,26 @@ _start:
|
||||
mov %ax, %fs
|
||||
mov %ax, %ss
|
||||
mov %ax, %gs
|
||||
|
||||
|
||||
movq $0x7e00, %rsp
|
||||
|
||||
// 2. 设置临时页表
|
||||
// 最高级
|
||||
mov $__PML4E, %eax
|
||||
mov $__PDPTE, %ebx
|
||||
or $0x7, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
|
||||
// 次级
|
||||
mov $__PDPTE, %eax
|
||||
mov $__PDE, %ebx
|
||||
or $0x7, %ebx
|
||||
mov %ebx, 0(%eax)
|
||||
// ==== 加载CR3寄存器
|
||||
movq $0x101000, %rax //设置页目录基地址
|
||||
movq $__PML4E, %rax //设置页目录基地址
|
||||
movq %rax, %cr3
|
||||
movq switch_seg(%rip), %rax
|
||||
|
||||
movq switch_seg(%rip), %rax
|
||||
// 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
|
||||
// 实在是太妙了!Amazing!
|
||||
pushq $0x08 //段选择子
|
||||
@ -44,9 +292,11 @@ _start:
|
||||
|
||||
// 64位模式的代码
|
||||
switch_seg:
|
||||
|
||||
.quad entry64
|
||||
|
||||
entry64:
|
||||
|
||||
movq $0x10, %rax
|
||||
movq %rax, %ds
|
||||
movq %rax, %es
|
||||
@ -119,11 +369,8 @@ SetUp_TSS64:
|
||||
// mov $0x50, %ax // 设置起始地址为80
|
||||
// ltr %ax
|
||||
|
||||
// 切换到内核主程序
|
||||
movq go_to_kernel(%rip), %rax
|
||||
pushq $0x08
|
||||
pushq %rax
|
||||
lretq
|
||||
|
||||
call Start_Kernel
|
||||
|
||||
go_to_kernel:
|
||||
.quad Start_Kernel
|
||||
@ -148,13 +395,14 @@ ENTRY(_stack_start)
|
||||
|
||||
|
||||
// 初始化页表
|
||||
.align 8 //设置为8byte对齐
|
||||
|
||||
.align 0x1000 //设置为8byte对齐
|
||||
.org 0x1000 //设置页表位置为内核执行头程序的0x1000处
|
||||
|
||||
__PML4E:
|
||||
.quad 0x102007 // 用户访问,可读写,已存在, 地址在31~12位
|
||||
.fill 255,8,0
|
||||
.quad 0x102007
|
||||
.quad 0x102007
|
||||
.fill 255,8,0
|
||||
|
||||
.org 0x2000
|
||||
@ -185,6 +433,7 @@ __PDE:
|
||||
|
||||
// GDT表
|
||||
.section .data
|
||||
.align 16
|
||||
.global GDT_Table // 使得GDT可以被外部程序引用或者访问
|
||||
|
||||
GDT_Table:
|
||||
|
@ -5,10 +5,14 @@ ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
. = 0xffff800000000000 + 0x100000;
|
||||
. = 0;
|
||||
|
||||
|
||||
. = 1M;
|
||||
.text :
|
||||
{
|
||||
_text = .;
|
||||
*(.multiboot_header)
|
||||
*(.text)
|
||||
|
||||
_etext = .;
|
||||
@ -19,6 +23,7 @@ SECTIONS
|
||||
_data = .;
|
||||
*(.data)
|
||||
|
||||
*(.eh_frame)
|
||||
_edata = .;
|
||||
}
|
||||
.rodata :
|
||||
|
@ -13,10 +13,10 @@
|
||||
#include "syscall/syscall.h"
|
||||
|
||||
unsigned int *FR_address = (unsigned int *)0xffff800000a00000; //帧缓存区的地址
|
||||
// char fxsave_region[512] __attribute__((aligned(16)));
|
||||
// char fxsave_region[512] __attribute__((aligned(16)));
|
||||
|
||||
struct memory_desc memory_management_struct = {{0}, 0};
|
||||
//struct Global_Memory_Descriptor memory_management_struct = {{0}, 0};
|
||||
struct memory_desc memory_management_struct = {{0}, 0};
|
||||
// struct Global_Memory_Descriptor memory_management_struct = {{0}, 0};
|
||||
|
||||
void show_welcome()
|
||||
{
|
||||
@ -37,7 +37,6 @@ void show_welcome()
|
||||
printk_color(0x00e0ebeb, 0x00e0ebeb, " \n\n");
|
||||
}
|
||||
|
||||
|
||||
// 测试内存管理单元
|
||||
/*
|
||||
void test_mm()
|
||||
@ -63,18 +62,16 @@ void test_mm()
|
||||
// 初始化系统各模块
|
||||
void system_initialize()
|
||||
{
|
||||
// 初始化printk
|
||||
init_printk(1440, 900, FR_address, 1440 * 900 * 4, 8, 16);
|
||||
|
||||
// 初始化printk
|
||||
init_printk(1024, 768, FR_address, 1024 * 768 * 4, 8, 16);
|
||||
printk("11111\n");
|
||||
load_TR(10); // 加载TR寄存器
|
||||
|
||||
while(1);
|
||||
// 初始化任务状态段表
|
||||
ul tss_item_addr = 0xffff800000007c00;
|
||||
|
||||
|
||||
set_TSS64(_stack_start, _stack_start, _stack_start, tss_item_addr, tss_item_addr,
|
||||
tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr);
|
||||
|
||||
|
||||
|
||||
// 初始化中断描述符表
|
||||
init_sys_vector();
|
||||
@ -96,12 +93,10 @@ void Start_Kernel(void)
|
||||
{
|
||||
|
||||
system_initialize();
|
||||
|
||||
|
||||
// show_welcome();
|
||||
// test_mm();
|
||||
|
||||
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
@ -264,6 +264,8 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
|
||||
thd->rbp = (ul)tsk + STACK_SIZE;
|
||||
thd->rip = regs->rip;
|
||||
thd->rsp = (ul)tsk + STACK_SIZE - sizeof(struct pt_regs);
|
||||
thd->fs = KERNEL_DS;
|
||||
thd->gs = KERNEL_DS;
|
||||
|
||||
// 若进程不是内核层的进程,则跳转到ret from system call
|
||||
if (!(tsk->flags & PF_KTHREAD))
|
||||
|
100
run.sh
Normal file
100
run.sh
Normal file
@ -0,0 +1,100 @@
|
||||
# ======检查是否以sudo运行=================
|
||||
#uid=`id -u`
|
||||
#if [ ! $uid == "0" ];then
|
||||
# echo "请以sudo权限运行"
|
||||
# exit
|
||||
#fi
|
||||
|
||||
# 第一个参数如果是--notbuild 那就不构建,直接运行
|
||||
if [ ! "$1" == "--nobuild" ]; then
|
||||
echo "开始构建..."
|
||||
make all -j 16
|
||||
make clean
|
||||
fi
|
||||
|
||||
IA32_USE_QEMU=1
|
||||
bochsrc="./bochsrc"
|
||||
ARCH="x86_64"
|
||||
|
||||
# 内核映像
|
||||
kernel='./bin/kernel/kernel.elf'
|
||||
iso_boot_grub='./iso/boot/grub'
|
||||
iso_boot='./iso/boot/'
|
||||
iso='./DragonOS.iso'
|
||||
iso_folder='./iso/'
|
||||
|
||||
|
||||
# toolchain
|
||||
OS=`uname -s`
|
||||
if [ "${OS}" == "Linux" ]; then
|
||||
GRUB_PATH="$(dirname $(which grub-file))"
|
||||
elif [ "${OS}" == "Darwin" ]; then
|
||||
GRUB_PATH="$(pwd)/tools/grub-2.04/build/grub/bin"
|
||||
fi
|
||||
export PATH="${GRUB_PATH}:$PATH"
|
||||
|
||||
# ==============检查文件是否齐全================
|
||||
|
||||
|
||||
bins[0]=${kernel}
|
||||
|
||||
for file in ${bins[*]};do
|
||||
if [ ! -x $file ]; then
|
||||
echo "$file 不存在!"
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
# ===============文件检查完毕===================
|
||||
|
||||
# 如果是 i386/x86_64,需要判断是否符合 multiboot2 标准
|
||||
if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then
|
||||
if ${GRUB_PATH}/grub-file --is-x86-multiboot2 ${kernel}; then
|
||||
echo Multiboot2 Confirmed!
|
||||
else
|
||||
echo NOT Multiboot2!
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
# 检测路径是否合法,发生过 rm -rf -f /* 的惨剧
|
||||
if [ "${iso_boot}" == "" ]; then
|
||||
echo iso_boot path error.
|
||||
else
|
||||
mkdir -p ${iso_boot}
|
||||
rm -rf -f ${iso_boot}/*
|
||||
fi
|
||||
|
||||
# 设置 grub 相关数据
|
||||
if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then
|
||||
cp ${kernel} ${iso_boot}
|
||||
mkdir ${iso_boot_grub}
|
||||
touch ${iso_boot_grub}/grub.cfg
|
||||
echo 'set timeout=15
|
||||
set default=0
|
||||
menuentry "DragonOS" {
|
||||
multiboot2 /boot/kernel.elf "KERNEL_ELF"
|
||||
}' >${iso_boot_grub}/grub.cfg
|
||||
fi
|
||||
|
||||
${GRUB_PATH}/grub-mkrescue -o ${iso} ${iso_folder}
|
||||
rm -rf ${iso_folder}
|
||||
# 进行启动前检查
|
||||
flag_can_run=0
|
||||
|
||||
if [ -d "${iso_folder}" ]; then
|
||||
flag_can_run=0
|
||||
echo "${iso_folder} 文件夹未删除!"
|
||||
else
|
||||
flag_can_run=1
|
||||
fi
|
||||
|
||||
if [ $flag_can_run -eq 1 ]; then
|
||||
if [ ${IA32_USE_QEMU} == 0 ]; then
|
||||
bochs -q -f ${bochsrc} -rc ./tools/bochsinit
|
||||
else
|
||||
qemu-system-x86_64 -cdrom ${iso} -m 128M \
|
||||
-monitor telnet::2333,server,nowait -serial stdio
|
||||
fi
|
||||
else
|
||||
echo "不满足运行条件"
|
||||
fi
|
@ -1,80 +0,0 @@
|
||||
# ======检查是否以sudo运行=================
|
||||
uid=`id -u`
|
||||
if [ ! $uid == "0" ];then
|
||||
echo "请以sudo权限运行"
|
||||
exit
|
||||
fi
|
||||
|
||||
# 第一个参数如果是--notbuild 那就不构建,直接运行
|
||||
if [ ! "$1" == "--nobuild" ]; then
|
||||
echo "开始构建..."
|
||||
make all -j 16
|
||||
make clean
|
||||
fi
|
||||
|
||||
# ==============检查文件是否齐全================
|
||||
|
||||
bins[0]=bin/bootloader/boot.bin
|
||||
bins[1]=bin/bootloader/loader.bin
|
||||
bins[2]=bin/boot.img
|
||||
bins[3]=bin/kernel/kernel.bin
|
||||
|
||||
for file in ${bins[*]};do
|
||||
if [ ! -x $file ]; then
|
||||
echo "$file 不存在!"
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
# ===============文件检查完毕===================
|
||||
|
||||
|
||||
# =========将引导程序写入boot.img=============
|
||||
dd if=bin/bootloader/boot.bin of=bin/boot.img bs=512 count=1 conv=notrunc
|
||||
|
||||
# =========创建临时文件夹==================
|
||||
# 判断临时文件夹是否存在,若不存在则创建新的
|
||||
if [ ! -d "tmp/" ]; then
|
||||
mkdir tmp/
|
||||
echo "创建了tmp文件夹"
|
||||
fi
|
||||
|
||||
# ==============挂载boot.img=============
|
||||
mkdir tmp/boot
|
||||
mount bin/boot.img tmp/boot -t vfat -o loop
|
||||
|
||||
# 检查是否挂载成功
|
||||
if mountpoint -q tmp/boot
|
||||
then
|
||||
echo "成功挂载 boot.img 到 tmp/boot"
|
||||
# ========把loader.bin复制到boot.img==========
|
||||
cp bin/bootloader/loader.bin tmp/boot
|
||||
# ========把内核程序复制到boot.img======
|
||||
cp bin/kernel/kernel.bin tmp/boot
|
||||
sync
|
||||
# 卸载磁盘
|
||||
umount tmp/boot
|
||||
else
|
||||
echo "挂载 boot.img 失败!"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# 运行结束后删除tmp文件夹
|
||||
rm -rf tmp
|
||||
|
||||
# 进行启动前检查
|
||||
flag_can_run=0
|
||||
|
||||
if [ -d "tmp/" ]; then
|
||||
flag_can_run=0
|
||||
echo "tmp文件夹未删除!"
|
||||
else
|
||||
flag_can_run=1
|
||||
fi
|
||||
|
||||
if [ $flag_can_run -eq 1 ]; then
|
||||
bochs -f ./bochsrc -q
|
||||
else
|
||||
echo "不满足运行条件"
|
||||
fi
|
@ -1,78 +0,0 @@
|
||||
# ======检查是否以sudo运行=================
|
||||
uid=`id -u`
|
||||
if [ ! $uid == "0" ];then
|
||||
echo "请以sudo权限运行"
|
||||
exit
|
||||
fi
|
||||
|
||||
# 第一个参数如果是--notbuild 那就不构建,直接运行
|
||||
if [ ! "$1" == "--nobuild" ]; then
|
||||
echo "开始构建..."
|
||||
make all
|
||||
make clean
|
||||
fi
|
||||
|
||||
# ==============检查文件是否齐全================
|
||||
bins[0]=bin/bootloader/boot.bin
|
||||
bins[1]=bin/bootloader/loader.bin
|
||||
bins[2]=bin/boot.img
|
||||
bins[3]=bin/kernel/kernel.bin
|
||||
|
||||
for file in ${bins[*]};do
|
||||
if [ ! -x $file ]; then
|
||||
echo "$file 不存在!"
|
||||
exit
|
||||
fi
|
||||
done
|
||||
# ===============文件检查完毕===================
|
||||
|
||||
|
||||
# =========将引导程序写入boot.img=============
|
||||
dd if=bin/bootloader/boot.bin of=bin/boot.img bs=512 count=1 conv=notrunc
|
||||
|
||||
# =========创建临时文件夹==================
|
||||
# 判断临时文件夹是否存在,若不存在则创建新的
|
||||
if [ ! -d "tmp/" ]; then
|
||||
mkdir tmp/
|
||||
echo "创建了tmp文件夹"
|
||||
fi
|
||||
|
||||
# ==============挂载boot.img=============
|
||||
mkdir tmp/boot
|
||||
mount bin/boot.img tmp/boot -t vfat -o loop
|
||||
|
||||
# 检查是否挂载成功
|
||||
if mountpoint -q tmp/boot
|
||||
then
|
||||
echo "成功挂载 boot.img 到 tmp/boot"
|
||||
# ========把loader.bin复制到boot.img==========
|
||||
cp bin/bootloader/loader.bin tmp/boot
|
||||
# ========把内核程序复制到boot.img======
|
||||
cp bin/kernel/kernel.bin tmp/boot
|
||||
sync
|
||||
# 卸载磁盘
|
||||
umount tmp/boot
|
||||
else
|
||||
echo "挂载 boot.img 失败!"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# 运行结束后删除tmp文件夹
|
||||
rm -rf tmp
|
||||
|
||||
# 进行启动前检查
|
||||
flag_can_run=0
|
||||
|
||||
if [ -d "tmp/" ]; then
|
||||
flag_can_run=0
|
||||
echo "tmp文件夹未删除!"
|
||||
else
|
||||
flag_can_run=1
|
||||
fi
|
||||
|
||||
if [ $flag_can_run -eq 1 ]; then
|
||||
qemu-system-x86_64 -s -S -m 2048 -fda bin/boot.img
|
||||
else
|
||||
echo "不满足运行条件"
|
||||
fi
|
Loading…
x
Reference in New Issue
Block a user