加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

linux内核初始化init(main.c)

(2014-03-27 11:19:43)
标签:

linux

内核初始化

main.c

it

分类: LINUX

main.c将进行进一步初始化工作。主要方面:分配主内存功能,IDT表各中断描述符重新设定,对内核其它模块如mm,fs进行初始化,然后移到用户模式下生成进程1执行init,常驻进程0死循环执行pause。进程init加载根文件系统,设置终端标准IO,创建进程2/etc/rc为标准输入文件执行shell.完成rc文件中的命令。

init等进程2退出,进入死循环:创建子进程,建立新会话,设置标准IO终端,以登录方式执行shell.

至此系统动作起来了。

 

所以整个系统的建立起来后除了两个死循环的进程idleinit,其它的动作都是由用户在shell下执行命令,产生系统调用来工作的。

通过执行move_to_usermdoe()idleinit进程都属于用户态下的进程。而内核则完全是中断驱动的。也就是说只有通过中断才能进入系统,如时钟和系统调用等。

 

所以问题的重点就在于内核各部分数据结构的建立、初始化、操作是怎样进行的。这些初始化流程涉及到内核各个模块全部重要的数据结构。

现在从main执行的一系列初始化代码来浅窥一下:

1.根据内存的大小,设置高速缓冲的末端。16M内存把高速缓冲末端设为4M。缓冲末端到主存末端为主内存区。

2.mem_init(main_memory_start,memory_end);主内存区初始化

 设置高端内存HIGH_MEMORY=memory_end,

 设置内存映射字节图mem_map [ PAGING_PAGES ],将不可用的全部置为USED,可用的置为0mem_map数组是系统mm模块核心数据结构,记载了每个内存页使用计数。

3.trap_init().硬件中断向量表设置。

  IDT中填充各个中断描述符,使其指向对应的中断处理程序。对于错误,基本是结束当前进程。其他如外设中断都是各个模块初始化的时候向IDT表中相应项进行设置。

4.blk_dev_init();     // 块设备初始化。

       初始化请求数组request[],将所有请求项置为空闲项(dev = -1)

5.chr_dev_init();    // 字符设备初始化。尚为空操作。

6.tty_init();            // tty 初始化。                    

       /// tty 终端初始化函数。                                                 

       // 初始化串口终端和控制台终端。                                          

       void tty_init (void)                                                     

       { 

              rs_init ();                   // 初始化串行中断程序和串行接口1 2(serial.c, 37)   

              con_init ();                   // 初始化控制台终端。(console.c, 617)                

       }

       rs_init 初始化两个串口,安装串口中断处理IDT项。

       con_init 初始化显示器和键盘。安装键盘中断处理IDT项。                                                                 

7.time_init().CMOS 时钟,并设置开机时间 startup_time(为从1970-1-1-0 时起到开机时的秒数)

8.sched_init(); // 调度程序初始化(加载了任务0 tr, ldtr)

 这里初始化与进程调度有关的数据结构。

 手工设置了任务0TSSLDTGDT表中。

 GDT表和task[NR_TASKS]数组其余部分。

 ltr (0);                 // 将任务0 TSS 加载到任务寄存器tr

lldt (0);                // 将局部描述符表加载到局部描述符表寄存器。

设置内核的工作心跳--8253定时器,安装定时器中断。

设置系统调用中断门:set_system_gate (0x80, &system_call);

9.buffer_init(buffer_memory_end);// 缓冲管理初始化,建内存链表等。

  在内核的结束地址end(由连接程序生成)buffer_memory_end之间(除掉640kb-1MBIOS范围)区域中,建立缓冲区链表(表头start_buffer)并分配缓冲块(1KB)

  初始化空闲表free_listHASHhash_table

10.hd_init();// 硬盘初始化。

 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; //设置硬盘的设备请求函数为do_hd_request.

 设置硬盘中断处理IDT项。

11.floppy_init();//软盘初始化。

       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;

       设置软盘中断处理IDT项。

12.sti()开中断。

13.move_to_user_mode();移动到用户态执行。

这是个宏。由嵌入汇编代码组成。设置内核堆栈中的CS为任务0代码段(用户态),通过中断返回iret, 自动加载了LDT0的代码段到CS,数据段到SSDS等,完成了从特权级从0跳到3。其实执行的代码在内存中的位置完全相同。只是完成执行权跳到用户态而已。这样,内核执行变成了任务0的执行。

14.fork();生成进程1,执行init();

这里的fork()是内联函数。为了不使用用户栈。

进程0从此死循环执行pause();

15 init();

进程1执行init()函数。

调用setup取硬盘分区信息hd.加载虚拟盘,进程init加载根文件系统,设置终端标准IO,创建进程2/etc/rc为标准输入文件执行shell.完成rc文件中的命令。加载完根文件系统之后,整个OS就已经完整地运行起来了。

init等进程2退出,进入死循环:创建子进程,建立新会话,设置标准IO终端,以登录方式执行shell.,剩下的动作由用户来决定了。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有