首页 > 其他 > 详细

Linux内核设计的艺术-设备环境初始化及激活进程0

时间:2014-02-21 03:49:02      阅读:453      评论:0      收藏:0      [点我收藏+]

      代码路径: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个字节的硬盘参数。

      bubuko.com,布布扣



       预备知识

<<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。此时还没有虚拟盘。

bubuko.com,布布扣

       bubuko.com,布布扣



       代码路径: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;                 //虚拟盘后所有的页设置为空闲      
}
      形成的结果,如下图所示:

   bubuko.com,布布扣



      代码路径: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)
       首先看下图

bubuko.com,布布扣bubuko.com,布布扣

  bubuko.com,布布扣

        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()的代码省略,从机器中读取开机时间。


          











    

Linux内核设计的艺术-设备环境初始化及激活进程0

原文:http://blog.csdn.net/jltxgcy/article/details/19540305

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!