LINUX0.11 main 函数中traps_init()作用研究

 

LINUX0.11 main 函数中traps_init()作用研究

 

目的:研究linux0.11系统初始化时,执行traps_init()函数后,相关的捕获函数如何与中断表述符表进行关联?

 

试验环境:linux-0.11-devel-050518 (oldlinux网站上可以下载)。其中包括bochs虚拟机,和带编译环境的linux0.11操作系统。运行linux-0.11-devel-050518中的bochsrc-hd.bxrc文件,

即可以在bochs中运行linux0.11系统,该系统中已经将linux0.11的内核进行了编译,生成的文件放在usr/src/linux/boot, usr/src/linux/kernel等目录下。

 

资料准备:1、上面系统中已经编译好的bootsect,setup,head.o文件。

          2、改写main.c traps.c,改写的文件如下:

main.c

 

 long user_stack[2048];

struct

{

  long *a;

  short b;

}stack_start = {&user_stack[2048], 0x10};

 

void main(void)            

{                

       trap_init();

 

       for(;;)

       {

       ;

       }

}

 

int printk(const char *fmt, ...)

{

 

       return 0;

}

 

traps.c

 

typedef struct desc_struct

{                  

  unsigned long a, b;           

}desc_table[256];

 

extern desc_table idt;    

#define move_to_user_mode() /

__asm__ ("movl %%esp,%%eax/n/t" /

       "pushl $0x17/n/t" /

       "pushl %%eax/n/t" /

       "pushfl/n/t" /

       "pushl $0x0f/n/t" /

       "pushl $1f/n/t" /

       "iret/n" /

       "1:/tmovl $0x17,%%eax/n/t" /

       "movw %%ax,%%ds/n/t" /

       "movw %%ax,%%es/n/t" /

       "movw %%ax,%%fs/n/t" /

       "movw %%ax,%%gs" /

       :::"ax")

 

#define sti() __asm__ ("sti"::)

#define cli() __asm__ ("cli"::)

#define nop() __asm__ ("nop"::)

 

#define iret() __asm__ ("iret"::)

 

#define _set_gate(gate_addr,type,dpl,addr) /

__asm__ ("movw %%dx,%%ax/n/t" /

       "movw %0,%%dx/n/t" /

       "movl %%eax,%1/n/t" /

       "movl %%edx,%2" /

       : /

       : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), /

       "o" (*((char *) (gate_addr))), /

       "o" (*(4+(char *) (gate_addr))), /

       "d" ((char *) (addr)),"a" (0x00080000))

 

#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)

 

#define _set_seg_desc(gate_addr,type,dpl,base,limit) {/

       *(gate_addr) = ((base) & 0xff000000) | /

              (((base) & 0x00ff0000)>>16) | /

              ((limit) & 0xf0000) | /

              ((dpl)<<13) | /

              (0x00408000) | /

              ((type)<<8); /

       *((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | /

              ((limit) & 0x0ffff); }

 

#define _set_tssldt_desc(n,addr,type) /

__asm__ ("movw $104,%1/n/t" /

       "movw %%ax,%2/n/t" /

       "rorl $16,%%eax/n/t" /

       "movb %%al,%3/n/t" /

       "movb $" type ",%4/n/t" /

       "movb $0x00,%5/n/t" /

       "movb %%ah,%6/n/t" /

       "rorl $16,%%eax" /

       ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), /

        "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) /

       )

 

#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89")

#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x82")

 

#define get_seg_byte(seg,addr) ({ /

register char __res; /

__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" /

       :"=a" (__res):"0" (seg),"m" (*(addr))); /

__res;})

 

#define get_seg_long(seg,addr) ({ /

register unsigned long __res; /

__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" /

       :"=a" (__res):"0" (seg),"m" (*(addr))); /

__res;})

 

#define _fs() ({ /

register unsigned short __res; /

__asm__("mov %%fs,%%ax":"=a" (__res):); /

__res;})

 

 

void divide_error(void)

{    

;

}

 

static void die(char * str,long esp_ptr,long nr)

{

       ;

}

 

void do_divide_error(long esp, long error_code)

{

       die("divide error",esp,error_code);

}

 

void trap_init(void)

{

       set_trap_gate(0,&divide_error);

}

 

3、已经制作好的build工具。

 

下面进行研究:

第一步:编译main.c traps.c文件,链接head.o ,main.o,traps.o文件

 

 

第二步:将system.map导出,为后续分析作准备。

system.map

Allocating common _user_stack: 2000 at 7008

 

Files:

 

  head.o text 0(64b8), data 7000(0), bss 7008(0) hex

  main.o text 64b8(1c), data 7000(8), bss 7008(0) hex

  traps.o text 64d4(58), data 7008(0), bss 7008(0) hex

 

Global symbols:

 

  _tmp_floppy_area: 0x5000

  _stack_start: 0x7000

  __edata: 0x7008

  _pg_dir: 0x0

  _printk: 0x64c8

  __etext: 0x7000

  _divide_error: 0x64d4

  _user_stack: 0x7008

  _do_divide_error: 0x64f0

  __end: 0x9008

  _etext: 0x7000

  _trap_init: 0x6508

  _main: 0x64b8

  _edata: 0x7008

  _end: 0x9008

  _gdt: 0x5cb8

  _idt: 0x54b8

 

Local symbols of head.o:

 

  startup_32: 0x0

  setup_idt: 0x6f

  setup_gdt: 0x9f

  check_x87: 0x5a

  after_page_tables: 0x5400

  ignore_int: 0x5428

  rp_sidt: 0x8c

  idt_descr: 0x54aa

  gdt_descr: 0x54b2

  pg0: 0x1000

  pg1: 0x2000

  pg2: 0x3000

  pg3: 0x4000

  setup_paging: 0x5450

  int_msg: 0x5414

 

Local symbols of main.o:

 

  gcc_compiled.: 0x64b8

 

Local symbols of traps.o:

 

  gcc_compiled.: 0x64d4

  _die: 0x64dc

 

第三步:使用build工具将相关文件buildimage文件,该文件可以算操作系统文件。

 

 

 

第四步:将生成的iamge文件以写磁盘命令写到软盘中,制成系统盘。

 

 

 

下面回到主题:研究linux0.11系统初始化时,执行traps_init()函数后,相关的捕获函数如何与中断表述符表进行关联?

 

基础知识准备:

中断描述符表的建立:

中断描述符表(IDT)的创建代码在boot/head.s中,与全局描述符表的创建类似,内核执行lidt idt_descr指令完成创建工作,全局变量idt_descr的定义如下:

idt_descr:

       .word 256*8-1            # idt contains 256 entries

       .long _idt

_idt: .fill 256,8,0           # idt is uninitialized

 

lidt指令为6字节操作数,它将_idt的地址加载进idtr寄存器,IDT被设置为包含2568字节表项的描述符表。

 

中断描述符表的初始化工作主要通过宏_set_get来完成,它定义于traps.如下:

#define _set_gate(gate_addr,type,dpl,addr) /

__asm__ ("movw %%dx,%%ax/n/t" /

       "movw %0,%%dx/n/t" /

       "movl %%eax,%1/n/t" /

       "movl %%edx,%2" /

       : /

       : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), /

       "o" (*((char *) (gate_addr))), /

       "o" (*(4+(char *) (gate_addr))), /

       "d" ((char *) (addr)),"a" (0x00080000))

/*设置中断门函数,特权级0,类型386中断门*/

#define set_intr_gate(n,addr) /

       _set_gate(&idt[n],14,0,addr)

/*设置陷阱门函数,特权级0,类型386陷阱门*/

#define set_trap_gate(n,addr) /

       _set_gate(&idt[n],15,0,addr)

/*设置系统调用函数,特权级3,类型386陷阱门*/

#define set_system_gate(n,addr) /

_set_gate(&idt[n],15,3,addr)

内核将用这些宏初始化IDT表,代码如下:

  set_trap_gate(0,&divide_error);

每个中断向量号具体意义这里不做说明,有兴趣的同志可以参考清华大学出版社出版的《保护方式下的80386及其编程》和赵炯博士的《Linux内核完全注释》;中断调用的具体过程将在后面的例子中详细分析。现在我们关心的是初始化完毕的IDT,调试查看这张表的内容,选取0x0号中断作为例子。通过查看System.map文件可知:0x0号中断调用的divide_error函数地址为_divide_error: 0x64d4Map文件中_trap_init: 0x6508,因此我们在_trap_ini函数地址0x6508处设置断点,启动bochsdgb进行调试,命令行如下:

 

 

 

 

 

 

 

 

门描述符具有如下形式:

 

 

因此调试信息显示,0x0号中断描述符中断调用地址为0x0008:0x000064d4,是一个特权级为0386陷阱门,这和在system.map_divide_error: 0x64d4一致。

 

 

注:以上分析参考了《实例分析Linux0.11内核中断机制 》这篇文章。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值