Linux0.11笔记——执行MAIN函数到激活进程0

    现在main函数开始行了,可真正意上的linux操作系开始运行了。main函数将置程序在操作系下运行所需的境并0,操作系才有了第一个程。

    设置根设备和硬盘信息:之前在setup程序中加了一些硬件信息并存在物理内存0x90000-0x901FC处,main函数从些参数中置了全局量根设备ROOT_DEV、硬信息drive_info两个信息在置操作系统环会被访问

    规划物理内存格局,设置缓冲区,虚拟盘和主内存:内存分为内核代码和数据所占空间(也就是物理内存从0x000000xFFFFF1MB)、主内存区(进程代码运行的,以及一些申内存的操作都是使用的,包括内核管理内存的数据task_struct都是存放在此。16MB的物理内存情况下10MB)、冲区(主机与外数据交互的中站,主要是了外的数据能被多个程共享,防止访问,外访问速度比内存的访问速度慢多了。16MB的物理内存情况下3MB)、虚拟盘(可,物理内存不够时可以不置,外的数据可以先里提高访问速度。16MB的物理内存情况下2MB,现在一般都没有用到虚拟盘了)。

    内存管理结构mem_map的初始化:主内存的访问需要通mem_map来管理,内存中有多少的页mem_map就有多少的项。每次进程新申请的页,都要找mem_map报备,让该页的引用计数加1。如果还页的话,引用计数就减1。当需要释放页时,必须满足该页的P位(存在位)为0且在mem_map中释放,这个页才是真正的释放。简单来说mem_map就是为内存扮演记账的角色。初始化(mem_init)将主内存中的面使用数置0,其它的置100,之后系内存只能使用0面。

    异常中断服程序挂接:调用trap_init一些异常型的中断(如缺、溢出、除0错误、边界检查等)的中断处理程序挂接到IDT上,以支持内核,进程在主机中的运算。

    其他的初始化操作包括初始化块设备请项结构、初始化字符设备、设置串口,显示器以及键盘、设置开机启动时间等等

   初始化0

    0是操作系建立的第一个程,一直运行在系中,当系没有可行的任会切0执行,因此进程0也叫守护进程。注意到现在的代码是从bootsect开始一路跳到此的,还处内核。在进程0创建前,内存中有个内核栈,一旦进程0激活后,该栈会变成进程0的用户栈。之后再也没有一个绝对内核栈了,而是每个进程都有属于自己的用户栈和内核栈。
初始化进程0这个阶段主要包含3个方面的工作:

    一、每个进程都有自己的管理结构task_struct,进程0也不例外。而它的task_struct的代码是事先设计好的。因为在Linux里认为是进程创建进程,进程0是系统的第一个进程,所以进程0相当于所有进程的祖先。所以我们需要把进程0的task_struct中的LDT,TSS挂接到GDT上(所有的进程都有一对LDT和TSS,新创建的进程需要把它们挂接到GDT上)。并对GDT、task[64](是否为一个进程的重要标志就是task_struct是否放到了task[64]中,此时task的第0项指向进程0,其他项清零)以及进程调度相关的寄存器进行初始化设置(TR寄存器指向进程0的tss地址,LDTR寄存器指向进程0的LDT地址)。

    task_struct:task_struct和内核是一个union结构共同占用一个内存页面,进程进入内核态后,执行用的代码都是内核代码,但执行路径未必相同,导致数据压栈的顺序和内容不同,而这些栈又不能存储在每个进程的用户空间中,这样容易被用户覆盖和改动,因此需要为每一个进程专门准备一套内核栈。效果如下图所示:

Linux0.11笔记——执行MAIN函数到激活进程0_第1张图片

    二、Linux0.11作为现代操作系统,其最重要的标志就是能够支持多进程轮流执行,这就要求操作系统能够支持时钟中断,以便在进程0运行后,为进程0以及后续由它直接或间接创建出的进程能够参与轮转奠定基础。

    三、进程0需要具备处理系统调用的能力。每个进程在运行时都可能需要与内核进行交互(比如读写文件等),而交互的接口就是系统调用程序。系统需要将system_call与IDT相挂接(系统调用本身也是中断的一种,属于0x80中断)。这样进程0就具备了处理系统调用的能力了,这个system_call就是系统调用的总入口。

    初始化冲区管理构:缓冲区的本质是以空间换时间。我们知道如果想获取数据,需要从硬盘上将数据搬进内存,而有了缓冲区,我们便可以从缓冲区获取数据,大大提升了效率。前面到操作系会在挨着内核代和数据区为缓冲区分配3MB的内存,个内存区域就是用来建多个冲区,每个冲区可以存1KB的数据,所以共有3072冲区。操作系struct buffer_header*类型的free_list链表和hash_table[307]哈希表管理冲区,两个都是内核数据区中的量。当程要从设备取数据,操作系先把数据从设备中按block的大小取到缓冲区中,并设置哈希表和free_list这样如果其他程也要设备上相同的block可以直接从内存上取而不必再次访问设。请缓冲区是从free_list部开始遍,找到第一个可用的buffer_head,也就是从冲区尾部往前找,将其对应冲区作新的冲区。接着是进行硬盘和软盘的初始化。

    开启中断:值得注意的是自从setup关中断以后到目前为止都没有开启中断,但是在操作系要使用的中断服程序以及置好了,意味着中断服务体系已经建立完毕,系统可以在32位保护模式下处理中断,所以现在可以开中断了。

   翻转进程0的特权级

    Linux规定,所有进程都要由一个已有进程在3特权级下创建。当前是内核,需要转变成用户态使0真正意上的第一个用户进程。里的模式变换是通iret实现的(模仿中断返回动作move_to_user_mode,使进程0的特权级从0变到3)。

    正常的中断处理方式:所有型的中断会先通过进task_struct结构中的的tss找到程的内核栈栈顶在的内核栈栈底就是在bootsect置的0x9000),依次把寄存器SS(用户栈栈底)、ESP(用户栈栈顶)、EFLAGS志位)、CS(代段)、EIP(下条指令的地址)压入该进程的内核,并将系0x11用户态转为0x00内核态。行完后通iret返回。iret会从进程的内核出五个别赋值给5个寄存器,并将系从系模式翻回用模式。这个保护现场和恢复现场以及翻转特权级的动作是由CPU硬件实现的。

    Linux0.11笔记——执行MAIN函数到激活进程0_第2张图片

    而此时需要人为地制造现场,当前在操作系统里只有一个绝对内核栈。此时相当于把该绝对内核栈的SS和ESP压入绝对内核栈中。0x17和0x0f是均是3特权级的,说明入栈的SS和CS都是用户态的。在恢复现场后,绝对内核栈就变成了进程0的用户栈,特权级也由原来的0态变成了3态。这个设计真是太巧妙了!

    至此,进程0激活结束。它的工作几乎做完了,接下来它要创建进程1,并将自己于无限行状

    小知识:关中断和进程有关吗?有关,一个进程关中断是将EFLAGS中IF位置0,不同进程的EFLAGS是存在该进程的TSS中,所以一个进程关中断并不会影响另一个进程的中断使用。











你可能感兴趣的:(操作系统,操作系统,Linux,进程0初始化)