فهرست منبع

:new: 完成了内核执行头程序(编译仍有问题)

fslongjin 3 سال پیش
والد
کامیت
24a0a78d15
6فایلهای تغییر یافته به همراه191 افزوده شده و 3 حذف شده
  1. 18 1
      CMakeLists.txt
  2. 1 1
      bootloader/loader.asm
  3. 18 0
      kernel/CMakeLists.txt
  4. 142 0
      kernel/head.S
  5. 11 0
      kernel/main.c
  6. 1 1
      run_in_qemu.sh

+ 18 - 1
CMakeLists.txt

@@ -1,6 +1,23 @@
 cmake_minimum_required(VERSION 3.20)
-project(dragonOS C)
+set(CMAKE_VERBOSE_MAKEFILE on)
+
+set(DRAGONOS_ARCH "x86_64")
+
+mark_as_advanced(CMAKE_INSTALL_PREFIX)
+
+set(CROSS_COMPILE "${DRAGONOS_ARCH}-linux-gnu-")
+set(CMAKE_C_COMPILER "${CROSS_COMPILE}gcc")
+set(CMAKE_ASM_COMPILER "${CROSS_COMPILE}gcc")
+enable_language(ASM ASM_NASM)
+
+set(CMAKE_C_FLAGS
+        "-Wall -fPIC -nostdlib -nostartfiles -ffreestanding ")
+
+
+project(dragonOS C ASM)
 
 set(CMAKE_C_STANDARD 11)
 add_subdirectory(bootloader)
+add_subdirectory(kernel)
+include_directories(kernel)
 

+ 1 - 1
bootloader/loader.asm

@@ -619,7 +619,7 @@ GO_TO_TMP_Protect:
     mov cr3, eax
 
     ; ==== 启用长模式 ===
-    ; 参见英特尔开发手册合集p4360 volume4, chapter2  2-60 Vol. 4
+    ; 参见英特尔开发手册合集p4360 volume4, chapter2  页码2-60 Vol. 4
     ; IA32_EFER寄存器的第8位是LME标志位,能启用IA-32e模式
     mov ecx, 0xC0000080
     rdmsr

+ 18 - 0
kernel/CMakeLists.txt

@@ -0,0 +1,18 @@
+
+
+#修改输出的路径
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/kernel)
+# 添加汇编包含目录(当前文件夹)
+add_compile_options(-I ${CMAKE_CURRENT_SOURCE_DIR}/ )
+
+add_library(${PROJECT_NAME}-arch
+        head.S
+        main.c)
+add_executable(kernel.bin
+        head.S main.c)
+set_property(
+        TARGET kernel.bin
+        PROPERTY
+        DEPENDS
+        "link.lds"
+)

+ 142 - 0
kernel/head.S

@@ -0,0 +1,142 @@
+// 这是内核执行头程序
+// Created by longjin.
+// 2022/01/20
+
+.section .text
+
+.global _start
+
+_start:
+    // 初始化寄存器
+    mov $0x10, %ax
+    mov %ax, %ds
+    mov %ax, %es
+    mov %ax, %fs
+    mov %ax, %ss
+
+    mov $0x7e00, %esp
+
+// === 加载GDTR ====
+    lgdt GDT_POINTER(%rip) //这里我没搞明白rip相对寻址, 看了文档,大概是用来实现PIC的(position independent code)
+// === 加载IDTR ====
+    lidt IDT_POINTER(%rip)
+    mov $0x10, %ax
+    mov %ax, %ds
+    mov %ax, %es
+    mov %ax, %fs
+    mov %ax, %ss
+    mov %ax, %gs
+
+    movq $0x7e00, %rsp
+
+// ==== 加载CR3寄存器
+    movq $0x101000, %rax //设置页目录基地址
+    movq %rax, %cr3
+    movq switch_seg(%rip), %rax
+
+    // 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
+    // 实在是太妙了!Amazing!
+    pushq $0x08 //段选择子
+    pushq %rax
+    lretq
+
+// 64位模式的代码
+switch_seg:
+    .quad entry64
+
+entry64:
+    movq $0x10, %rax
+    movq %rax, %ds
+    movq %rax, %es
+    movq %rax, %gs
+    movq %rax, %ss
+
+    movq $0xffff800000007e00, %rsp //rsp的地址
+
+    // 切换到内核主程序
+    movq go_to_kernel(%rip), %rax
+    pushq $0x08
+    pushq %rax
+    lretq
+
+go_to_kernel:
+    .quad Start_Kernel
+
+
+
+// 初始化页表
+.align 8 //设置为8byte对齐
+.org 0x1000 //设置页表位置为内核执行头程序的0x1000处
+
+__PML4E:
+    .quad 0x102007 // 系统访问,可读写,已存在, 地址在31~12位
+    .fill	255,8,0
+	.quad	0x102007
+	.fill	255,8,0
+
+.org	0x2000
+
+__PDPTE:
+
+	.quad	0x103003 // 用户访问,可读写,已存在
+	.fill	511,8,0
+
+.org	0x3000
+
+__PDE:
+
+	.quad	0x000083    // 用户访问,可读写,已存在
+	.quad	0x200083
+	.quad	0x400083
+	.quad	0x600083
+	.quad	0x800083
+	.quad	0xe0000083		/*0x a00000*/
+	.quad	0xe0200083
+	.quad	0xe0400083
+	.quad	0xe0600083		/*0x1000000*/
+	.quad	0xe0800083
+	.quad	0xe0a00083
+	.quad	0xe0c00083
+	.quad	0xe0e00083
+	.fill	499,8,0
+
+// GDT表
+.section .data
+.global GDT_Table // 使得GDT可以被外部程序引用或者访问
+
+GDT_Table:
+    .quad 0x0000000000000000 // 0 空描述符 00
+    .quad 0x0020980000000000 // 1 内核64位代码段描述符 08
+    .quad 0x0000920000000000 // 2 内核64位数据段描述符 10
+    .quad 0x0020f80000000000 // 3 用户64位代码段描述符 18
+    .quad 0x0000f20000000000 // 4 用户64位数据段描述符 20
+    .quad 0x00cf9a000000ffff // 5 内核32位代码段描述符 28
+    .quad 0x00cf92000000ffff // 6 内核32位数据段描述符 30
+    .fill 10, 8, 0           // 8~9 TSS(跳过了第七段)  重复十次填充8字节的空间,赋值为0
+GDT_END:
+
+GDT_POINTER:
+GDT_LIMIT: .word GDT_END - GDT_Table - 1 // GDT的大小
+GDT_BASE: .quad GDT_Table
+
+// IDT 表
+.global IDT_Table
+
+IDT_Table:
+    .fill 512, 8, 0 // 设置512*8字节的IDT表的空间
+IDT_END:
+
+IDT_POINTER:
+IDT_LIMIT: .word IDT_END - IDT_Table - 1
+IDT_BASE: .quad IDT_Table
+
+// 64位的TSS表
+.global TSS64_Table
+
+TSS64_Table:
+    .fill 13, 8, 0
+TSS64_END:
+
+TSS64_POINTER:
+TSS64_LIMIT: .word TSS64_END - TSS64_Table - 1
+TSS64_BASE: .quad TSS64_Table

+ 11 - 0
kernel/main.c

@@ -0,0 +1,11 @@
+//
+// Created by longjin on 2022/1/20.
+//
+
+void Start_Kernel(void)
+{
+    while(1)
+    {
+
+    };
+}

+ 1 - 1
run_in_qemu.sh

@@ -43,7 +43,7 @@ fi
       # ========把loader.bin复制到boot.img==========
       cp bin/bootloader/loader.bin tmp/boot
       # ========把内核程序复制到boot.img======
-      cp bin/bootloader/kernel.bin tmp/boot
+      cp bin/kernel/kernel.bin tmp/boot
       sync
       # 卸载磁盘
       umount tmp/boot