第三篇章 启动进程0

本文详细阐述了操作系统内核的初始化过程,包括基础概念如任务寄存器和内存规划,以及中断和外设初始化。内容涉及内存分配、虚拟盘初始化、中断描述符设置、设备请求结构初始化、人机交互外设(如串口、显示器、键盘)的配置,以及系统调用、缓冲区和硬盘、软盘的初始化。最后,文章描述了如何开启中断并进行状态切换,使系统具备基本运行条件。
摘要由CSDN通过智能技术生成

日期:2022-09-27

版本号:V1.0

作者:snow

一、基础概念

1.1、任务寄存器

TR寄存器指向当前任务的TSS,通过ltr访问

LDTR寄存器指向当前任务的LDT,通过lldt访问

二、内存规划

2.1、备份根设备与硬盘参数

由于主存存储空间后续会被重新规划,所以需要提前备份好重要参数。(原系统参数通过setup程序存放在了0x90000~0x901FC)

  1. 将根设备号备份至ROOT_DEV(位于内核数据区)
  2. 将硬盘参数备份至drive_info(位于内核数据区)

2.2、内存规划(按功能)

2.2.1 分配缓冲区

内存容量

m>16MB

16MB≥m>12MB

12MB≥m>6MB

6MB≥m

块0-缓冲区

6MB

4MB

2MB

1MB

块1-主存区

12MB

m-4

m-2

m-1

注:块0-缓冲区的前1MB空间为内核代码与内核数据。后续对于非内核区内容将会采用分页管理机制。而分页管理所需要的参数则据此存储在内核数据区中。(小彩蛋,基于分页管理基础上的用户程序无法访问没有通过分页管理的内容,同时这里指的是纯粹的页式管理,需要区别下段页式管理的页式机制)。缓冲区主要用以与外设-块设备进行数据交互的缓冲。

2.2.2 虚拟盘初始化

若在编译阶段虚拟盘(典型代表ramdisk)使用标志宏定义有效,则会默认在主存区的低地址范围分配一个2MB的空间,然后将对应的处理函数挂接到块设备第7项中,随后对虚拟盘该范围内进行清0。后续对7个块设备的访问即对应和虚拟盘的数据交互。

2.2.3 内存管理结构初始化

将缓冲区(不含内核)的使用次数标记为100,除缓冲区以外的主存区内容设置为0并将次数置为0,后续仅将使用次数为0的页认为是未使用页面。

三、中断&外设初始化

3.1、初始化中断描述符

将中断函数与中断号绑定,即初始化中断号对应IDT中各项内容,主要是将每个中断的中断函数地址、中断优先级等内容写入到中断描述符中。

set_trap_gate(0,&divide_error);

set_trap_gate(1,&debug);

set_intr_gate(2,&nmi);

set_system_intr_gate(3,&int3);

set_system_gate(4,&overflow);

set_system_gate(5,&bounds);

set_trap_gate(6,&invalid_op);

set_trap_gate(7,&device_not_available);

set_task_gate(8,31);

set_trap_gate(9,&coprocessor_segment_overrun);

set_trap_gate(10,&invalid_TSS);

set_trap_gate(11,&segment_not_present);

set_trap_gate(12,&stack_segment);

set_trap_gate(13,&general_protection);

set_intr_gate(14,&page_fault);

set_trap_gate(16,&coprocessor_error);

set_trap_gate(17,&alignment_check);

set_trap_gate(18,&machine_check);

set_trap_gate(19,&simd_coprocessor_error);

set_system_gate(128,&system_call);

3.2、初始化块设备请求项结构

系统会定义32个(或更多)块设备请求项结构,将每个设备请求项指向一个空设备,并将其断开请求项链表(下一个请求项为空)

3.3、初始化人机交互外设

3.3.1 初始化串口

(1)将串口中断服务程序与中断描述表连接

(2)初始话串口工作参数

(3)允许串口外设发出相关中断

3.3.2 初始化显示器

(1)根据系统数据配置显示器工作参数、显存位置以及相关寄存器位置

(2)设置滚屏相关参数、顶底端行号等工作参数

3.3.3 初始化键盘

(1)将键盘中断服务程序与中断描述表连接

(2)允许键盘发出相关中断

3.3.4 确定系统时间

根据CMOS时钟芯片(或者RTC)获取系统启动时间,并据此记录系统时间

3.4、启动前准备

3.4.1 初始化进程槽

3.4.1.1 进程0描述符表挂接

将进程0的状态描述符表添加到gdt+FIRST_TSS_ENTRY处,也就是第4个描述符

将进程0的局部数据描述符表添加到gdt+FIRST_LDT_ENTRY处,也就是第5个描述符

3.4.1.2 其他描述符表清0

定义了64个任务对应描述符空间,每个任务描述符即对应一个任务状态描述符和一个局部数据描述符,故还需要清理余下63个任务对应的描述符空间。

3.4.1.3 分配进程0的栈

在第二篇章的2.1.2.1节中定义了一个页的栈空间,内核(引导程序)启动完成后,这份空间有进程0继续使用,所以直接将进程槽首地址指向这个栈空间。

struct task_struct * task[NR_TASKS] = {&(init_task.task), };

为方便理解,这里可以解释为2

  1. 分配了NR_TASKS个进程描述符指针,每个指针均指向自己的栈空间
  2. 将进程0的进程描述符指针指向内核栈空间。

3.4.1.4 清空进程槽其他进程的栈

task[i]=NULL //i!=0

3.4.1.4 加载当前任务描述符

ltr(0) //让TR寄存器指向第0个TSS

lldt(0) //让LDTR寄存器指向第0个LDT,对应3.4.1.1节

3.4.2 初始化时钟中断

根据系统所需要中断周期配置定时器的中断周期,并允许定时器发出相关中断。

3.4.3 初始化系统调用程序

将系统调用程序绑定到中断描述表,系统调用程序可以理解为由软件触发的中断。

3.4.4 初始化缓冲区

由于缓冲区采用了空闲表与哈希表两种管理方式,故需要两种管理结构均需要初始化。

(1)空闲表建立

将所有的缓冲块连接为一个双向链表,并清空缓冲块中的数据区。

(2)哈希表的建立

让整个哈希表的所有指针均指向空,而不是任何一个缓冲块。

3.4.5 初始化硬盘

(1)将硬盘请求与块设备请求项结构挂接

(2)将硬盘中断函数与中断描述表挂接

(3)允许硬盘发送中断

3.4.6 初始化软盘

(1)将软盘请求与块设备请求项结构挂接

(2)将软盘中断函数与中断描述表挂接

(3)允许软盘发送中断

3.4.7 开中断

sti()

开启中断后标志进程0可以启动,并且系统能够与交互外设、内存、时钟、块设备(软/硬盘)等子系统进行交互,具备了基本的运行条件,可以为系统提供基本的运算功能,但还不能为用户提供计算功能。

3.4.8 状态切换

由于所有的进程任务都只能由已有进程并在用户态创建,而当前系统还处于内核态,故需要通过模仿中断的方式进行状态的切换。

  1. 将用户态下的ss、esp、eflags、cs、eip所需要的数据压栈
  2. 执行iret
  3. 将压入的数据弹出给ss、esp、eflags、cs、eip。

特权等级的切换标志进程0正式启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值