![88639652610e0ff7b0235b3251588198.png](https://img-blog.csdnimg.cn/img_convert/88639652610e0ff7b0235b3251588198.png)
先讲一下代码在跑到setup之前的内存视图,有助于我们更好地理解setup中的操作。
在上电时,内存视图如下:
在内存的0x0位置是BIOS的中断向量表
![13534517948e8c9eba6ed8f23328c131.png](https://img-blog.csdnimg.cn/img_convert/13534517948e8c9eba6ed8f23328c131.png)
执行Bootset之后,内存视图如下:
Bootset首先将自己本身读到了0x90000的位置,然后将4个区块的setup读入0x90200,然后打印出正在加载系统,然后将system读到0x10000的位置。
![02a339d18c03599a62bbafc97f400b39.png](https://img-blog.csdnimg.cn/img_convert/02a339d18c03599a62bbafc97f400b39.png)
下面分析setup代码
代码在开头的一大部门是先通过BIOS中断读取一些硬件信息到0x90000~0x900A0的位置(覆盖了bootset)
然后接下来是将原来位于0x10000的system移动到0x0处,这样,BIOS的中断表都被覆盖了,因此中断不能用了。
![a4cd8db859337ad618e301f22f002060.png](https://img-blog.csdnimg.cn/img_convert/a4cd8db859337ad618e301f22f002060.png)
移动完之后,需要安装GDT和IDT表,IDT表长度为0,地址也为0;GDT表长度0x800,地址为(0x0000 0000 0009 0000)+(0x200,里面有刚读入存储的硬件信息)+(gdt标号相对于setup程序头部的偏移),该地址是32位的线性地址。在setup中安装的GDT和IDT都是临时的,只是为了jmpi 0,8这一个保护模式指令用的,后续子啊head.s中会重新安装GDT和IDT,但是那时IDT的内容是空的,等到外设初始化的时候才会装入中断入口函数。
GDT表中有三个表项:空项、system内核段、system内核数据段
![e6c4f0d6da897bee5be9e9fa8f759bde.png](https://img-blog.csdnimg.cn/img_convert/e6c4f0d6da897bee5be9e9fa8f759bde.png)
![950b84774968ddfbf4ea37220394c1ad.png](https://img-blog.csdnimg.cn/img_convert/950b84774968ddfbf4ea37220394c1ad.png)
将下图与GDT表项格式进行对比看,可以发现,内核代码段描述符的基地址组合起来就是0x0,内核数据段基地址也是0x0.
![0b96a6482efce3c8527c832a2f46ef3a.png](https://img-blog.csdnimg.cn/img_convert/0b96a6482efce3c8527c832a2f46ef3a.png)
接下来开启A20地址线并置位CR0,最后使用指令jmpi 0 , 8 ,则CS = 8 即GDT表中第八个字节往后,这是内核代码段,EIP=0,组合起来即0x0,这个地址正是move后的system地址。
![48d65fcbcfef65f6a6c7faaa06612874.png](https://img-blog.csdnimg.cn/img_convert/48d65fcbcfef65f6a6c7faaa06612874.png)
![7da04ab8f6c5b662416d7d59b3feeb3f.png](https://img-blog.csdnimg.cn/img_convert/7da04ab8f6c5b662416d7d59b3feeb3f.png)
Setup执行完后的内存视图:
![fb1afb1f89526eb6042c1d9a4bd1fd56.png](https://img-blog.csdnimg.cn/img_convert/fb1afb1f89526eb6042c1d9a4bd1fd56.png)