随笔-80  评论-24  文章-0  trackbacks-0
终于跳转到main.c文件中的cbegin()函数执行了,这是从boot到loader再到内核,第一次执行c代码的地方。我们先看main.c都做了什么。

 1 #include <type.h>
 2 #include <asm/system.h>
 3 #include <winixj/clock.h>
 4 #include <winixj/mm.h>
 5 #include <winixj/hdd.h>
 6 #include <winixj/sys_call.h>
 7 #include <winixj/process.h>
 8 #include <getpid.h>
 9 
10 //指向在loader.s中保存的系统参数表
11 //包括显示卡参数、硬盘参数等等
12 void *sys_param = (void *)0xf0000;
13 volatile int cursor_pos = 0;
14 
15 
16 //这个函数是真正的第一个C函数,从_start函数中跳入
17 //最好将cbegin函数用volatile关键字修饰,这样做的好处
18 //是:用volatile修饰函数的话则是告诉gcc编译器该函数
19 //不返回(可能是函数内含有exit()或者死循环之类的),这样
20 //gcc在函数优化的时候就不会将返回值压入堆栈,这样,起到
21 //优化的作用,在cbegin中start_proc0()启动了第一个init进程
22 //下面的for循环永远不可能执行到,就算执行到那cbegin()也不会
23 //返回
24 void cbegin()
25 {
26     //初始化系统调用,包括将0x30号中断与自陷框架sys_call函数挂钩
27     //以及安装对用系统调用号的中断入口函数
28     init_sys_call();
29     //初始化proc_list进程链表以及对init和sys进程进行初始化
30     init_proc_list();
31     //初始化心跳值为0,以及打开时钟中断、初始化开机时间等
32     init_clock();
33     init_mm();
34 
35     //这里调试了很久!!!!!!!!!!
36     //注意这里一定要开中断,因为当前中断是关闭的
37     //init_hd()中有涉及到硬盘中断的操作
38     //如果中断关闭那么将响应不到硬盘中断
39     sti();
40     init_hd();
41     cli();
42 
43     //启动第一个进程也即0号init进程
44     start_proc0();
45 
46     //下面的代码应该永远不会被执行,因为start_proc0()函数不会返回,
47     //start_proc0()函数执行完iretd命令后便启动了第一个init进程,
48     //自此系统便开始了多进程的运行
49     for(;;){}
50 }
51 
52 //proc0
53 //第一个进程
54 void init()
55 {
56     int i;
57     uint8 *= (uint8 *)(0xb8000);
58     *= (uint8)getpid() + '0';
59 
60     for(;;)
61     {
62         for ( i = 0; i < 1000000++i);
63 
64         if (*< '9')
65         {
66             *= ++(*p);
67         }
68     };
69 }
70 
71 //proc1
72 //第二个进程
73 void sys()
74 {
75     int i;
76     //这里由sys进程调用partition()系统调用来完成硬盘的初始化
77     //之所以在不在内核中完成硬盘的初始化是因为这里需要读取硬盘
78     //MBR的内容,而读取硬盘需要将当前进程睡眠,而内核是不允许
79     //睡眠的,因此选择在sys进程中初始化硬盘
80     //这里的工作包括获取硬盘柱面、柱头、磁道、每磁道扇区数等的
81     //信息
82     uint8 *= (uint8 *)(0xb8002);
83     *= (uint8)getpid() + '0';
84 
85     for(;;)
86     {
87         for ( i = 0; i < 1000000++i);
88 
89         if (*< '9')
90         {
91             *= ++(*p);
92         }
93     };
94 }
95 

代码量并不多,但是完成的事情其实并不少,主要的函数以及功能如下:
1、init_sys_call 初始化系统调用
2、init_proc_list 初始化进程控制块数组
3、init_clock 初始化时钟中断
4、init_mm 初始化告诉缓冲区
5、init_hd 初始化硬盘及硬盘中断
6、start_proc0 启动第一个进程init进程
其中每一项功能的实现都不简单,之后的章节再一一详细论述。
这里有必要将内存分配的情况展示一下:
在boot执行过程中:
1、首先BIOS将自动从软盘第一扇区读取boot代码(共512B),然后将其加载到内存物理地址0x7c00处,开始执行第一条代码,boot开始执行。
2、我们的boot程序完成从软盘的第二个扇区开始将loader和kernel Image加载到物理地址0x80000开始的地方,然后便急切的跳转到0x80000地址处去执行loader。
3、loader此时开始执行,它首先分析kernel Image,将其各个段(包括若干代码段、数据段等)复制到内存合适的地址处(我们编译内核的时候指定了内核起始虚拟地址为0x0,由于我们的分段机制使得虚拟地址等于线性地址,所以内核开始执行时的线性地址也是0x0,又由于此时分页机制是地址对等映射,所以物理地址也同样是0x0,所以我们是将内核搬运到内存起始物理地址0x0开始运行的);然后从BIOS ROM区获取一些系统参数,将参数保存在物理地址0xf0000开始的地方;之后准备GDT,并填充适当的GDT描述符项,然后通过打开A20地址线和置cr0寄存器最后一位PE位为1来打开保护模式,然后跳转到保护模式运行;而进入保护模式之后loader什么也不干,毕竟我们想尽快的到内核世界去旅行,所以这里只简单的跳转到kernel去执行。
至此为止,boot运行完成时的内存分布如下:



而当loader执行完毕后的内存分布如下:



之后内存分布不会有太大的变化。
posted on 2012-02-14 13:01 myjfm 阅读(578) 评论(0)  编辑 收藏 引用 所属分类: 操作系统

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理