lab1 BootLoader启动ucoreos实现

一、x86启动顺序

在这里插入图片描述
——一上电,CS和EIP来决定启动的第一条地址:
cs:16位的段寄存器 EIP:32位的指令指针寄存器
x86为了兼容之前的8086,一开始启动时,进入16位的实模式,寻找第一条指令的地址时按照实模式寻址方式(实模式下寻址空间只有1M)cs左移四位+EIP
加电之后要去取得第一条地址,就是BIOS(PC中的一个固件,主要进行底层的硬件初始化工作,是只读的ROM),空间大小1M
在这里插入图片描述
——然后跳到BIOS中执行硬件初始化工作(外设,cpu等硬件自检)
实模式下没有段机制页机制,保护模式才有

——BIOS完成硬件,外设的自检后,会去加载磁盘或者硬盘的第一个主引导扇区(零号扇区,里面存着BootLoader的代码)读到内存中,一个扇区的大小是512个字节,将这个扇区的内容读到一个固定地址0x7C00,同时将Eip地址跳到0x7c00这里来,继续执行该扇区内(BootLoader)的代码

——进入到BootLoader
BootLoader完成对操作系统的进一步加载
• 为什么BIOS不直接加载操作系统?
BIOS能力不够,只加载一个扇区(512字节),而操作系统是大于512字节的,所以BIOS加载扇区后,让扇区继续完成后面的加载工作,这个扇区称为bootloader

在这里插入图片描述
——BootLoader完成的功能:
从实模式切换到保护模式(从16位寻址空间切换到32位寻址空间,从1M的寻址到4G的寻址),保护模式中段机制就可以正常工作了
将ucore的代码从硬盘中读到内存中来
最后将控制权交给ucore,就是将CS EIP的值指向操作系统内核所在内存中的起始点

二、中断机制

中断机制:从产生中断到中断响应的过程
中断描述符表寄存器(IDTR):记录中断描述符表(IDT)的起始地址
中断描述符表(IDT):IDT中存放着中断门,中断门指出了当一个中断产生后它对应的中断服务例程在什么地方
在这里插入图片描述
中断或异常产生之后,根据它的编号, cpu会在IDT中找对应的中断门,中断门中有偏移和选择子,选择子作为index来查找GDT,从而得知中断服务例程所处段的基址,基址加偏移形成了最终中断服务例程的入口地址

中断执行过程
无特权级切换(即内核中的中断,依然只需要内核栈):
在这里插入图片描述
当发生中断时,将当前程序执行现场保存到内核栈中,cs与eip指明被打断的下一条地址。
然后执行中断服务例程,中断执行完后,内核栈弹出相应地址恢复执行

有特权级切换(即用户态的中断,需要进到内核执行完中断后再恢复到用户态执行):
在这里插入图片描述
从当前进程的描述符中提取其内核栈的ss0及esp0信息,获取内核栈的地址。将用户态程序的下一条指令的地址(CS,EIP,eflags,error code等)压到内核栈中,将用户栈地址ss3和esp3压到内核栈中。
然后执行中断服务例程,中断执行完成后,弹出ss3和esp3,相当于找到了用户栈,然后将保存在内核栈中的用户程序的下一条指令地址加载到用户栈中,从而执行下一条用户态程序代码
ss和esp的作用就是找到相应的栈

段描述符中会设定该内容到底属于哪个特权级,cs的低两位是0表示运行在内核态,cs低两位是3表示运行在用户态
内核态产生的中断依然在内核态,特权级没变,用户态产生的中断会跳到内核态,特权级发生了变化

三、各个练习内容

1、lab1中代码执行流程总结(练习2:单步调试):
启动CPU:BIOS将bootasm.S汇编代码从硬盘的第一个扇区加载到物理地址为0x7c00的内存,开始以实模式执行
(练习3的内容:分析bootloader进入保护模式的过程)
{
关闭中断,将各个段寄存器重置
开启A20(什么是A20:当 A20 地址线控制禁止时,则程序就像在 8086 中运行,1MB 以上的地址是不可访问的。而在保护模式下 A20 地址线控制是要打开的,所以需要通过将键盘控制器上的A20线置于高电位,使得全部32条地址线可用。)
加载GDT表(全局描述符表)
长跳转指令跳转到bootloader的起始地址0x7c00
转到保护模式完成,进入bootmain.c
}
————————————
进入bootmain.c
(练习4内容:分析bootloader加载ELF格式的OS的过程)
{
读取硬盘扇区
判断读入文件是否为合法的elf文件(linux下的可执行文件格式)
ELF头部有描述ELF文件应加载到内存什么位置的描述表,这里读取出来将之存入ph
按照程序头表的描述,将ELF文件中的数据载入内存
根据ELF头表中的入口信息,找到内核的入口并开始转到kern(ucore)代码段执行
}
硬件初始化
屏幕打印os is loading信息
打印内核信息,内核入口地址,及内核使用多少内存等等
初始化物理内存
初始化中断控制器
初始化中断描述符表(练习6:完善中断初始化和处理 )
{
填充中断描述符表:使用SETGATE填充(内置函数)
中断处理函数:根据不同的中断号执行不同的操作
}
初始化时钟中断
使能中断(汇编指令sti使能中断,cli屏蔽中断)
lab1_switch_test(特权级切换)
(包含练习5内容:实现函数调用堆栈跟踪函数)
{
(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
函数调用大概包括以下几个步骤:
1、参数入栈:将参数依次压入系统栈中。
2、返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。
3、代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。
4、栈帧调整
4.1保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)。
4.2将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部)。
4.3给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶)。
而函数返回大概包括以下几个步骤:
1、保存返回值,通常将函数的返回值保存在寄存器EAX中。
2、弹出当前帧,恢复上一个栈帧。
2.1在堆栈平衡的基础上,给ESP加上栈帧的大小,降低栈顶,回收当前栈帧的空间
2.2将当前栈帧底部保存的前栈帧EBP值弹入EBP寄存器,恢复出上一个栈帧。
2.3将函数返回地址弹给EIP寄存器。
3、跳转:按照函数返回地址跳回母函数中继续执行。
}

四、其他需要了解的内容:

——中断知识:
中断是操作系统对硬件提供的接口,系统调用是操作系统对上层应用提供的服务接口
系统调用与函数调用的区别:系统调用更安全,但开销更大,原因是系统调用有一个用户态到内核态的切换
异常:应用程序出现意外后,将控制权转交给操作系统,由操作系统进行异常处理
中断描述符表IDT 全局描述符表GDT 局部描述符表LDT
中断描述符表IDT将每个异常或中断向量分别与它们的处理过程联系起来。
全局描述符表(Global Descriptor Table,GDT)是保护模式所必须的数据结构,引入GDT主要是出于系统安全性、内存寻址方式的兼容等方面的考虑。 一个段描述符只用来定义一个内存段,这些描述符都存放在全局描述符表中。GDT相当于存放段描述符的数组,而索引则是选择子。在实模式中,段寄存器存放的是段基地址,而在保护模式下段基址已经存放在段描述符中了。因此,段寄存器的作用就改为了存储全局描述符表的索引——选择子。
LDT:每个任务的私有内存段都应该放到自己的段描述符表中
外设是外部中断,内部中断就是软件产生的中断(软中断),软中断通常用于系统调用
中断号唯一标识了这个中断的特征,对于每一个中断号都有相应的中断处理的一个例程
——使用的linux命令:ls,cd,make(编译),make clean(清除编译文件),less(查看文件),pwd(显示当前目录),Makdir test(创建文件夹),vim(编辑,:q,:wq)
——C语言知识:"0x%08x"其中,0x为普通字符,输出的时候会原样输出为0x。%08x为整型以16进制方式输出的格式字符串,会把后续对应参数的整型数字,以16进制输出。08的含义为,输出的16进制值占8位,不足部分左侧补0。于是,如果执行printf(“0x%08x”, 0x1234);会输出0x00001234。
——虚拟机操作:Ubuntu进入与退出root模式,输入命令:su root,然后输入密码:发现可以切换到root权限了。使用su xyx命令,切换到普通用户。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值