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地址处的内容。关于0x90000到0x901FF的内容请见下表(表摘自《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_start和rd_length就是两个全局变量
cp = rd_start;
for (i=0; i < length; i++)
*cp++ = '\0';
return(length);
将虚拟磁盘处的内存全部初始化为0
OK,我们可以回到main.c了,下一篇继续。