操作系统实践之路——五、初始化(设置工作模式与环境)


前言

​ 这个章节会在这个 hal_start 函数里,首先执行板级初始化,其实就是 hal 层(硬件抽象层,下同)初始化,其中执行了平台初始化,hal 层的内存初始化,中断初始化,最后进入到内核层的初始化。

初始化平台

我们先来写好平台初始化函数,因为它需要最先被调用。

这个函数主要负责完成两个任务,一是把二级引导器建立的机器信息结构复制到 hal 层中的一个全局变量中(init_machbstart),方便内核中的其它代码使用里面的信息,之后二级引导器建立的数据所占用的内存都会被释放。二是要初始化图形显示驱动(init_bdvideo),内核在运行过程要在屏幕上输出信息。

初始化内存

首先,我们建立一个 halmm.c 文件,用于初始化内存,为了后面的内存管理器作好准备。

hal 层的内存初始化比较容易,只要向内存管理器提供内存空间布局信息就可以。

你可能在想,不对啊,明明我们在二级引导器中已经获取了内存布局信息,是的,但 Cosmos 的内存管理器需要保存更多的信息,最好是顺序的内存布局信息,这样可以增加额外的功能属性,同时降低代码的复杂度。

主要的原理就是根据 e820map_t 结构数组,建立了一个 phymmarge_t 结构数组,init_one_pmrge 函数正是把 e820map_t 结构中的信息复制到 phymmarge_t 结构中来。

初始化中断

​ 在 x86 CPU 上,最多支持 256 个中断,还记得前面所说的中断表和中断门描述符吗,这意味着我们要准备 256 个中断门描述符和 256 个中断处理程序的入口。

​ 有了中断门之后,还差中断入口处理程序,中断入口处理程序只负责这三件事:

  1. 保护 CPU 寄存器,即中断发生时的程序运行的上下文。

  2. 调用中断处理程序,这个程序可以是修复异常的,可以是设备驱动程序中对设备响应的程序。

  3. 恢复 CPU 寄存器,即恢复中断时程序运行的上下文,使程序继续运行。

​ 以上这些操作又要用汇编代码才可以编写,我觉得这是内核中最重要的部分,所以我们建立一个文件,并用 kernel.asm 命名。

​ 一开始把所有中断的处理程序设置为保留的通用处理程序,避免未知中断异常发生了 CPU 无处可去,然后对已知的中断和异常进一步设置,这会覆盖之前的通用处理程序,这样就可以确保万无一失。

​ 前面我们只是解决了中断的 CPU 相关部分,而 CPU 只是响应中断,但是并不能解决产生中断的问题。

​ 比如缺页中断来了,我们要解决内存地址映射关系,程序才可以继续运行。再比如硬盘中断来了,我们要读取硬盘的数据,要处理这问题,就要写好相应的处理函数。

​ 因为有些处理是内核所提供的,而有些处理函数是设备驱动提供的,想让它们和中断关联起来,就要好好设计中断处理框架了。

​ 下面我们来画幅图,描述中断框架的设计:

在这里插入图片描述

初始化中断控制器

​ 我们把 CPU 端的中断搞定了以后,还有设备端的中断,这个可以交给设备驱动程序,但是 CPU 和设备之间的中断控制器,还需要我们出面解决。

​ 多个设备的中断信号线都会连接到中断控制器上,中断控制器可以决定启用或者屏蔽哪些设备的中断,还可以决定设备中断之间的优先线,所以它才叫中断控制器。

调用流程

一、建造二级引导器

1、grub启动后,选择对应的启动菜单项,grub会通过自带文件系统驱动,定位到对应的eki文件

2、grub会尝试加载eki文件【eki文件需要满足grub多协议引导头的格式要求】
这些是在imginithead.asm中实现的,所以要包括:
A、grub文件头,包括魔数、grub1和grub2支持等
B、定位的_start符号等

3、grub校验成功后,会调用_start,然跳转到_entry
A、_entry中:关闭中断
B、加载GDT
C、然后进入_32bits_mode,清理寄存器,设置栈顶
D、调用inithead_entry【C】

4、inithead_entry.c
A、从imginithead.asm进入后,首先进入函数调用inithead_entry
B、初始化光标,清屏
C、从eki文件内部,找到initldrsve.bin文件,并分别拷贝到内存的指定物理地址
D、从eki文件内部,找到initldrkrl.bin文件,并分别拷贝到内存的指定物理地址
E、返回imginithead.asm

5、imginithead.asm中继续执行
jmp 0x200000
而这个位置,就是initldrkrl.bin在内存的位置ILDRKRL_PHYADR
所以后面要执行initldrkrl.bin的内容

6、这样就到了ldrkrl32.asm的_entry
A、将GDT加载到GDTR寄存器【内存】
B、将IDT加载到IDTR寄存器【中断】
C、跳转到_32bits_mode
初始寄存器
初始化栈
调用ldrkrl_entry【C】

7、ldrkrlentry.c
A、初始化光标,清屏
B、收集机器参数init_bstartparm【C】

8、bstartparm.c
A、初始化machbstart_t
B、各类初始化函数,填充machbstart_t的内容
C、返回

9、ldrkrlentry.c
A、返回

10、ldrkrl32.asm
A、跳转到0x2000000地址继续执行

二、HAL层调用链
hal_start()

A、先去处理HAL层的初始化
->init_hal()

->->init_halplaltform()初始化平台
->->->init_machbstart()
主要是把二级引导器建立的机器信息结构,复制到了hal层一份给内核使用,同时也为释放二级引导器占用内存做好准备。
其做法就是拷贝了一份mbsp到kmbsp,其中用到了虚拟地址转换hyadr_to_viradr
->->->init_bdvideo()
初始化图形机构
初始化BGA显卡 或 VBE图形显卡信息【函数指针的使用】
清空屏幕
找到"background.bmp",并显示背景图片
->->->->hal_dspversion()
输出版本号等信息【vsprintfk】
其中,用ret_charsinfo根据字体文件获取字符像素信息

->->move_img2maxpadr()
将移动initldrsve.bin到最大地址

->->init_halmm()初始化内存
->->->init_phymmarge
申请phymmarge_t内存
根据 e820map_t 结构数组,复制数据到phymmarge_t 结构数组
按内存开始地址进行排序

->->init_halintupt();初始化中断
->->->init_descriptor();初始化GDT描述符x64_gdt
->->->init_idt_descriptor();初始化IDT描述符x64_idt,绑定了中断编号及中断处理函数
->->->init_intfltdsc();初始化中断异常表machintflt,拷贝了中断相关信息
->->->init_i8259();初始化8529芯片中断
->->->i8259_enabled_line(0);好像是取消mask,开启中断请求

最后,跳转去处理内核初始化
->init_krl()

三、中断调用链,以硬件中断为例
A、kernel.inc中,通过宏定义,进行了中断定义。以硬件中断为例,可以在kernel.inc中看到:
宏为HARWINT,硬件中断分发器函数为hal_hwint_allocator
%macro HARWINT 1
保存现场…
mov rdi, %1
mov rsi,rsp
call hal_hwint_allocator
恢复现场…
%endmacro

B、而在kernel.asm中,定义了各种硬件中断编号,比如hxi_hwint00,作为中断处理入口
ALIGN 16
hxi_hwint00:
HARWINT (INT_VECTOR_IRQ0+0)

C、有硬件中断时,会先到达中断处理入口,然后调用到硬件中断分发器函数hal_hwint_allocator
第一个参数为中断编号,在rdi
第二个参数为中断发生时的栈指针,在rsi
然后调用异常处理函数hal_do_hwint

D、hal_do_hwint
加锁
调用中断回调函数hal_run_intflthandle
释放锁

E、hal_run_intflthandle
先获取中断异常表machintflt
然后调用i_serlist 链表上所有挂载intserdsc_t 结构中的中断处理的回调函数,是否处理由函数自己判断

F、中断处理完毕

G、异常处理类似,只是触发源头不太一样而已

流程思维导图:
在这里插入图片描述

以下贴一张树下野鹿大佬整理的操作系统Cosmos hal层的函数调用思维导图

在这里插入图片描述

参考资料

以上内容是我学习彭东老师的《操作系统实战45讲》后所进行的一个笔记记录,如有错误,还请各位大佬多多指教。

我主要参考了以下资料,十分感谢:

操作系统实战45讲——彭东老师

评论区大佬—neohope、艾恩凝、卖薪沽酒等

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值