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了,下一篇继续。