加载内核
加载内核_start函数一个没有包含头文件的c程序
1234int main(){ while (1); return 0;}
利用gcc -c -o kernel/main.o kernel/main.c编译获得mian.o文件,这里的main文件实际上是一个半成品,并不是直接打开就能运行的可执行文件,使用命令file main.o也可以看出这是个重定向文件,此时变量、地址和函数名等都还未确定
ld main.o -Ttext 0xc0001500 -o kernel.bin将文件链接,组成真正的可执行文件,但是这里报了个warning缺少_start,默认地址为00000000c0001500
一个程序需要一个入口地址来表示程序从哪里开始执行,这里的入口程序并不是指平时常见的main函数,也不是程序中第一个字节的起始地址,在一个文件的开头往往会定义相当多的数据(就像之前的loader.S),而是一个名为**_start**的函数,编译器默认将 _start函数所在的地址作为入口地址,在上面中就缺少 _start函数,将main函数名改为 _st ...
保护模式进阶
保护模式进阶获取内存在linux中有许多方法获取内存容量,其本质上是调用 BIOS 中断 0x15 实现的,分别是 BIOS 中断 0x15 的 3 个子功能。
EAX=0xE820:遍历主机上全部内存。
AX=0xE801: 分别检测低 15MB 和 16MB~4GB 的内存,最大支持 4GB。
AH=0x88:最多检测出 64MB 内存,实际内存超过此容量也按照 64MB 返回。
0xe820子功能ARDSBIOS 中断 0x15 的子功能 0xE820 能够获取系统的内存布局,由于系统内存各部分的类型属性不同,BIOS 就按照类型属性来划分这片系统内存,所以这种查询呈迭代式,每次 BIOS 只返回一种类型的内存信息,直到将所有内存类型返回完毕。子功能 0xE820 的强大之处是返回的内存信息较丰富,包括多个属性字段,所以需要一种格式结构来组织这些数据。内存信息的内容是用地址范围描述符来描述的,用于存储这种描述符的结构称之为地址范围描述符(Address Range Descriptor Structure,ARDS)。
地址范围描述符大小是4个字节,共5个字段,一共20个字 ...
保护模式入门
保护模式在16位cpu天下时,并没有实模式的概念,但是随着cpu发展到了32位,寄存器,总线等许多硬件设备得到了更新换代,随之而来的就是cpu新的运行模式,但新出的cpu必须兼容以前老版本的16位的运行模式,所以才有了保护模式和实模式之分。
GDT到了保护模式下,内存段(如数据段、代码段等)不再是简单地用段寄存器加载一下段基址就能用,信息增加了很多,需要提前把段定义好才能使用。全局描述符表(Global Descriptor Table,GDT)是保护模式下内存段的登记表,寄存器GDTR负责指向它。
顾名思义,GDT是一个表,表中必然有表项,每一个表项大小为8个字,称作段描述符,用来描述各个内存段的起始地址、大小、权限等信息,可谓是相当详细。与之对应的,段寄存器也发生了变化,里面保存的不再是段地址,而是‘选择子’,selector,选择子用于索引GDT中的段描述符,看起来就像个数组下标一样。也正是因为段寄存器不再指向物理上的段地址,所以段寄存器中的地址没必要再左移四位硬凑20位的地址,一个32位的寄存器寻址范围是0x00000000 ~ 0xFFFFFFFF,即0~4GB,这样高效的寻 ...