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

全部博文(104)

文章存档

2013年(1)

2012年(9)

2011年(41)

2010年(3)

2009年(3)

2008年(47)

分类: 系统运维

2011-01-20 10:47:20

    在前面的启动流程分析中已经看到,boot monitor将控制权交给了minix3的内核,从内核的entry处开始
执行,本文就是继续这个流程。

    内核中最先执行的代码是与体系结构相关的汇编代码,在386上,这部分代码包含在arch/i386/mpx.S中。
在这个文件中,定义了标签MINIX,这就是内核的入口点。我们看到,该标签后的第一条指令是jmp,它会跳过
后续的一些数据(这些数据就是给boot monitor用的,放在这里只是为了寻址方便)。
    这部分汇编代码主要做的工作包括:
* 设置内核栈
    为后面要调用的C代码(就是kernel任务的代码)设置好栈帧。boot monitor已经设置好了cs、ds,但是
并没有设置好栈,此时的栈仍然是monitor使用的16位的栈,ss也还指向monitor的数据段。
    1.  判断boot monitor是否设置好了minix退出时的返回地址,如果设置好了,将C的全局变量mon_return
        增加1(设置为真)。
    2.  将此时,也就是boot monitor的栈指针值保存在C全局变量mon_sp中;
    3.  将monitor的GDT表拷贝到内核空间的gdt表头部,后续内核保护模式初始化的prot_init()会使用。
    4.  将gdtr切换到内核的GDT表,此时,ds设置为内核的数据段。
    5.  保存monitor通过栈传递过来的参数:
        a.  将monitor保存的image中进程头信息数组的地址放在aout中;
        b.  内核的数据段的值设置给es, fs, gs, ss寄存器。
        c.  设置esp,此时,才真正设置好了C的执行栈。
        d.  将内核启动参数的地址、偏移量保存在C变量params_size,params_offset中,将monitor的数据
            段基值保存在mon_ds中。
    6.  调用C的初始化代码cstart(cs, ds, mds, params_offset, params_len)继续初始化环境;
        cstart()函数定义在kernel/start.c文件中,它用于在调用main()之前完成一些系统初始化,例如
        初始化kinfo中的信息,将启动参数拷贝到内核空间的缓冲区等,这些主要是把一些信息记录在全局
        的C变量中,方便后续的C代码访问。
        但是,该函数最重要的工作是初始化两个表:GDT和IDT,前者是i386保护模式的核心数据结构,后者
        是中断处理的核心数据结构。
    7.  重新加载GDT和IDT,并使用ljmp指令迫使新加载的这两个表其作用;
    8.  使用DS_SELECTOR初始化所有的数据、堆栈段寄存器,不再使用TSS;

* 调用main()
    如你所见,这确实是Minix3的真正的入口,定义在文件kernel/main.c中。

    该汇编代码文件的后面的部分定义了32位保护模式下的硬件中断处理入口、IPC入口、内核调用入口
、异常(软中断)处理入口,启动/重启一个进程的代码。这是些工具性质的汇编代码。
    汇编代码的最后是一些数据空间,此处就是预留的内核栈空间。

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