1.1 set_trap_gate(0,& divide_error);函数干了些什么?
main --> trap_init -->set_trap_gate
上图出自《Orange's:一个操作系统的实现》于渊 P51
set_trap_gate(0,& divide_error);
set_trap_gate(n, addr);
_set_gate(&idt[n],15,0,addr)
_set_gate(gate_addr, type, dpl, addr);
-
#define _set_gate(gate_addr,type,dpl,addr) \
-
__asm__ ("movw %%dx,%%ax\n\t" \ -->edx是addr的全部地址,这儿只用了低16位
-
"movw %0,%%dx\n\t" \
-
"movl %%eax,%1\n\t" \ -->eax的低16位是addr的低16位,eax的高16位是选择子
-
"movl %%edx,%2" \ -->edx的低16位是属性,edx的高16位是addr的高16位
-
: \ -->movl一次移动4个字节,这样既填充了属性又填充了addr
-
: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ -->0x8000-->P=1 dpl偏移是13,type偏移是8
-
"o" (*((char *) (gate_addr))), \
-
"o" (*(4+(char *) (gate_addr))), \
-
"d" ((char *) (addr)),"a" (0x00080000))
edx=(char*)addr
eax=0x00080000
[0-3] -->0x00080000|(addr&0xFFFF)
[4-5] --> edx的低16位去填充属性
[6-7] --> edx的高16位去填充addr的高16位
都写到&idt[n]这个地方去了,idt是在head.s中分配了地址空间[0x54c0-0x5cc0] -->idt 2k
设置完如下图所示:
1.2 关于属性
type=0xE=1110=14 是中断门
type=0xF=1111=15 是陷阱门
CPL: Current Privilege Level
DPL: Descriptor Privilege Level
RPL: Requested Privilege Level
1.3 问题1: 这儿为什么是0x80000呢
上图出自《Orange's:一个操作系统的实现》 P32
8 --> 1000 --> 描述符索引是1, TI=0(GDT), RPL=0
TI是Table Indicator,指示TI=0选择子是在GDT中,TI=1选择子是在LDT中
1.4 问题2: 这儿选择子=1有什么作用?
看看下面的图就明白了
上图出自《Linux内核完全注释(修正版v3.0).pdf》 P116
a. 中断入口地址 = 段基址:偏移值
段基址是选择子中的段基址,偏移值是中断门描述符中的偏移
b. 在head.s中设置的选择子1是内核的代码段
gdt:
dq 0x0000000000000000
dq 0x00c09a0000000fff -->selector=1,即内核的代码段
00 c09a 000000 0fff -->段基址=0, 段界限=4096*0xFFF=16M
1.5 问题: 为什么set_trap_gate(0,& divide_error); 这儿要传 & divide_error?
感觉只要 divide_error 就够了, 为什么要多一个&?
a. 测试程序
从测试程序中可以看到 add = &add
b. 再加一点
从测试程序中可以看到 add = &add = *add
c. 反汇编看一下
add &add *add 反汇编后都是一个地址
我的理解是这样的:
编译器知道add是一个函数,那么就把 &add *add 都当add处理了.
1.6 C嵌入汇编
__asm__ ("assamble code":output : input : modify);
其中:
output 要加一个修饰符 =
a b c d D S -->eax ebx ecx edx edi esi
q --> 任意的4个通用寄存器(eax, ebx, ecx, edx)
r --> 任意的6个通用寄存器(eax, ebx, ecx, edx, esi, edi)
g --> 表示可放在任意的地方,可放寄存器,也可放内存
i --> 代表整数立即数
$ -->立即数前缀, $8代表数字8
阅读(1782) | 评论(0) | 转发(0) |