擦!前几天光纤被搞断了,今天下午才来修好,没网络的日子很不爽啊。
前几天扯到哪了,哦,改用C来继续写第五章的内容了。上一篇搞定了GDT和内核栈的切换了,现在就来写8259A的设置和填充IDT的内容了。
设置8259A的话就是一堆out指令向相应的端口写一些命令字,当然只能用汇编了,不过也能用C来封装一下,哈哈。下面这个函数就是相应的封装:
- void Out_Byte(u16 port,u8 value);
-
- void Init_8259A()
- {
- Out_Byte(0x20,0x11);
- Out_Byte(0xa0,0x11);
-
- Out_Byte(0x21,0x20);
- Out_Byte(0xa1,0x28);
-
- Out_Byte(0x21,0x4);
- Out_Byte(0xa1,0x2);
-
- Out_Byte(0x21,0x1);
- Out_Byte(0xa1,0x1);
-
- Out_Byte(0x21,0xff);
- Out_Byte(0xa1,0xff);
- }
这个Out_Byte函数自然是用汇编写了:
Out_Byte:
push ebp
mov ebp,esp
push eax
push edx
mov edx,[ebp + 8]
mov eax,[ebp + 12]
out dx,al
pop edx
pop eax
pop ebp
ret
最后在C_Start中调用Init_8259A就完成对8259A的初始化了。
接下来就是建立IDT并把它加载到IDTR中,并且把对应的中断处理程序写好。
先把内中断的处理程序写好,由于有些中断没有错误码,有些有,而我们想最终用同一个函数来处理所有的内中断,所以在没有错误码的中断的压入一个值来保证统一。由下面的代码得知,每个中断处理程序还多压入了一个中断向量号。
Divide_Error:
push 0ffffffffh
push 0
jmp Exception
Single_Step_Exception:
push 0ffffffffh
push 1
jmp Exception
NMI:
push 0ffffffffh
push 2
jmp Exception
Breakpoint_Exception:
push 0ffffffffh
push 3
jmp Exception
Overflow:
push 0ffffffffh
push 4
jmp Exception
Bounds_Check:
push 0ffffffffh
push 5
jmp Exception
Inval_Opcode:
push 0ffffffffh
push 6
jmp Exception
Copr_Not_Available:
push 0ffffffffh
push 7
jmp Exception
Double_Fault:
push 8
jmp Exception
Copr_Seg_Overrun:
push 0ffffffffh
push 9
jmp Exception
Inval_TSS:
push 10
jmp Exception
Segment_Not_Present:
push 11
jmp Exception
Stack_Exception:
push 12
jmp Exception
General_Protection:
push 13
jmp Exception
Page_Fault:
push 14
jmp Exception
Copr_Error:
push 0ffffffffh
push 16
jmp Exception
Exception:
call Exception_Handler
add esp,8
hlt
我们看到,所有的内中断最终都调用了一个Exception_Handler的函数,这个函数是用C写的,这个函数把传进去的5个参数都打印出来:分别是中断向量号,错误码,发生错误的位置的eip,cs,eflags。
- void Disp_Color_Str(char *p_Str,u32 color);
- void Disp_Int(u32 num);
-
- void Exception_Handler(u32 vec_no,u32 err_code,u32 eip,u32 cs,int eflags)
- {
- int i;
-
- Disp_Pos = 0;
- for(i = 0 ; i < 80 * 5 ; i++)
- {
- Disp_Color_Str(" ",0xc);
- }
- Disp_Pos = 0;
-
- Disp_Color_Str("VEC_NO:",0xc);
- Disp_Int(vec_no);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("ERROR_CODE:",0xc);
- Disp_Int(err_code);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("CS:",0xc);
- Disp_Int(cs);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("EIP:",0xc);
- Disp_Int(eip);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("EFLAGS:",0xc);
- Disp_Int(eflags);
- Disp_Color_Str("/n",0xc);
- }
这个函数又调用了两个函数,Disp_Color_Str用汇编写的,Disp_Int则用C写的。
;Disp_Color_Str=======================================================
;函数原型:void Disp_Color_Str(char * pszStr,u32 color);
;函数功能:在Disp_Str的基础上改变字符串的颜色
Disp_Color_Str:
push ebp
mov ebp,esp
push eax
push ebx
push esi
push edi
mov esi,[ebp + 8] ;取得要显示的字符串的偏移
mov edi,[Disp_Pos]
xor eax,eax
mov eax,[ebp + 12]
shl eax,8
and eax,0000ff00h ;ah保存颜色
.begin:
lodsb
test al,al ;如果字符为0就退出
je .exit
cmp al,0ah ;如果是回车则跳到改变esi跳到下一行
jne .disp
push eax
mov eax,edi
mov bl,160
div bl
and ax,0ffh
inc ax
mov bl,160
mul bl
mov edi,eax
pop eax
jmp .begin
.disp:
mov [gs:edi],ax
add edi,2
jmp .begin
.exit:
mov [Disp_Pos],edi ;全局变量赋回值
pop edi
pop esi
pop ebx
pop eax
pop ebp
ret
;end of Disp_Color_Str================================================
-
-
-
-
- char * itoa(char * str, int num)
- {
- char * p = str;
- char ch;
- int i;
- int flag = 0;
-
- *p++ = '0';
- *p++ = 'x';
-
- if(num == 0){
- *p++ = '0';
- }
- else{
- for(i=28;i>=0;i-=4){
- ch = (num >> i) & 0xF;
- if(flag || (ch > 0)){
- flag = 1;
- ch += '0';
- if(ch > '9'){
- ch += 7;
- }
- *p++ = ch;
- }
- }
- }
-
- *p = 0;
-
- return str;
- }
-
-
-
-
- void Disp_Int(u32 num)
- {
- char output[16];
- itoa(output, num);
- Disp_Color_Str(output,0xc);
- }
接下来轮到设置IDT了,先声明两个全局数组分别存放IDT和IDT_PTR。
- Gate IDT[256];
- u8 IDT_Ptr[6];
然后是填充1个Gate的函数:Fill_Gate,并在函数Init_IDT中填充16个要处理的内中断的Gate。
-
- void Divide_Error();
- void Single_Step_Exception();
- void NMI();
- void Breakpoint_Exception();
- void Overflow();
- void Bounds_Check();
- void Inval_Opcode();
- void Copr_Not_Available();
- void Double_Fault();
- void Copr_Seg_Overrun();
- void Inval_TSS();
- void Segment_Not_Present();
- void Stack_Exception();
- void General_Protection();
- void Page_Fault();
- void Copr_Error();
-
- void Fill_Gate(u8 idt_no,Int_Handler handler,u8 type,u8 privilege)
- {
- Gate *p_Gate = (Gate*)&IDT[idt_no];
- u32 base = (u32)handler;
- p_Gate->offset_low = base & 0xffff;
- p_Gate->selector = 16;
- p_Gate->dcount = 0;
- p_Gate->attr = type | (privilege << 5);
- p_Gate->offset_high = (base >> 16) & 0xffff;
- }
-
- void Init_IDT()
- {
- Fill_Gate(INT_VECTOR_DIVIDE,Divide_Error,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_DEBUG,Single_Step_Exception,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_NMI,NMI,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_BREAKPOINT,Breakpoint_Exception,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_OVERFLOW,Overflow,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_BOUNDS,Bounds_Check,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_INVAL_OP,Inval_Opcode,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_COPROC_NOT,Copr_Not_Available,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_DOUBLE_FAULT,Double_Fault,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_COPROC_SEG,Copr_Seg_Overrun,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_INVAL_TSS,Inval_TSS,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_SEG_NOT,Segment_Not_Present,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_STACK_FAULT,Stack_Exception,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_PROTECTION,General_Protection,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_PAGE_FAULT,Page_Fault,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_COPROC_ERR,Copr_Error,DA_386IGate,PRIVILEGE_KRNL);
- }
接着在C_Start中添加填充IDT_Ptr的代码。
- Init_IDT();
- *(u16*)(&IDT_Ptr[0]) = sizeof(Gate) * 256 - 1;
- *(u32*)(&IDT_Ptr[2]) = (u32)&IDT;
最后在kernel.asm里添加lidt [IDT_Ptr]来加载IDTR,并初始化各段寄存器使用新填充好的GDT,并进行跳转实验跳到_test标号处执行,jmp 100:0故意写的错误的语句,我们只在GDT中填充了4个描述符,这样跳显然越界了,产生一个General Protection异常,在屏幕打印相应的出错信息。
明天再继续弄外中断吧,呵呵。附上源代码:
kernel.asm:
extern GDT_Ptr
extern IDT_Ptr
extern Disp_Pos
extern C_Start
extern Exception_Handler
Selector_Loader_Flat_RW equ 8
Selector_Kernel_Flat_RW equ 8
Selector_Kernel_Flat_C equ 16
Selector_Kernel_Video equ 24
[section .bss]
Stack_Space resb 2 * 1024
Top_Of_Stack:
[section .text]
global Divide_Error
global Single_Step_Exception
global NMI
global Breakpoint_Exception
global Overflow
global Bounds_Check
global Inval_Opcode
global Copr_Not_Available
global Double_Fault
global Copr_Seg_Overrun
global Inval_TSS
global Segment_Not_Present
global Stack_Exception
global General_Protection
global Page_Fault
global Copr_Error
global Out_Byte
global Disp_Color_Str
global _start
_start:
mov ax,Selector_Loader_Flat_RW
mov ds,ax
mov es,ax
call C_Start
lgdt [GDT_Ptr]
lidt [IDT_Ptr]
mov ax,Selector_Kernel_Flat_RW
mov ds,ax
mov es,ax
mov ss,ax
mov esp,Top_Of_Stack
mov ax,Selector_Kernel_Video
mov gs,ax
jmp Selector_Kernel_Flat_C:_test
_test:
jmp 100:0
hlt
Out_Byte:
push ebp
mov ebp,esp
push eax
push edx
mov edx,[ebp + 8]
mov eax,[ebp + 12]
out dx,al
pop edx
pop eax
pop ebp
ret
;Disp_Color_Str=======================================================
;函数原型:void Disp_Color_Str(char * pszStr,u32 color);
;函数功能:在Disp_Str的基础上改变字符串的颜色
Disp_Color_Str:
push ebp
mov ebp,esp
push eax
push ebx
push esi
push edi
mov esi,[ebp + 8] ;取得要显示的字符串的偏移
mov edi,[Disp_Pos]
xor eax,eax
mov eax,[ebp + 12]
shl eax,8
and eax,0000ff00h ;ah保存颜色
.begin:
lodsb
test al,al ;如果字符为0就退出
je .exit
cmp al,0ah ;如果是回车则跳到改变esi跳到下一行
jne .disp
push eax
mov eax,edi
mov bl,160
div bl
and ax,0ffh
inc ax
mov bl,160
mul bl
mov edi,eax
pop eax
jmp .begin
.disp:
mov [gs:edi],ax
add edi,2
jmp .begin
.exit:
mov [Disp_Pos],edi ;全局变量赋回值
pop edi
pop esi
pop ebx
pop eax
pop ebp
ret
;end of Disp_Color_Str================================================
Divide_Error:
push 0ffffffffh
push 0
jmp Exception
Single_Step_Exception:
push 0ffffffffh
push 1
jmp Exception
NMI:
push 0ffffffffh
push 2
jmp Exception
Breakpoint_Exception:
push 0ffffffffh
push 3
jmp Exception
Overflow:
push 0ffffffffh
push 4
jmp Exception
Bounds_Check:
push 0ffffffffh
push 5
jmp Exception
Inval_Opcode:
push 0ffffffffh
push 6
jmp Exception
Copr_Not_Available:
push 0ffffffffh
push 7
jmp Exception
Double_Fault:
push 8
jmp Exception
Copr_Seg_Overrun:
push 0ffffffffh
push 9
jmp Exception
Inval_TSS:
push 10
jmp Exception
Segment_Not_Present:
push 11
jmp Exception
Stack_Exception:
push 12
jmp Exception
General_Protection:
push 13
jmp Exception
Page_Fault:
push 14
jmp Exception
Copr_Error:
push 0ffffffffh
push 16
jmp Exception
Exception:
call Exception_Handler
add esp,8
hlt
start.c
- typedef unsigned char u8;
- typedef unsigned short u16;
- typedef unsigned int u32;
-
-
- #define DA_32 0x4000 /* 32 位段 */
- #define DA_LIMIT_4K 0x8000 /* 段界限粒度为 4K 字节 */
- #define DA_DPL0 0x00 /* DPL = 0 */
- #define DA_DPL1 0x20 /* DPL = 1 */
- #define DA_DPL2 0x40 /* DPL = 2 */
- #define DA_DPL3 0x60 /* DPL = 3 */
-
-
- #define DA_DR 0x90 /* 存在的只读数据段类型值 */
- #define DA_DRW 0x92 /* 存在的可读写数据段属性值 */
- #define DA_DRWA 0x93 /* 存在的已访问可读写数据段类型值 */
- #define DA_C 0x98 /* 存在的只执行代码段属性值 */
- #define DA_CR 0x9A /* 存在的可执行可读代码段属性值 */
- #define DA_CCO 0x9C /* 存在的只执行一致代码段属性值 */
- #define DA_CCOR 0x9E /* 存在的可执行可读一致代码段属性值 */
-
-
- #define DA_LDT 0x82 /* 局部描述符表段类型值 */
- #define DA_TaskGate 0x85 /* 任务门类型值 */
- #define DA_386TSS 0x89 /* 可用 386 任务状态段类型值 */
- #define DA_386CGate 0x8C /* 386 调用门类型值 */
- #define DA_386IGate 0x8E /* 386 中断门类型值 */
- #define DA_386TGate 0x8F /* 386 陷阱门类型值 */
-
-
-
- #define PRIVILEGE_KRNL 0
- #define PRIVILEGE_TASK 1
- #define PRIVILEGE_USER 3
-
-
- #define INT_VECTOR_DIVIDE 0x0
- #define INT_VECTOR_DEBUG 0x1
- #define INT_VECTOR_NMI 0x2
- #define INT_VECTOR_BREAKPOINT 0x3
- #define INT_VECTOR_OVERFLOW 0x4
- #define INT_VECTOR_BOUNDS 0x5
- #define INT_VECTOR_INVAL_OP 0x6
- #define INT_VECTOR_COPROC_NOT 0x7
- #define INT_VECTOR_DOUBLE_FAULT 0x8
- #define INT_VECTOR_COPROC_SEG 0x9
- #define INT_VECTOR_INVAL_TSS 0xA
- #define INT_VECTOR_SEG_NOT 0xB
- #define INT_VECTOR_STACK_FAULT 0xC
- #define INT_VECTOR_PROTECTION 0xD
- #define INT_VECTOR_PAGE_FAULT 0xE
- #define INT_VECTOR_COPROC_ERR 0x10
-
-
- void Divide_Error();
- void Single_Step_Exception();
- void NMI();
- void Breakpoint_Exception();
- void Overflow();
- void Bounds_Check();
- void Inval_Opcode();
- void Copr_Not_Available();
- void Double_Fault();
- void Copr_Seg_Overrun();
- void Inval_TSS();
- void Segment_Not_Present();
- void Stack_Exception();
- void General_Protection();
- void Page_Fault();
- void Copr_Error();
-
- typedef struct s_descriptor
- {
- u16 limit_low;
- u16 base_low;
- u8 base_mid;
- u8 attr1;
- u8 limit_high_attr2;
- u8 base_high;
- }Descriptor;
-
- typedef struct s_gate
- {
- u16 offset_low;
- u16 selector;
- u8 dcount;
- u8 attr;
- u16 offset_high;
- }Gate;
-
- Descriptor GDT[128];
- u8 GDT_Ptr[6];
- Gate IDT[256];
- u8 IDT_Ptr[6];
- u32 Disp_Pos = 0;
-
- typedef void (*Int_Handler)();
-
- void Disp_Color_Str(char *p_Str,u32 color);
- void Disp_Int(u32 num);
- void Out_Byte(u16 port,u8 value);
-
- void Fill_Desc(u8 desc_no,u32 base,u32 limit,u16 attr)
- {
- Descriptor *p_Desc = (Descriptor *)&GDT[desc_no];
- p_Desc->limit_low = limit & 0xffff;
- p_Desc->base_low = base & 0xffff;
- p_Desc->base_mid = (base >> 16) & 0xff;
- p_Desc->attr1 = attr & 0xff;
- p_Desc->limit_high_attr2 = ((limit >> 16) & 0xf) | (attr >> 8);
- p_Desc->base_high = (base >> 24) & 0xff;
- }
-
- void Init_GDT()
- {
- Fill_Desc(0,0,0,0);
- Fill_Desc(1,0,0xfffff,DA_DRW | DA_32 | DA_LIMIT_4K);
- Fill_Desc(2,0,0xfffff,DA_C | DA_32 | DA_LIMIT_4K);
- Fill_Desc(3,0xb8000,0xffff,DA_DRW);
- }
-
- void Fill_Gate(u8 idt_no,Int_Handler handler,u8 type,u8 privilege)
- {
- Gate *p_Gate = (Gate*)&IDT[idt_no];
- u32 base = (u32)handler;
- p_Gate->offset_low = base & 0xffff;
- p_Gate->selector = 16;
- p_Gate->dcount = 0;
- p_Gate->attr = type | (privilege << 5);
- p_Gate->offset_high = (base >> 16) & 0xffff;
- }
-
- void Init_IDT()
- {
- Fill_Gate(INT_VECTOR_DIVIDE,Divide_Error,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_DEBUG,Single_Step_Exception,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_NMI,NMI,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_BREAKPOINT,Breakpoint_Exception,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_OVERFLOW,Overflow,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_BOUNDS,Bounds_Check,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_INVAL_OP,Inval_Opcode,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_COPROC_NOT,Copr_Not_Available,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_DOUBLE_FAULT,Double_Fault,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_COPROC_SEG,Copr_Seg_Overrun,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_INVAL_TSS,Inval_TSS,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_SEG_NOT,Segment_Not_Present,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_STACK_FAULT,Stack_Exception,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_PROTECTION,General_Protection,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_PAGE_FAULT,Page_Fault,DA_386IGate,PRIVILEGE_KRNL);
- Fill_Gate(INT_VECTOR_COPROC_ERR,Copr_Error,DA_386IGate,PRIVILEGE_KRNL);
- }
-
- void Init_8259A()
- {
- Out_Byte(0x20,0x11);
- Out_Byte(0xa0,0x11);
-
- Out_Byte(0x21,0x20);
- Out_Byte(0xa1,0x28);
-
- Out_Byte(0x21,0x4);
- Out_Byte(0xa1,0x2);
-
- Out_Byte(0x21,0x1);
- Out_Byte(0xa1,0x1);
-
- Out_Byte(0x21,0xff);
- Out_Byte(0xa1,0xff);
- }
-
- void C_Start()
- {
- Init_8259A();
- Init_GDT();
- Init_IDT();
- *(u16*)(&GDT_Ptr[0]) = 4 * 8 - 1;
- *(u32*)(&GDT_Ptr[2]) = (u32)&GDT;
- *(u16*)(&IDT_Ptr[0]) = sizeof(Gate) * 256 - 1;
- *(u32*)(&IDT_Ptr[2]) = (u32)&IDT;
- }
-
- void Exception_Handler(u32 vec_no,u32 err_code,u32 eip,u32 cs,int eflags)
- {
- int i;
-
- Disp_Pos = 0;
- for(i = 0 ; i < 80 * 5 ; i++)
- {
- Disp_Color_Str(" ",0xc);
- }
- Disp_Pos = 0;
-
- Disp_Color_Str("VEC_NO:",0xc);
- Disp_Int(vec_no);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("ERROR_CODE:",0xc);
- Disp_Int(err_code);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("CS:",0xc);
- Disp_Int(cs);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("EIP:",0xc);
- Disp_Int(eip);
- Disp_Color_Str("/n",0xc);
-
- Disp_Color_Str("EFLAGS:",0xc);
- Disp_Int(eflags);
- Disp_Color_Str("/n",0xc);
- }
-
-
-
-
-
- char * itoa(char * str, int num)
- {
- char * p = str;
- char ch;
- int i;
- int flag = 0;
-
- *p++ = '0';
- *p++ = 'x';
-
- if(num == 0){
- *p++ = '0';
- }
- else{
- for(i=28;i>=0;i-=4){
- ch = (num >> i) & 0xF;
- if(flag || (ch > 0)){
- flag = 1;
- ch += '0';
- if(ch > '9'){
- ch += 7;
- }
- *p++ = ch;
- }
- }
- }
-
- *p = 0;
-
- return str;
- }
-
-
-
-
- void Disp_Int(u32 num)
- {
- char output[16];
- itoa(output, num);
- Disp_Color_Str(output,0xc);
- }
最后照例附图一张: