第四篇章 启动进程1

本文详细介绍了Linux系统中进程创建的过程,包括分段和分页机制。在创建新进程时,通过fork函数,压栈保存寄存器状态,并分配进程号和任务号。接着,复制父进程信息,初始化进程描述符,设置代码和数据段基址,并调整页面映射。最后,调整进程管理结构,使得新进程具备独立的文件管理和页表。在切换到新进程后,进程1开始执行,而父进程进入等待状态,等待调度器的调度。
摘要由CSDN通过智能技术生成

日期:2022-09-30

版本号:V1.0

作者:snow

一、基础概念

1.1、地址映射

1.1.1 分段机制

逻辑地址定义如下

   段选择符定义见第二篇1.1节。根据段选择符的定义可以定义8192-1个可用段,每个段对应4GB。同时受限于段寄存器数量,CPU某个时刻只能同时访问六个段。段选择符的偏移即对应GDT或LDT表的偏移,段选择符的TI即对应访问LDT亦或GDT。

从GDT或则LDT中可以获取到当前任务某个段的段基址。

线性地址即对应=段基址+偏移

1.1.2 分页机制

线性地址定义如下:

(1)寄存器CR3:页目录表基址

(2)线性地址高10位:页目录表偏移

(3)线性地址中10位:页表偏移

(4)线性地址低12位:页内偏移

其中,以下内容对应实际物理地址:

页目录表基址=CR3寄存器

页表基址=(1)+(2)

页面基址=页表基址+(3)

线性地址=页面基址+(4)

二、创建进程1前准备

通过fork函数创建进程1

2.1、寄存器压栈

(1)通过软中断(同时传入fork函数编号2)将系统从用户态切换到内核态,同时由硬件将当前任务的5个与任务相关寄存器入栈,这5个寄存器值将会作为进程1的寄存器值模板。

(2)由软中断(系统调用)程序中的fork函数将ds、es、fs、edx、ecx、ebx压栈,这些数据将会用以初始化进程1的tss结构。

2.2、申请空闲进程号&任务号

(1)申请任务号,从任务号1开始与当前进程槽中所有进程的任务号比对,若发现可用,则标记为last_pid

(2)申请空闲进程号,在进程槽中从1开始搜索,若为使用则标记该进程项位置

2.3、寄存器压栈

压入gs、esi、edi、ebp数据,这些寄存器的值也将用来初始化进程1的tss

三、复制进程1信息

调用_copy__process程序拷贝进程1的信息(传入参数为2.2节返回的空闲进程号,此时为1)

3.1、申请空闲页

(1)通过get_free_page申请一个空闲页

(2)将进程1的进程描述指向该空闲页,作为进程1的栈空间。并将进程槽中该进程的进程管理结构指向该空闲页

task[nr]=p

3.2、复制进程描述符

current指向当前进程0的进程描述符,task[nr]指向进程1的进程描述符,通过正常复制即可完成相应拷贝。

3.3、进程1状态锁定

将进程1的状态设置为不可中断等待状态,该状态会一直保持到进程1创建完毕,避免进程1收到任何中断信号的影响。直至其创建完毕后将其改为就绪,才能让进程1可执行。

3.4、进程描述符调整

将进程1的进程描述部分内容进行调整

例如指定任务号为2.2节中空闲任务号

父进程为进程0

优先级

信号清空

执行周期默认

进程执行时间相关参数配置

3.5、初始化任务描述符

(1)将进程0的各项寄存器值拷贝到进程1的任务(状态)描述符中(即进程0上述对应时刻的寄存器状态)(即设置返回环境)

(2)将进程1的任务(状态)描述符中eax置0(即设置返回环境,该值可用以标记进程1返回还是进程0返回)

(3)将进程1的LDT设置为GDT的第1个LDT(任务0占用第0个)

(4)将进程1的trace_bitmap设置为0x80000000(信号位图&协处理器)

3.6、初始化进程1的页面

(1)获取当前进程(进程0)的代码段、数据段的段限长和基址

在进程3.4.1.4节加载了当前进程的LDT位置,此时通过get_limit访问

code_limit=get_limit(0x0f);//获取当前进程第1项LDT,访问权限:用户级

data_limit=get_limit(0x17); //获取当前进程第2项LDT,访问权限:用户级

(2)检查当前进程(进程0)的代码段、数据段成都是否合法(数据段需要不小于代码段)

(3)检查当前进程(进程0)的代码段、数据段的基地址是否一致

(4)定义新的进程1的数据段、代码段基地址(0x64MB偏移)

(5)将进程1的代码默认启动地址指向进程1代码段的基地址

(6)将进程1的数据段、代码段基地址装载到进程1的第1项ldt(代码)、第2项(数据)

(7)申请页目录项,并让进程1的进程管理结构指向该目录

(8)申请页表,并让进程1的页目录的第一项指向该页表

(9)将进程0的第0个页目录的第0个页表的前160个页面地址拷贝给进程1,使进程拥有相同的页面(即相同的数据)。(注:此时进程0通过页面访问物理内存0~64MB,进程1基于基地址64MB可以访问64~128MB,但是进程1的页表实际是指向0~64MB的160个页面)

四、进程1管理结构调整

4.1、文件管理结构初始化

经过复制后,进程0与进程1的进程管理结构基本一致(除了代码段、数据段基址),但是进程1作为子进程,需要有更加丰富功能-文件交互。故还需要针对进程1的文件相关的管理结构进行初始化。

4.2、进程1描述符表挂接

同理3.4.1.1节

将进程1的状态描述符表添加到gdt+(nr<<1)+FIRST_TSS_ENTRY处,也就是第5个描述符

将进程1的局部数据描述符表添加到gdt++(nr<<1)+FIRST_LDT_ENTRY处,也就是第6个描述符。

描述符的挂载意味着进程1创建完毕。

五、切换进程1

5.1、fork返回

(1)将进程1的状态改为就绪态,使其参与调度

(2)返回进程1的进程标号

5.2、进程0返回

进程0判断返回值是否为0,不为0(为进程1的进程标号1),继续进行进程0余下工作。

陷入死循环,并执行pause()函数。该函数主要用以产生软中断,在对应软中断函数中,会将本进程状态切换为可中断等待状态,并执行一次进程调度器。

5.3、进程调度器

(1)在进程调度器器中,会检索当前所有进程,若有信号量释放或者那种时间,则对相应进程信号进行相应处理(使进程状态发生变化,接收参数等)。

(2)会检索当前所有进程,根据调度规则,选择一个进程进行执行。

5.4、进程1返回

进程1从start开始运行,但是由于在3.5节多压入的一个0,所以进程1恢复现场时,会返回。

进程1判断返回值是否为0,为0,继续进行进程1余下工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值