代码路径:init/main.c
...
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
...
struct drive_info
{
char dummy[32];
} drive_info;
void main(void)
{
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
...
} 代码路径:fs/super.c
/* this is initialized in init/main.c */ int ROOT_DEV = 0;
参考此图,可知ROOT_DEV存的2个字节(unsigned short)的根设备号,定义在fs/super.c,29行,这个值为0。drive_info填充了32个字节的硬盘参数。
预备知识
<<20 或 >>20 相当于乘或除以 1 MB, <<12 或 >>12 相当于乘或除以 4 KB(联想到页), <<10 或 >>10 相当于乘或除以 1 KB
代码路径:init/main.c
...
#define EXT_MEM_K (*(unsigned short *)0x90002) //从1MB开始的扩展内存(KB)数
...
void main(void)
{
...
memory_end = (1<<20) + (EXT_MEM_K<<10); //1MB+扩展内存(MB),即内存总数
memory_end &= 0xfffff000; //// 按页的倍数取整,忽略内存末端不足一页的部分
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024; //执行到此,memory_end为16MB
if (memory_end > 12*1024*1024)
buffer_memory_end = 4*1024*1024;//执行到此,buffer_memory_end为4MB
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;//执行到此,main_memory_start为4MB
...
} 如下图所示,主内存结束(memory_end)为0xFFFFFF,主内存开始(main_memory_start)此时为0x3FFFFF,高速缓冲区末端(buffer_memory_end)为0x3FFFFF。此时还没有虚拟盘。
代码路径:init/main.c
void main(void)
{
...
#ifdef RAMDISK
main_memory_start += rd_init(main_memory_start, RAMDISK*1024);//主内存从0x5FFFFF开始
#endif
...
} 代码路径:kernel/blk_drv/ll_rw_blk.c
...
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 */
};
... 代码路径:kernel/blk_drv/blk.h
...
#define NR_BLK_DEV 7
...
struct blk_dev_struct {
void (*request_fn)(void);
struct request * current_request;
};
...
#if (MAJOR_NR== 1)
...
#define DEVICE_REQUEST do_rd_request
... 代码路径:kernel/blk_drv/ramdisk.c
...
#define MAJOR_NR 1
...
char *rd_start;
int rd_length = 0;
...
long rd_init(long mem_start, int length)
{
int i;
char *cp;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;//内核能够通过调用 do_rd_request 函数处理与虚拟盘相关的请求项操作
rd_start = (char *) mem_start;
rd_length = length;
cp = rd_start; //从0x3FFFFF开始
for (i=0; i < length; i++)//共2MB
*cp++ = ‘\0‘; //0x3FFFFF~0x5FFFFF都是虚拟盘
return(length);
}
如上图所示,主内存结束(memory_end)为0xFFFFFF,主内存开始(main_memory_start)此时为0x5FFFFF,高速缓冲区末端(buffer_memory_end)为0x3FFFFF,虚拟盘从0x3FFFFF~0x5FFFFF。
代码路径:init/main.c
void main(void)
{
...
mem_init(main_memory_start,memory_end);
...
} 代码路径:mm/memory.c
...
#define LOW_MEM 0x100000 //1 MB
#define PAGING_MEMORY (15*1024*1024)
#define PAGING_PAGES (PAGING_MEMORY>>12) //15 MB 的页数
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
#define USED 100
...
static long HIGH_MEMORY= 0;
...
static unsigned char mem_map [PAGING_PAGES]= {0,};
...
void mem_init(long start_mem, long end_mem)
{
int i;
HIGH_MEMORY= end_mem;
for (i=0;i<PAGING_PAGES;i++)
mem_map[i]= USED; //所有的页都设置为USED
i= MAP_NR(start_mem); //虚拟盘开始的页标
end_mem -= start_mem;
end_mem >>= 12; //虚拟盘后总共的页数
while (end_mem-->0)
mem_map[i++]=0; //虚拟盘后所有的页设置为空闲
} 形成的结果,如下图所示:
代码路径:init/main.c
void main(void)
{
...
trap_init();
...
} 代码路径:kernel/traps.c
void trap_init(void)
{
int i;
set_trap_gate(0,÷_error);// 除零错误
set_trap_gate(1,&debug); // 单步调试
set_trap_gate(2,&nmi); // 不可屏蔽中断
set_system_gate(3,&int3); /* int3-5 can be called from all */
set_system_gate(4,&overflow); // 溢出
set_system_gate(5,&bounds); // 边界检查错误
set_trap_gate(6,&invalid_op); // 无效指令
第 2 章 设备环境初始化及激活进程 0 53
set_trap_gate(7,&device_not_available); // 无效设备
set_trap_gate(8,&double_fault); // 双故障
set_trap_gate(9,&coprocessor_segment_overrun);// 协处理器段越界
set_trap_gate(10,&invalid_TSS); // 无效 TSS
set_trap_gate(11,&segment_not_present); // 段不存在
set_trap_gate(12,&stack_segment); // 栈异常
set_trap_gate(13,&general_protection); // 一般性保护异常
set_trap_gate(14,&page_fault); // 缺页
set_trap_gate(15,&reserved); // 保留
set_trap_gate(16,&coprocessor_error); // 协处理器错误
for (i=17;i<48;i++) // 都先挂接好,中断服务程序函数名初
// 始化为保留
set_trap_gate(i,&reserved);
set_trap_gate(45,&irq13); // 协处理器
outb_p(inb_p(0x21)&0xfb,0x21); // 允许 IRQ2 中断请求
outb(inb_p(0xA1)&0xdf,0xA1); // 允许 IRQ13 中断请求
set_trap_gate(39,?llel_interrupt); // 并口
}
代码路径:include\asm\system.h
...
#define _set_gate(gate_addr,type,dpl,addr) __asm__("movw %%dx,%%ax\n\t" \ // 将 edx 的低字赋值给 eax 的低字
"movw %0,%%dx\n\t" \ //%0 对应第二个冒号后的第 1 行的 "i"
"movl %%eax,%1\n\t" \ //%1 对应第二个冒号后的第 2 行的 "o"
"movl %%edx,%2" \ //%2 对应第二个冒号后的第 3 行的 "o"
: \ // 这个冒号后面是输出,下面冒号后面
// 是输入
: "i" ((short) (0x8000 + (dpl<<13) + (type<<8))), \ // 立即数
"o" (*((char *) (gate_addr))), \ // 中断描述符前 4 个字节的地址
"o" (*(4 + (char *) (gate_addr))), \ // 中断描述符后 4 个字节的地址
"d" ((char *) (addr)),"a" (0x00080000)) //"d" 对应 edx,"a" 对应 eax
...
#define set_intr_gate(n,addr) _set_gate(&idt[n],14,0,addr)
#define set_trap_gate(n,addr) _set_gate(&idt[n],15,0,addr)
#define set_system_gate(n,addr) _set_gate(&idt[n],15,3,addr) 首先看下图
Selector为0x0008,Offset为中断函数的偏移。set_trap_gate,P为1,DPL为00,TYPE为F。set_intr_gate,P为1,DPL为00,TYPE为E。set_system_gate,P为1,DPL为11,TYPE为F。
代码路径:init/main.c
void main(void)
{
...
blk_dev_init();
...
} 代码路径:kernel/blk_dev/blk.h
...
#define NR_REQUEST 32
struct request {
int dev; /* -1 if no request */
int cmd; /* READ or WRITE */
int errors;
unsigned long sector;
unsigned long nr_sectors;
char * buffer;
struct task_struct * waiting;
struct buffer_head * bh;
struct request * next; // 说明 request 可以构成链表
};
... 代码路径:kernel/blk_dev/ll_rw_block.c
...
struct request request[NR_REQUEST]; // 数组链表
...
void blk_dev_init(void)
{
int i;
for (i=0;i<NR_REQUEST;i++) {
request[i].dev= -1; // 设置为空闲
request[i].next= NULL; // 互不挂接
}
}
代码路径:init/main.c
void main(void)
{
...
tty_init();
...
} 代码路径:kernel/chr_dev/tty_io.c
void tty_init(void)
{
rs_init();
con_init()
}
代码路径:kernel/chr_dev/serial.c
void rs_init(void)
{
set_intr_gate(0x24,rs1_interrupt); // 设置串行口 1 中断,参看上图
set_intr_gate(0x23,rs2_interrupt); // 设置串行口 2 中断
init(tty_table[1].read_q.data); // 初始化串行口 1
init(tty_table[2].read_q.data); // 初始化串行口 2
outb(inb_p(0x21)&0xE7,0x21); // 允许 IRQ3,IRQ4
} 代码路径:kernel/chr_dev/console.c
...
void con_init(void)
{
...
set_trap_gate(0x21,&keyboard_interrupt);// 设置键盘中断,参看 2.5 节
outb_p(inb_p(0x21)&0xfd,0x21);// 允许 IRQ1
a=inb_p(0x61);
outb_p(a|0x80,0x61); // 禁止键盘工作
outb(a,0x61); // 再允许键盘工作
} 省略了很多初始化显示设备的工作,这部分主要是通过读0x90000~0x9000C的内容来初始化显示器,初始化完成后,原来的0x90000~0x901FE就没有用了,下面会被用作高速缓冲区。
代码路径:init/main.c
void main(void)
{
...
time_init();
...
} time_init()的代码省略,从机器中读取开机时间。
原文:http://blog.csdn.net/jltxgcy/article/details/19540305