前言
- 在了解段页门得基础上,理解如何从实时模式进入保护模式
- 如何引入C语言得开发与调试
- 生成内核:汇编与C语言如何生成内核
- 调试C语言
- 汇编、C语言如何互调
手写64位操作系统内核规划图:
boot程序起始0扇区,共占1个扇区 setup程序起始1扇区,共占一个扇区2个扇区 x86内核起始 3扇区,共占一个扇区大于30个扇区
1、从实时模式进入保护模式
- 关中断
cli:是一个汇编指令,用于清除(禁用)中断标志位(IF位)在eflags寄存器中。当IF位被清除时,处理器将不响应可屏蔽的硬件中断,这常用于临界区代码,以避免在执行关键任务时被中断。 sti:用于设置(启用)中断标志位在eflags寄存器中。执行sti后,处理器将开始响应可屏蔽的硬件中断。这通常用于完成关键任务后重新启用中断。 eflags.IF:一个寄存器,其中的IF(Interrupt Flag)是eflags中的一个位,用于控制处理器是否响应可屏蔽的硬件中断。cli和sti指令分别用于清除和设置这个标志位。
- 开A20总线
考虑为什么要开A20? ; 开A20 in al, 92h or al, 00000010b out 92h, al
- 设置段寄存器、加载gdt表
内核态 代码段、数据段 2 ----------------------------- x64长模式 4 tss 用户态切内核态 8个 ------------------------------ 调用门
- cr0寄存器,cr0.pe = 1
cr0 : pe位(进入保护模式)、pg(开启分页) cr1: cr2: 内存异常 4G 0x10000000 页机制 cr3: 页表的基址
- 来一个练习:32位,0-4g,代码段
Base;0 Limit::0xfffff G:1 ;为0时Segment Limit单位为字节 2^20*1Byte = 1M 为1时单位4K 2^20*4K =4G D/B:1 AVL:0 P:1 DPL:0 S:1 ;代码段 TYPE:1000 ;Execule Only ------------------------------------- 高32位:0000 0000 1100 1111 1001 1000 0000 0000 ---> 0x00cf9800 低32位:0000 0000 0000 0000 1111 1111 1111 1111 ---> 0x0000ffff
2、如何引入C语言得开发与调试
- 生成内核:汇编与C语言如何生成内核
${BUILD}/kernel.bin: ${BUILD}/boot/head.o ${BUILD}/init/main.o ld -m elf_i386 $^ -o $@ -Ttext 0x1200 非常重要:-Ttext 0x1200,指定代码入口,调试时候需要用 调试的时候,要选kenel.bin,因为这里面有调试符号,如果说你编译.o文件的时候,不带-g,那内核就是没办法调试 ${BUILD}/system.bin: ${BUILD}/kernel.bin objcopy -O binary ${BUILD}/kernel.bin ${BUILD}/system.bin nm ${BUILD}/kernel.bin | sort > ${BUILD}/system.map(不是必须的)
- 调试C语言
1、内核依赖的所有文件编译的时候应该要带-g,生成调试符号 2、指定入口-Ttext 0x1200 3、要用qemu调试模式运行 -s -S socket lo 127.0.0.1:1234 gdb kernel.bin target remote:1234
- 汇编、C语言如何互调
- 汇编如何调用C语言中的函数
以汇编中掉调用C语言中c_test()函数,核心全局函数 汇编代码中增加: extern c_test gq_ctest: call c_test C语言中: void c_test(void) { int a = 0; char* video = (char*)0xb8000; *video = 'Z'; }
汇编如何访问C语言中的全局变量
C语言如何调用汇编语言的函数
C语言中调用gq_ctest()函数,核心是要将汇编中的void gq_ctest(void) 申明成全局函数
C语言如何访问汇编中定义的变量:地址