代码路径: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