手写64位操作系统内核规划图:
boot程序起始0扇区,共占1个扇区
setup程序起始1扇区,共占一个扇区2个扇区
x86内核起始 3扇区,共占一个扇区大于30个扇区
关中断
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
生成内核:汇编与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语言如何访问汇编中定义的变量:地址