开始动工了高大上的了,这次记录完成linux源码中的相关库函数和试调打印函数
1. 常用库函数和试调打印函数
1.1 在内核开发中c语言的标准库我们是用不了的,所以我们需要自己实现一些相关函数,当下要实现的就是操作字符串的一些函数。函数声明写在include文件夹下的string.h头文件中。
这里简单解释几个函数 例如
void memcpy(uint8_t *dest, const uint8_t *src, uint32_t len); //这个就是从src内存地址开始拷贝len个字节,到dest内存地址开始的位置
void memset(void *dest, uint8_t val, uint32_t len); // 将val所指内存中后len个字节全部转变为ACII值,存入dest位置
1.2 在 libs文件夹中的string.c文件中实现string.h中声明的函数
1.3 可以操作字符串以后,我问需要有一个屏幕打印函数,这个屏幕打印函数类似于c中的print()函数,我们需要去写一个printk()函数。屏幕打印函数printk()的声明写在include文件夹下的debug.h文件中
l就像这样声明,但是这里因为不确定传进来的参数有几个,所以我们用了...来代替,也就导致了没有形参,那我们如何找到要打印的字符串呢?
1.4 我们需要先看上面代码中的vargs.h头文件(头文件都在include文件夹中)
例如:
#define va_start(ap, last) (__builtin_va_start(ap, last)) | //初始化变参指针ap,使ap指向last后的第一个变参 |
#define va_arg(ap, type) (__builtin_va_arg(ap, type)) | //将ap指针指向下一个可变参数 |
#define va_end(ap) | //任务完成清除ap |
1.5 输出函数printk()搞完了以后,我们还需要一点东西,那就是当内核遇到致命错误的时候如何自动打印当前函数的调用栈,
这涉及到GRUB Multiboot规范的很多细节和函数 调用栈的结构。也就是需要inclue中的multiboot.h头文件
然而这里面又有ELF格式section头表的一些定义 。
1.6 所以又引出了elf.h头文件 ,里面定义了许多结构体 ,同理也需要提取elf.h结构体中的相关代码(在kernel/debug/elf.c中)
1.7 接下来就到了声明定义当内核遇到致命错误的时候如何自动打印当前函数的调用栈的这些函数了(例如:printc()....),和printk()函数的声明一样是放在debug.h头文件中的 ,然后实现定义的代码在kernel/debug/debug.c中
这下对于内核中屏幕打印,字符操作、内存调用栈等函数就实现了。
2、描述符表的添加(全局描述符表,中断描述符表)
这里需要说 cpu的运行模式 : 实模式、 保护模式、 虚拟8086模式 和 smm模式
一些专业名词 GDT: 全局描述符表 GDTR: 全局描述符表寄存器
IDT :中断描述符表 IDTR : 中断描述符寄存器
80386cpu(32位):有5个控制寄存器CR0--3和CR08,CR0的pe位就是cpu运行状态
分段使用 :分段可以说是Intel的 CPU一直保持着的一种机制,
分页使用:分页是保护模式下的一种内存管理策略。不过想开启分页 机制,CPU就必须工作在保护模式,而工作在保护模式时候可以不开启分页。所以事实上分 段是必须的,而分页是可选的。
2.1 首先需要有全局描述符表的定义,也就是头文件, 这个在/include/gdt.h文件中定义,同理当然也要函数实现了啊,这个在/gdt/gdt.c文件中,(注: 这里我也没搞懂为什么不把函数实现函数同意放一个文件夹中,等整体看完再去研究),最后就是怎末加载了,这是因为有/gdt/gdt_s.s文件,所以在启动过程内核就知道了关于全局描述符表的信息。
2.2 同上我们要有中断描述符表的定义啦,在/include/idt.h中定义,/idt/idt.c中实现函数 /idt/idts_.s文件加载。
2.3 例如 实现定时器中断, 实现函数在/drivers/timer.c中实现,老规矩头文件在timer.h中