Linux0.11内核之旅3——main.c(1)

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/p/2300711.html