您的位置:首页 > 运维架构 > Linux

《Linux内核设计的艺术》学习笔记(一)从开机加电到执行main函数之前的过程

2016-05-07 14:57 495 查看
分享一个最近丢了手机心塞到爆炸的我,现在穷的只剩下满脑子的智慧了,好了,我要开始学习了.

首先,搭建一个linux0.11的系统环境,贴出结果图.



从开机加电到执行main函数之前的过程.

1. 启动BIOS,准备实模式下的中断向量表和中断服务程序;

2. 从启动盘加载操作系统程序到内存,加载操作系统程序的工作就是利用第一步中断服务程序实现的;

3. 为执行32位的main函数做过渡工作.

启动BIOS,准备实模式下的中断向量表和中断服务程序

cpu的硬件设计为加电即进入16位实模式下状态运行,硬件逻辑设计为加电瞬间强行将CS的值置为0xF000,IP的值为0xFFF0,而这个位置就是BIOS的的地址范围.(IP指令指针寄存器,记录将要执行的指令在代码段内的偏移地址,和cs组合即为将要执行的指令的内存地址).

BIOS程序在内存中加载中断向量表和中断服务程序

加载操作系统内核程序为保护模式做准备(boot)

加载第一 部分内核代码-bootsect引导程序

找到软盘并加载第一扇区,该扇区的内容就是引导程序,其作用就是陆续把软盘中的操作系统程序载入内存.

加载 第二部分内核代码-setup

加载第三部分内核代码-system模块 将系统模块载入内存

为执行32位的main函数做过渡工作

关中断并将system移动到内存起始位置0x00000

这里需要注意,0x00000这个位置原来存放这有BIOS建立的中断向量表及BIOS数据区.这个复制动作将之前东西覆盖,操作系统不再具备相应处理中断的能力

设置中断描述符表和全局描述符表

打开A20,实现32位寻址

为保护模式下执行head.s做准备

head.s开始执行

head.s

这里补充一点,开机时的16位实模式与main函数执行需要的32位保护模式之间有很大的差距,这个差距就有head.s来做这项工作.这期间,head程序打开A20,打开pe,pg,废弃旧的,16位的中断响应机制,建立新的32位的IDT.

前4KB的代码将被页目录覆盖掉。这些代码执行的操作包括:设置系统堆栈为_stack_start。重新设置GDTR和IDTR。gdt,idt表都定义在head.s的末端,长度均为256项(2KBYTE)。第2个页面到第5个页面是系统的4张页表。最后一个页表后面的代码执行分页操作,即填充的4个页目录和4张页表的内容,实现对等映射,即物理地址=线性地址。每个页表项属性为存在并且用户可读写。设置好后置CR3页目录地址即0。启动分页标志,CR0的PG标志置1。跳到main函数中执行。head还做了重要事情,就是用程序自身的代码在程序自身所在的内存空间创建了内核分页机制,即在0x000000的位置创建了页目录表,页表,缓冲区,GDT,并将head程序已经执行过的代码所占内存空间覆盖

跳到main之前,内存布局如下:从0到16M

页目录4K(0x0开始)

页表1 4K

页表2 4K

页表3 4K

页表4 4K

软盘缓冲区1K

head.s后半部分代码

IDT表2K

GDT表2K

main.o代码部分

内核其余部分(大约到512K,end值为结束地址)

setup保存的系统参数(90000H~900200)这个区间还保存着root_dev.

BIOS(640K-1M)

主内存区(1M-16M)



在执行main函数之前,先要执行三个由汇编代码生成的程序,即bootset(加载bootset到0x07c00,然后复制到0X90000),setup(加载setup到ox90200)和head(先将head.s汇编成目标代码,将用c语言编写的内核程序编译成目标代码,然后链接成system模块,head程序在前,内核)之后,才执行由main函数开始的用c语言编写的操作系统内核程序.

写不下去了…我觉得这本书将的非常好…还是自己看书吧哈哈哈

下午再整理吧…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: