diff --git a/.gitignore b/.gitignore
index 27aa8727..14ce310d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/cmake-build-debug/
/bin/
+./DragonOS.iso
\ No newline at end of file
diff --git a/Makefile b/Makefile
index e5035b39..cdaa5dd5 100644
--- a/Makefile
+++ b/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;\
diff --git a/bochsrc b/bochsrc
index b2ac6e94..fd300488 100644
--- a/bochsrc
+++ b/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
diff --git a/boot(empty).img b/boot(empty).img
deleted file mode 100644
index 3525e064..00000000
Binary files a/boot(empty).img and /dev/null differ
diff --git a/bootloader/Makefile b/bootloader/Makefile
deleted file mode 100644
index e58c32f0..00000000
--- a/bootloader/Makefile
+++ /dev/null
@@ -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~
diff --git a/bootloader/boot.asm b/bootloader/boot.asm
deleted file mode 100644
index f0f9722e..00000000
--- a/bootloader/boot.asm
+++ /dev/null
@@ -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为结尾
-
diff --git a/bootloader/fat12.inc b/bootloader/fat12.inc
deleted file mode 100644
index 104a757e..00000000
--- a/bootloader/fat12.inc
+++ /dev/null
@@ -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 '
\ No newline at end of file
diff --git a/bootloader/loader.asm b/bootloader/loader.asm
deleted file mode 100644
index 3d96e89e..00000000
--- a/bootloader/loader.asm
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/kernel/Makefile b/kernel/Makefile
index 61f9001e..f0cfda68 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -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)
\ No newline at end of file
diff --git a/kernel/common/boot_info.h b/kernel/common/boot_info.h
new file mode 100644
index 00000000..8e854fab
--- /dev/null
+++ b/kernel/common/boot_info.h
@@ -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:
+ *
+ * Date | Author | Description
+ * |
---|
2021-09-18 | digmouse233 | 迁移到 doxygen
+ * |
+ */
+
+#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_ */
\ No newline at end of file
diff --git a/kernel/driver/multiboot2/boot.S b/kernel/driver/multiboot2/boot.S
new file mode 100644
index 00000000..7941984d
--- /dev/null
+++ b/kernel/driver/multiboot2/boot.S
@@ -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
diff --git a/kernel/driver/multiboot2/multiboot2.c b/kernel/driver/multiboot2/multiboot2.c
new file mode 100644
index 00000000..2e1bb0f5
--- /dev/null
+++ b/kernel/driver/multiboot2/multiboot2.c
@@ -0,0 +1,3 @@
+
+int *boot_info_addr;
+int *multiboot2_magic;
\ No newline at end of file
diff --git a/kernel/driver/multiboot2/multiboot2.cpp b/kernel/driver/multiboot2/multiboot2.cpp
new file mode 100644
index 00000000..b92dcfed
--- /dev/null
+++ b/kernel/driver/multiboot2/multiboot2.cpp
@@ -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:
+ *
+ * Date | Author | Description
+ * |
---|
2021-09-18 | digmouse233 | 迁移到 doxygen
+ * |
+ */
+
+#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(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;
+ }
+};
\ No newline at end of file
diff --git a/kernel/driver/multiboot2/multiboot2.h b/kernel/driver/multiboot2/multiboot2.h
new file mode 100644
index 00000000..02386184
--- /dev/null
+++ b/kernel/driver/multiboot2/multiboot2.h
@@ -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:
+ *
+ * Date | Author | Description
+ * |
---|
2021-09-18 | digmouse233 | 迁移到 doxygen
+ * |
+ */
+
+#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_ */
\ No newline at end of file
diff --git a/kernel/head.S b/kernel/head.S
index f6d2f84e..b1f4af66 100644
--- a/kernel/head.S
+++ b/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:
diff --git a/kernel/link.lds b/kernel/link.lds
index 8961dbe9..b4897f60 100644
--- a/kernel/link.lds
+++ b/kernel/link.lds
@@ -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 :
diff --git a/kernel/main.c b/kernel/main.c
index c37643a6..102ca4b9 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -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)
;
}
diff --git a/kernel/process/process.c b/kernel/process/process.c
index 265cb268..f8bb6670 100644
--- a/kernel/process/process.c
+++ b/kernel/process/process.c
@@ -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))
diff --git a/run.sh b/run.sh
new file mode 100644
index 00000000..2ffd8605
--- /dev/null
+++ b/run.sh
@@ -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
\ No newline at end of file
diff --git a/run_in_bochs.sh b/run_in_bochs.sh
deleted file mode 100644
index 16342f49..00000000
--- a/run_in_bochs.sh
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/run_in_qemu.sh b/run_in_qemu.sh
deleted file mode 100644
index 6b2f1ef7..00000000
--- a/run_in_qemu.sh
+++ /dev/null
@@ -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
\ No newline at end of file