Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1078657
  • 博文数量: 104
  • 博客积分: 3715
  • 博客等级: 中校
  • 技术积分: 1868
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-30 08:38
文章分类

全部博文(104)

文章存档

2013年(1)

2012年(9)

2011年(41)

2010年(3)

2009年(3)

2008年(47)

分类: 系统运维

2011-01-11 13:53:01

    在上文中,我们大体分析了从加电到boot monitor启动及执行的流程。如前文所说,boot monitor通过调用
函数bootminix()真正加载minix的启动映像并启动它。
    bootminix()函数定义在文件bootimage.c中,它也作为boot程序的一个模块而链接进boot。本文主要分析这个
模块,通过这个模块了解minix的启动过程,并找出minix内核的入口。
* 几个工具函数
    1.  pretty_image():该函数会把image的名字、版本以较好看的形式打印到终端;
    2.  raw_clear():该函数将指定的一段内存清0;
* bootminix()
    该函数的主要流程如下:
    1.  从环境变量中取出"image"的路径名(boot/image),这可以是包含image的目录,
        image本身用版本号做名字,也可以是image的路径名;
    2.  调用函数select_image()来选择要启动的image;
    3.  如果tty是串口,设置SERVARNAME变量,指向这个串口名;
    4.  调用exec_image()启动找到的image;
    5.  检查是否出错,清理环境;
* select_image()
    该函数用于选择要启动的image,如果参数是一个文件,那么这就是要启动的image,如果参数是一个路径,
就在这个路径下找版本最新的image,如果参数是一个'offset:size'的格式,并且这个名字的文件不存在,
那么就以这个为磁盘的偏移量来读取image。
* exec_image()
    该函数加载image,patch它的数据结构并启动它。该函数有300行左右(bad practice)。该函数的主要流程
如下:
    1.  检查一下栈和堆是否已经冲突了,如果是,重启;
    2.  设置verboseboot的值;
    3.  打印Loading信息;
    4.  在BootMonitor的起始地址之前分配16*32的空间,用于保存image中的程序头信息;
    5.  一次读取各个进程的头信息,并处理:
            对于内核:
            i.  读取clickshift(click是内存分配单元)和flag,设置全局变量click_shift,click_size
                和k_flags;
            i.  将加载的开始地址对齐到click大小;
            i.  如果k_flags中有K_KHIGH标志,重新设置加载的起始地址和终止地址,将这种(较大的内核)
                加载到mem[1]部分的内存(扩展内存)中;
        a.  将进程头信息拷贝一份到(4)中保留的对应空间中; 
        b.  打印该进程的地址信息;
        c.  将进程的代码段、数据段等加载到内存;
    6.  检查:
        1.  (5)至少加载了一个进程(内核);
        2.  内核magic正确;
    7.  调用patch_sizes()方法,将加载的进程的信息打补丁到内核数据空间相应的位置(如果内核设置了
        K_HDR标志,表示内核会自己使用之前记录的头信息,这样就不用打补丁了。);从这个方法可以看出,
        image中最后一个进程必须是init,它的信息同时也会告诉FS;
    9.  准备一个内存sector的内核启动参数数据,调用minix()方法,启动minix内核。
        内核启动参数数据来自与boot monitor的环境变量。
    10. 如果minix函数返回,代表内核推出了,此时,回到boot monitor,继续接收用户的输入。内核可以通过
        传入内核的内存sector来向boot monitor传递内核退出后要执行的boot monitor的命令。
* minix()
    这是个在bootheader.s中定义的汇编方法。它的参数是:内核入口地址、内核代码段地址、内核数据段
地址、内核参数、内核参数大小、启动image中image header的副本起始地址。
    该函数主要做几件事情:
    1.  关闭软硬盘;
    2.  如果内核设置了可以返回到boot monitor的标志,准备好返回地址;
    3.  将CPU由实模式切换到保护模式;
    4.  在保护模式下调用内核的入口点;
    由此,控制权交给了minix的内核。
        
** 几个数据结构说明
*** struct process
    该结构体主要用于保存一个进程加载到内存后的几个关键地址。例如,入口地址、代码段、数据段等。
从process数组的大小可以看出,image中最多有16个进程。
*** struct image_header
    该结构体是头信息,在minix启动映像中的每个进程(包括内核)都有一个这样的头。在Image中,第一个
部分必须是Kernel,第三个部分必须是FS。

    至此,内核启动之前的所有工作就做完了,控制权也交给了内核。

阅读(3742) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~