博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux0.11内核之旅3——main.c(1)
阅读量:4612 次
发布时间:2019-06-09

本文共 5194 字,大约阅读时间需要 17 分钟。

init/main.c

首先我们贴上main.c中main函数的代码

void main(void)        /* This really IS void, no error here. */ {            /* The startup routine assumes (well, ...) this */ /*  * Interrupts are still disabled. Do necessary setups, then  * enable them */      ROOT_DEV = ORIG_ROOT_DEV;      drive_info = DRIVE_INFO;     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; #ifdef RAMDISK     main_memory_start += rd_init(main_memory_start, RAMDISK*1024); #endif     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();     move_to_user_mode(); if (!fork()) {        /* we count on this going ok */         init();     } /*  *   NOTE!!   For any other task 'pause()' would mean we have to get a  * signal to awaken, but task0 is the sole exception (see 'schedule()')  * as task 0 gets activated at every idle moment (when no other tasks  * can run). For task0 'pause()' just means we go check if some other  * task can run, and if not we return here. */ for(;;) pause(); }

 

 

我们从main.c的main函数开始读,首先是

ROOT_DEV = ORIG_ROOT_DEV;

我们可以追踪到:

#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)

在内核中有很多类似的宏,我们一层一层解释,首先(unsigned short *)0x901FC 说明这是一个指向unsigned short类型的指针,然后再对该指针解引用,所以ORIG_ROOT_DEV返回的应该是一个unsigned short,也就是两个字节,其内容是0x901FC地址处的内容。关于0x900000x901FF的内容请见下表(表摘自《Linux内核解释》----赵炯)

 

我们可以看出,0x901FC存放的是根设备号。

同理,main中的下一句:

drive_info = DRIVE_INFO;

我们查看一下DRIVE_INFO的定义:

#define DRIVE_INFO (*(struct drive_info *)0x90080)

因此,在drive_info中存储的是第一个硬盘的参数表。

我们继续看:

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;

这段

以下是对这段代码的详细注释:

首先我们看

memory_end = (1<<20) + (EXT_MEM_K<<10);

1 << 20: 1左移20位,得1MB

我们转到EXT_MEM_K的定义处:

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

通过查表,发现EXT_MEM_K存储的是系统从1MB开始的扩展内存数值,单位是KB,所以和以字节为单位的1MB相加时需要左移10位。

接下来是

 

memory_end &= 0xfffff000; // 忽略不到4KB(1页)的内存

 

继续

// 如果内存超过16MB,则按照16MB计算 // 因为在那个年代,内存如果超过16MB相当于你开了个加长奔驰。。。 if (memory_end > 16*1024*1024) memory_end = 16*1024*1024; // 如果内存大于12MB则缓冲区末端为4MB if (memory_end > 12*1024*1024) buffer_memory_end = 4*1024*1024; // 如果内存大于6MB则缓冲区末端为2MB else if (memory_end > 6*1024*1024) buffer_memory_end = 2*1024*1024; // 剩下的情况,也就是内存为0MB---6MB,则缓冲区末端为1MB else buffer_memory_end = 1*1024*1024; // 主内存起始地址 = 缓冲区末端 main_memory_start = buffer_memory_end;

 

如果定义了RAMDISK(虚拟磁盘),则主内存相应要减少,同时初始化虚拟磁盘

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

我们查看rd_init的定义:

/*  * 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是什么

/* blk_dev_struct is:  *    do_request-address  *    next-request */ struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
{ NULL, NULL }, /* no_dev */ { NULL, NULL }, /* dev mem */ { NULL, NULL }, /* dev fd */ { NULL, NULL }, /* dev hd */ { NULL, NULL }, /* dev ttyx */ { NULL, NULL }, /* dev tty */ { NULL, NULL } /* dev lp */ };

 

继续往深层走,我们可以看

struct blk_dev_struct {
void (*request_fn)(void); struct request * current_request; };

 

#define MAJOR_NR 1

 

#define DEVICE_REQUEST do_rd_request

 

do_rd_request函数:

void do_rd_request(void) {
int len; char *addr; INIT_REQUEST; addr = rd_start + (CURRENT->sector << 9); len = CURRENT->nr_sectors << 9; if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) {
end_request(0); goto repeat; } if (CURRENT-> cmd == WRITE) {
(void ) memcpy(addr, CURRENT->buffer, len); } else if (CURRENT->cmd == READ) {
(void) memcpy(CURRENT->buffer, addr, len); } else panic("unknown ramdisk-command"); end_request(1); goto repeat; }

 

我们发现,blk_dev_struct中只是包括两个指针,其中一个是函数指针,另一个是struct request指针,在这里,我们暂时不管这两个指针是做什么的。

 

但是我们基本上已经明白了

blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;

这句了,就是将blk_dev的索引为1的那项的reque_fn函数指针指向do_rd_request函数。好,我们不深究这个,继续。

让我们回到刚开始的rd_init函数,继续我们的分析:

rd_start = (char *) mem_start; rd_length = length;

 

没什么可说的,rd_startrd_length就是两个全局变量

cp = rd_start; for (i=0; i < length; i++) *cp++ = '\0'; return(length);

将虚拟磁盘处的内存全部初始化为0

OK,我们可以回到main.c了,下一篇继续。

转载于:https://www.cnblogs.com/xiaobo68688/archive/2011/12/24/2300711.html

你可能感兴趣的文章
我的2015---找寻真实的自己
查看>>
android编译遇到问题修改
查看>>
解决Ubuntu18.04.2远程桌面Xrdp登录蓝屏问题
查看>>
python_封装redis_hash方法
查看>>
Git的安装和使用教程详解
查看>>
lsof命令详解
查看>>
常用模块,异常处理
查看>>
父窗口与子窗口之间的传值
查看>>
eclipse 找不到 tomcat 的解决方案
查看>>
HDU 1890--Robotic Sort(Splay Tree)
查看>>
connection string for Excel/Access 2010
查看>>
【转】【Python】Python中的__init__.py与模块导入(from import 找不到模块的问题)
查看>>
学习wavenet_vocoder之环境配置
查看>>
常用Maven命令
查看>>
Docker启动mysql的坑2
查看>>
j2ee爬坑行之二 servlet
查看>>
JAVA基础入门(JDK、eclipse下载安装)
查看>>
最基础的applet运用--在applet上画线
查看>>
并不对劲的hdu4777
查看>>
linux使用rz、sz快速上传、下载文件
查看>>