linux0.12之main.c的工作流程分析

之前分析了head.s到main.c的跳转,下面看看mian.c的工作流程分析。
boot之后的执行代码是init目录下的main.c,执行初始化任务。研究一下
linus一开头就给出了四个内联静态函数

static inline _syscall0(int,fork)
static inline _syscall0(int,pause)
static inline _syscall1(int,setup,void *,BIOS)
static inline _syscall0(int,sync)

这个宏定义在include/unistd.h中

#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
 : "=a" (__res) \
 : "0" (__NR_##name)); \
if (__res >= 0) \
 return (type) __res; \
errno = -__res; \
return -1; \
}

将第一个函数宏展开

_syscall0(int,fork)=>
int fork(void)
{
    long __res;
    __asm__ volatile ("int $0x80" \
                        :"=a"(__res)\
                        :"0"(__NR_fork));\
    if(__res>=0) \
        return (int) __res;\
    errno = -__res;\
    return -1;\
}

从main函数开始分析
1、
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
完成了根文件系统的设备号的一些问题,先跳过分析
2、

memory_end = (1<<20) + (EXT_MEM_K<<10);
 memory_end &= 0xfffff000;
 if (memory_end > 16*1024*1024)
  memory_end = 16*1024*1024;
 if (memory_end > 12*1024*1024) 
  buffer_memory_end = 4*1024*1024;
 else if (memory_end > 6*1024*1024)
  buffer_memory_end = 2*1024*1024;
 else
  buffer_memory_end = 1*1024*1024;
 main_memory_start = buffer_memory_end;

根据机器物理内存设置高速缓存区和主内存区的位置和范围
其中

#define EXT_MEM_K (*(unsigned short *)0x90002)

关于物理内存大小呀、扩展大小呀,都是在setup阶段获取的,并将这些参数存储在0x90000开始的内存中
Setup 程序读取并保留的参数
—————————————————————————-
内存地址 长度(字节) 名称描述
—————————————————————————-
0x90000 2 光标位置列号(0x00-最左端),行号(0x00-最顶端)
0x90002 2 扩展内存数系统从1M 开始的扩展内存数值(KB)。
0x90004 2 显示页面当前显示页面
0x90006 1 显示模式
0x90007 1 字符列数
0x90008 2 ??
0x9000A 1 显示内存显示内存(0x00-64k,0x01-128k,0x02-192k,0x03=256k)
0x9000B 1 显示状态0x00-彩色,I/O=0x3dX;0x11-单色,I/O=0x3bX
0x9000C 2 特性参数显示卡特性参数
0x90080 16 硬盘参数表第1 个硬盘的参数表
0x90090 16 硬盘参数表第2 个硬盘的参数表(如果没有,则清零)
0x901FC 2 根设备号根文件系统所在的设备号(bootsec.s 中设置)
—————————————————————————-
从上表中可以看出,取两个字节为扩展内存数
memory_end = (1<<20) + (EXT_MEM_K<<10);
因为内核代码段(内存)映射到从物理内存地址0开始,所以可以根据内存大小获取内存开始和结束地址
1<<20 为1M,EXT_MEM_K<<10为从地址0开始EXT_MEM_K大小的结束地址,全部转换成字节。
memory_end &= 0xfffff000;
0xfff是4k大小,即将不满4k的忽略
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
16×1024×1024为16M,内存大小大于16M的也忽略,所以在linux0.12使用时,最大支持的内存就是16M,大于这个内存也不起作用
if (memory_end > 12*1024*1024)
buffer_memory_end = 4*1024*1024;
else if (memory_end > 6*1024*1024)
buffer_memory_end = 2*1024*1024;
else
buffer_memory_end = 1*1024*1024;
完成名为buffer内存区的设置,根据总内存的大小来进行分配
main_memory_start = buffer_memory_end;
在buffer内存区之后全部为main的缓存区。
到这里看看linus把内存区怎么去规划的
这里写图片描述
在这里linus还没有给虚拟盘划分空间

#ifdef RAMDISK
 main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif

这里使用条件编译,为虚拟盘在主内存中划分空间。
在kernel/blk_drv/ramdisk.c中Written by Theodore Ts’o给出了这个函数

/*
 * Returns amount of memory which needs to be reserved.
 */
long rd_init(long mem_start, int length)
{
 int    i;
 char   *cp;

 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 rd_start = (char *) mem_start;
 rd_length = length;
 cp = rd_start;
 for (i=0; i < length; i++)
  *cp++ = '\0';
 return(length);
}

这里关于blk_dev暂不讨论,这个函数两个功能,初始化更虚拟盘相关的参数,并返回虚拟盘占用的字节数,将main的内存区后移。
3、

 mem_init(main_memory_start,memory_end);
 trap_init();
 blk_dev_init();
 chr_dev_init();
 tty_init();
 time_init();
 sched_init();
 buffer_init(buffer_memory_end);
 hd_init();
 floppy_init();
 sti();

【为此研究一下内核内存管理部分的内容,看看mem_init做了些什么,见另一篇文章】
第二个初始化,块设备初始化
第三个初始化,字符设备初始化
第四个初始化,tty初始化
第五个初始化,设置开机启动时间
第六个初始化,调度程序初始化
第七个初始化,缓冲管理初始化
第八个初始化,硬盘初始化
第九个初始化,软驱初始化
第十个为开启中断
【上面每个会有一篇文章作为说明,这里暂不讨论】
4、
move_to_user_mode();
移到用户模式下执行。
5、

 if (!fork()) {  /* we count on this going ok */
  init();
 }

具体怎么进行fork暂不研究,init的主要任务就是对将要执行shell环境初始化,并执行shell
6、
for(;;) pause();
main会在此循环,这是任务0,永不停息
大致总结一下mian.c的工作,后面文章会详细说明
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值