亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

中斷——中斷描述符表的定義和初始化(一) (基于3.16-rc4)

2024-06-28 13:25:09
字體:
來源:轉載
供稿:網友
中斷——中斷描述符表的定義和初始化(一) (基于3.16-rc4)

1.中斷描述符表的定義(arch/x86/kernel/traps.c)

1 gate_desc debug_idt_table[NR_VECTORS] __page_aligned_bss;

定義的描述符表為一個結構體數組,數組元素類型為gate_desc,大小為8B。NR_VECTORS宏為256,即描述符表大小為256*8B。

2.idt_descr變量的定義(arch/x86/kernel/head_32.S)

1 idt_descr:2     .Word IDT_ENTRIES*8-1        # idt contains 256 entries3     .long idt_table4 5 # boot GDT descriptor (later on used by CPU#0):6     .word 0                # 32 bit align gdt_desc.address

這是內核定義的一個全局變量,存放有中斷描述符表的大小和首地址。該變量將存放在idtr寄存器中。

3.中斷描述符初步的初始化(arch/x86/kernel/head_32.S)

 1 __INIT 2 setup_once: 3     /* 4      * Set up a idt with 256 entries pointing to ignore_int, 5      * interrupt gates. It doesn't actually load idt - that needs 6      * to be done on each CPU. Interrupts are enabled elsewhere, 7      * when we can be relatively sure everything is ok. 8      */ 9 10     movl $idt_table,%edi11     movl $early_idt_handlers,%eax12     movl $NUM_EXCEPTION_VECTORS,%ecx13 1:14     movl %eax,(%edi)15     movl %eax,4(%edi)16     /* interrupt gate, dpl=0, PResent */17     movl $(0x8E000000 + __KERNEL_CS),2(%edi)18     addl $9,%eax19     addl $8,%edi20     loop 1b21 22     movl $256 - NUM_EXCEPTION_VECTORS,%ecx23     movl $ignore_int,%edx24     movl $(__KERNEL_CS << 16),%eax25     movw %dx,%ax        /* selector = 0x0010 = cs */26     movw $0x8E00,%dx    /* interrupt gate - dpl=0, present */27 2:28     movl %eax,(%edi)29     movl %edx,4(%edi)30     addl $8,%edi31     loop 2b32         ...33         ...

這段代碼是對中斷描述符表的初步初始化,14-20行是對前32個中斷描述符進行初始化,讓所有描述符指向early_idt_handlers處理函數。22-31行是對后256-32=224個中斷描述符進行初始化,使之指向ignore_int處理函數。省略號以后是對GDT描述符表的初始化,這里不予討論。

4.中斷描述符表最終的初始化(arch/x86/kernel/traps.c)

 1 void __init trap_init(void) 2 { 3     int i; 4  5 #ifdef CONFIG_EISA 6     void __iomem *p = early_ioremap(0x0FFFD9, 4); 7  8     if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) 9         EISA_bus = 1;10     early_iounmap(p, 4);11 #endif12 13     set_intr_gate(X86_TRAP_DE, divide_error);14     set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK);15     /* int4 can be called from all */16     set_system_intr_gate(X86_TRAP_OF, &overflow);17     set_intr_gate(X86_TRAP_BR, bounds);18     set_intr_gate(X86_TRAP_UD, invalid_op);19     set_intr_gate(X86_TRAP_NM, device_not_available);20 #ifdef CONFIG_X86_3221     set_task_gate(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS);22 #else23     set_intr_gate_ist(X86_TRAP_DF, &double_fault, DOUBLEFAULT_STACK);24 #endif25     set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun);26     set_intr_gate(X86_TRAP_TS, invalid_TSS);27     set_intr_gate(X86_TRAP_NP, segment_not_present);28     set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);29     set_intr_gate(X86_TRAP_GP, general_protection);30     set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug);31     set_intr_gate(X86_TRAP_MF, coprocessor_error);32     set_intr_gate(X86_TRAP_AC, alignment_check);33 #ifdef CONFIG_X86_MCE34     set_intr_gate_ist(X86_TRAP_MC, &machine_check, MCE_STACK);35 #endif36     set_intr_gate(X86_TRAP_XF, simd_coprocessor_error);37 38     /* Reserve all the builtin and the syscall vector: */39     for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)40         set_bit(i, used_vectors);41 42 #ifdef CONFIG_IA32_EMULATION43     set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);44     set_bit(IA32_SYSCALL_VECTOR, used_vectors);45 #endif46 47 #ifdef CONFIG_X86_3248     set_system_trap_gate(SYSCALL_VECTOR, &system_call);FIRST_EXTERNAL_VECTOR49     set_bit(SYSCALL_VECTOR, used_vectors);50 #endif51 52     /*53      * Set the IDT descriptor to a fixed read-only location, so that the54      * "sidt" instruction will not leak the location of the kernel, and55      * to defend the IDT against arbitrary memory write vulnerabilities.56      * It will be reloaded in cpu_init() */57     __set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);58     idt_descr.address = fix_to_virt(FIX_RO_IDT);59 60     /*61      * Should be a barrier for any external CPU state:62      */63     cpu_init();64 65     x86_init.irqs.trap_init();66 67 #ifdef CONFIG_X86_6468     memcpy(&debug_idt_table, &idt_table, IDT_ENTRIES * 16);69     set_nmi_gate(X86_TRAP_DB, &debug);70     set_nmi_gate(X86_TRAP_BP, &int3);71 #endif72 }

該函數對中斷描述表的進行了部分初始化,13-36行對系統已分配的異常和非屏蔽中斷進行初始化,中斷向量號為0-19。接著,39-40行在中斷位圖表中對已初始化的中斷所對應的位進行標記。接著,43和48行又出始化了兩個中斷,一個是系統中斷門,中斷向量號為0x80,一個是系統陷阱門,中斷向量號為2。

在該函數中,大家可以看出,對中斷進行初始化的函數有如下幾個:

1 set_intr_gate()2 set_system_intr_gate()3 set_system_trap_gate()4 set_task_gate()

這幾個函數也在arch/x86/kernel/traps.c中定義。分別是對中斷門,系統中斷門,系統陷阱門,任務門描述符的初始化。進一步深入可發現,這幾個函數都調用了如下的函數:

 1 static inline void _set_gate(int gate, unsigned type, void *addr, 2                  unsigned dpl, unsigned ist, unsigned seg) 3 { 4     gate_desc s; 5  6     pack_gate(&s, type, (unsigned long)addr, dpl, ist, seg); 7     /* 8      * does not need to be atomic because it is only done once at 9      * setup time10      */11     write_idt_entry(idt_table, gate, &s);12     write_trace_idt_entry(gate, &s);13 }

該函數定義在arch/x86/include/asm/desc.h文件中。在該函數中定義了一個gate_desc類型變量s,并將s的指針傳遞給pack_gate函數,把要初始化的描述符各個字段的值臨時存放在s中。下邊分析下pack_gate函數,在分析該函數之前,我們先看下gate_desc結構體。

 1 struct desc_struct { 2     union { 3         struct { 4             unsigned int a; 5             unsigned int b; 6         }; 7         struct { 8             u16 limit0; 9             u16 base0;10             unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;11             unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;12         };13     };14 } __attribute__((packed));typedef struct desc_struct gate_desc

該結構體定義位于arch/x86/include/asm/desc_defs.h中。該結構體中包含了一個共用體,共用體中又包含了兩個結構體。我們知道,共用體在分配內存單元時,并不為每個成員都分配,而是為最大的成員來分配??梢钥闯鲈摴灿皿w的兩個結構體成員大小相等,都是8B,因此整個gate_desc結構體大小就為8B。我們可以使用共用體中的任意一個結構體成員來為這個gate_desc賦值,也就是說我們既可以將gate_desc看成是struct { unsigned int a; unsigned int b; };也可以看成是struct {u16 limit0;u16 base0; .... };下面在分析pack_gate函數過程中將看到賦值過程,我們將gate_desc看作是struct { unsigned int a; unsigned int b; };。

1 static inline void pack_gate(gate_desc *gate, unsigned char type,2                  unsigned long base, unsigned dpl, unsigned flags,3                  unsigned short seg)4 {5     gate->a = (seg << 16) | (base & 0xffff);6     gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8);7 }

該函數也定義在arch/x86/include/asm/desc.h文件中。在該函數中為gate所指向的gate_desc描述符進行初始化。gate->a是描述符的0-31位,gate->b是描述符的32-63位。描述符的如下所示:

接著,我們分析_set_gate()中的11行,write_idt_entry()調用。

1 static inline void native_write_idt_entry(gate_desc *idt, int entry, const gate_desc *gate)2 {3     memcpy(&idt[entry], gate, sizeof(*gate));4 }#define write_idt_entry() native_write_idt_entry()  //粗略的寫了下,大家能明白就行 

該函數定義在arch/x86/include/asm/desc.h中。在該函數中,使用memcpy()函數將gate中的字段復制到&idt[entry]所指向的各個字段中。很顯然,idt[]數組就是內核中定義的中斷描述符表,我們在文章開頭給大家看過該定義。gate就是我們在_set_gate()中定義的臨時變量s,在這里我們將s中的字段值賦給idt[]數組的對應元素,至此一個描述符的初始化工作就全部完成了,s變量的用途也就結束了,另外,entry變量中存放的是要初始化的中斷向量號,用該號來定位idt數組的元素。

最后,再補充說明一點東西,回頭看下第4點中的trap_init()函數,在該函數中對中斷描述符表進行初始化,使用了很多初始化函數比如set_intr_gate()或set_system_intr_gate()等等,我們拿第一個初始化函數set_intr_gate(X86_TRAP_DE, divide_error)來做說明。X86_TRAP_DE是枚舉類型參數,代表的是中斷向量號,定義在arch/x86/include/asm/traps.h文件中。這種枚舉類型其實有很多。

 1 /* Interrupts/Exceptions */ 2 enum { 3     X86_TRAP_DE = 0,    /*  0, Divide-by-zero */ 4     X86_TRAP_DB,        /*  1, Debug */ 5     X86_TRAP_NMI,        /*  2, Non-maskable Interrupt */ 6     X86_TRAP_BP,        /*  3, Breakpoint */ 7     X86_TRAP_OF,        /*  4, Overflow */ 8     X86_TRAP_BR,        /*  5, Bound Range Exceeded */ 9     X86_TRAP_UD,        /*  6, Invalid Opcode */10     X86_TRAP_NM,        /*  7, Device Not Available */11     X86_TRAP_DF,        /*  8, Double Fault */12     X86_TRAP_OLD_MF,    /*  9, Coprocessor Segment Overrun */13     X86_TRAP_TS,        /* 10, Invalid TSS */14     X86_TRAP_NP,        /* 11, Segment Not Present */15     X86_TRAP_SS,        /* 12, Stack Segment Fault */16     X86_TRAP_GP,        /* 13, General Protection Fault */17     X86_TRAP_PF,        /* 14, Page Fault */18     X86_TRAP_SPURIOUS,    /* 15, Spurious Interrupt */19     X86_TRAP_MF,        /* 16, x87 Floating-Point Exception */20     X86_TRAP_AC,        /* 17, Alignment Check */21     X86_TRAP_MC,        /* 18, Machine Check */22     X86_TRAP_XF,        /* 19, SIMD Floating-Point Exception */23     X86_TRAP_IRET = 32,    /* 32, IRET Exception */24 };

第二個參數,是匯編函數的函數名(在這里作為函數指針來使用),該函數為內核原先就定義好的中斷或異常處理程序。這種類型的函數有很多,都定義在arch/x86/kernel/entry_32.S文件中,下邊我們列舉幾個給大家看看,有興趣自己去查。

 1 ENTRY(segment_not_present) 2     RING0_EC_FRAME 3     ASM_CLAC 4     pushl_cfi $do_segment_not_present 5     jmp error_code 6     CFI_ENDPROC 7 END(segment_not_present) 8  9 ENTRY(stack_segment)10     RING0_EC_FRAME11     ASM_CLAC12     pushl_cfi $do_stack_segment13     jmp error_code14     CFI_ENDPROC15 END(stack_segment)16 17 ENTRY(alignment_check)18     RING0_EC_FRAME19     ASM_CLAC20     pushl_cfi $do_alignment_check21     jmp error_code22     CFI_ENDPROC23 END(alignment_check)24 25 ENTRY(divide_error)26     RING0_INT_FRAME27     ASM_CLAC28     pushl_cfi $0            # no error code29     pushl_cfi $do_divide_error30     jmp error_code31     CFI_ENDPROC32 END(divide_error)

這些匯編代碼只是異常處理程序的開頭一部分,可以看到每一個匯編段中,都有一條pushl_cfi $do_***的指令,該$do_***才是真正的異常處理程序(函數名,也是函數指針),現將該函數名壓入棧中,然后通過jmp error_code指令跳轉到$do_***函數中。error_code其實也是一段匯編代碼,如下所示:

 1 error_code: 2     /* the function address is in %gs's slot on the stack */ 3     pushl_cfi %fs 4     /*CFI_REL_OFFSET fs, 0*/ 5     pushl_cfi %es 6     /*CFI_REL_OFFSET es, 0*/ 7     pushl_cfi %ds 8     /*CFI_REL_OFFSET ds, 0*/ 9     pushl_cfi %eax10     CFI_REL_OFFSET eax, 011     pushl_cfi %ebp12     CFI_REL_OFFSET ebp, 013     pushl_cfi %edi14     CFI_REL_OFFSET edi, 015     pushl_cfi %esi16     CFI_REL_OFFSET esi, 017     pushl_cfi %edx18     CFI_REL_OFFSET edx, 019     pushl_cfi %ecx20     CFI_REL_OFFSET ecx, 021     pushl_cfi %ebx22     CFI_REL_OFFSET ebx, 023     cld24     movl $(__KERNEL_PERCPU), %ecx25     movl %ecx, %fs26     UNWIND_ESPFIX_STACK27     GS_TO_REG %ecx28     movl PT_GS(%esp), %edi        # get the function address29     movl PT_ORIG_EAX(%esp), %edx    # get the error code30     movl $-1, PT_ORIG_EAX(%esp)    # no syscall to restart31     REG_TO_PTGS %ecx32     SET_KERNEL_GS %ecx33     movl $(__USER_DS), %ecx34     movl %ecx, %ds35     movl %ecx, %es36     TRACE_IRQS_OFF37     movl %esp,%eax            # pt_regs pointer38     call *%edi39     jmp ret_from_exception40     CFI_ENDPROC41 END(page_fault)

該片段來自arch/x86/kernel/entry_32.S文件中。代碼的開始部分3-22行,對寄存器進行壓棧操作,因為這些寄存器將要在隨后的異常處理程序中用到,所以事先要保存。最后可以看到在38行,執行了call %edi命令,調用了最終的異常處理程序,在28行可以看到將異常處理程序地址存入了edi寄存器中。第39行通過跳入ret_from_exception中,返回被中斷的進程。

至此,中斷描述符的初始化工作就告一段落。文中有問題的地方希望大家指正。QQ:1193533825


上一篇:rpm數字證書安裝

下一篇:GIT的使用

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲无av在线中文字幕| 一区二区三区视频免费| 亚洲国产精品久久久久秋霞蜜臀| 国产精品大陆在线观看| 日韩少妇与小伙激情| 中文字幕综合一区| 日韩亚洲在线观看| 国产成人精品视频在线观看| 亚洲精品久久久久中文字幕欢迎你| 亚洲一二三在线| 一区二区三区回区在观看免费视频| 在线日韩精品视频| 国产精品亚洲自拍| 欧美激情精品久久久久久变态| 精品久久久国产| 色偷偷噜噜噜亚洲男人的天堂| 91精品国产高清| 中文字幕日韩专区| 亚洲成人三级在线| 国产精品视频免费观看www| 久久国产精品视频| 日韩av综合网| 不卡伊人av在线播放| 日韩精品极品在线观看播放免费视频| 亚洲精品色婷婷福利天堂| 国产69精品久久久久9| 国产欧美日韩亚洲精品| 国产精品亚洲аv天堂网| 亚洲美女又黄又爽在线观看| 九色91av视频| 成人黄色午夜影院| 91精品久久久久久久| 国内精品免费午夜毛片| 久久亚洲精品中文字幕冲田杏梨| 粗暴蹂躏中文一区二区三区| 日韩av成人在线| www高清在线视频日韩欧美| 在线视频欧美性高潮| 亚洲国产精品嫩草影院久久| 亚洲综合日韩中文字幕v在线| 一本色道久久88亚洲综合88| 91影院在线免费观看视频| 乱亲女秽乱长久久久| 在线播放国产一区中文字幕剧情欧美| 国内精品小视频| 九九热在线精品视频| 福利一区福利二区微拍刺激| 91精品国产91久久久久久最新| 中文字幕亚洲无线码a| 91精品久久久久久久久久入口| 一区二区三区回区在观看免费视频| 亚洲欧美一区二区三区情侣bbw| 国产ts人妖一区二区三区| 久久久精品在线观看| 国产亚洲精品美女久久久久| 一色桃子一区二区| 日韩在线国产精品| 综合av色偷偷网| www.日韩不卡电影av| 国产精品你懂得| 超碰91人人草人人干| 日韩av影片在线观看| 日本中文字幕成人| 欧美电影免费观看高清| 成人国产亚洲精品a区天堂华泰| www.欧美精品一二三区| 久久精品中文字幕| 国产成人欧美在线观看| 一区二区欧美久久| 国产精品免费久久久| 国产小视频91| 久久福利视频导航| 精品国产91乱高清在线观看| 久青草国产97香蕉在线视频| 欧美一级片久久久久久久| 青青草一区二区| 国产精品视频播放| 欧美性猛交xxxxx免费看| 国产成人在线播放| 国产精品精品久久久久久| 91精品国产电影| 国产成人一区二区三区小说| 久久九九亚洲综合| 韩国19禁主播vip福利视频| 亚洲最大福利视频网| 欧美精品xxx| 国产精品偷伦视频免费观看国产| 国内精品视频在线| 久久久av网站| 欧美国产高跟鞋裸体秀xxxhd| 中文字幕日韩精品在线观看| 国产精品久久久久久久一区探花| 成年无码av片在线| 亚洲综合自拍一区| 午夜欧美不卡精品aaaaa| 国产精品96久久久久久又黄又硬| 精品视频在线播放色网色视频| 亚洲乱码av中文一区二区| 97久久伊人激情网| 91亚洲人电影| 欧美日韩国产综合视频在线观看中文| 久久夜色精品国产亚洲aⅴ| 国产精品久久久久久久久免费| 亚洲美女www午夜| 国产视频综合在线| 国产欧美一区二区三区久久人妖| 久久精品99国产精品酒店日本| 精品高清一区二区三区| 久久精品国产2020观看福利| 日韩中文av在线| 91九色国产视频| 久色乳综合思思在线视频| 欧美精品激情blacked18| 欧美小视频在线观看| 中文字幕亚洲色图| 久久久久久香蕉网| 国产精品久久久久久久久影视| 精品一区二区三区四区| 中文字幕自拍vr一区二区三区| 国产精品视频地址| 亚洲人成亚洲人成在线观看| 九九热99久久久国产盗摄| 国产成人激情视频| 亚洲欧美日韩中文视频| 国模视频一区二区三区| 欧美日韩国产一区在线| 欧美日本精品在线| 少妇激情综合网| 国产精品福利片| 国产精品青青在线观看爽香蕉| 日韩成人av网| 亚洲欧洲视频在线| 日韩精品一区二区视频| 亚洲男子天堂网| 成人信息集中地欧美| 91亚洲精品一区| 综合av色偷偷网| 国产精品爽黄69天堂a| 亚洲成人激情在线| 日本精品中文字幕| 日韩亚洲欧美中文在线| 亚洲福利在线播放| 欧美激情免费看| 亚洲精品短视频| 欧美夫妻性生活xx| 久久手机免费视频| 欧美激情视频在线免费观看 欧美视频免费一| 国产亚洲欧美一区| 2019日本中文字幕| 国产精品夫妻激情| 成人免费淫片视频软件| 91av视频在线| 精品爽片免费看久久| 亚洲第一综合天堂另类专| 久久久国产精彩视频美女艺术照福利| 懂色av中文一区二区三区天美| 日本久久久久久久| 亚洲视频精品在线| 热久久美女精品天天吊色| 国产精品嫩草影院久久久| 成人福利在线视频| 91夜夜未满十八勿入爽爽影院| 7777kkkk成人观看| 色99之美女主播在线视频|