把class03改成class04
IDT,GDT,PIC
我來介紹什麼是IDT和GDT,PIC,怎麼實現鍵盤中斷
GDT全域性描述表在16位CPU用不到,到了32位CPU要用。
16位CPU真實模式用基地址x16+偏移地址去尋找記憶體地址,到了32位也用基地址x16+偏移地址找地址但是,32位CPU有保護模式,防止程式亂訪問記憶體
所以用GDT
IDT,Interrupt Descriptor Table,即中斷描述符表,用來聯絡中斷和處理函式的,比如A中斷髮生->執行B函式
PIC(可程式設計中斷控制器),中斷是由PIC產生的
這是我自己的理解,你要想搞明白得自己去找資料
實現鍵盤中斷
鍵盤按下-PIC收到發起中斷-CPU處理中斷-執行對應函式
這是我自己意淫的,具體怎麼回事你得自己找資料
首先初始化pic,gdt,idt
建立檔案dsctbl.c
/* GDT、IDT、descriptor table 關係處理 */ #include "include/head.h" void init_gdtidt(void) { struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; int i; /* GDT初始化 */ for (i = 0; i <= LIMIT_GDT / 8; i++) { set_segmdesc(gdt + i, 0, 0, 0); } set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); load_gdtr(LIMIT_GDT, ADR_GDT); /* IDT初始化 */ for (i = 0; i <= LIMIT_IDT / 8; i++) { set_gatedesc(idt + i, 0, 0, 0); } load_idtr(LIMIT_IDT, ADR_IDT); /* IDT設定*/ set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); /* IDT的設定 */ return; } void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) { if (limit > 0xfffff) { ar |= 0x8000; /* G_bit = 1 */ limit /= 0x1000; } sd->limit_low = limit & 0xffff; sd->base_low = base & 0xffff; sd->base_mid = (base >> 16) & 0xff; sd->access_right = ar & 0xff; sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); sd->base_high = (base >> 24) & 0xff; return; } void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) { gd->offset_low = offset & 0xffff; gd->selector = selector; gd->dw_count = (ar >> 8) & 0xff; gd->access_right = ar & 0xff; gd->offset_high = (offset >> 16) & 0xffff; return; }
加粗的地方就是註冊21號鍵盤中斷處理函式到IDT
head.h
/*naskfunc.asm*/ void io_stihlt(); void io_hlt(void); void io_cli(void); void io_sti(void); int io_get8(int port); void io_set8(int port, int data); void write_mem8(int addr, int data); int io_load_eflags(void); void io_store_eflags(int eflags);
void load_gdtr(int limit, int addr);
void load_idtr(int limit, int addr);
void asm_inthandler21(void); /* asmhead.nas */ struct BOOTINFO { /* 0x0ff0-0x0fff */ char cyls; /* 啟動區讀磁碟讀到此為止 */ char leds; /* 啟動時鍵盤的LED的狀態 */ char vmode; /* 顯示卡模式為多少位彩色 */ char reserve; short scrnx, scrny; /* 畫面解析度 */ char *vram; }; #define ADR_BOOTINFO 0x00000ff0 /*graphic.c*/ void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); void putfont8(char *vram, int xsize, int x, int y, char c, char *font); void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); /*font*/ extern char font[4096]; /* dsctbl.c */ struct SEGMENT_DESCRIPTOR { short limit_low, base_low; char base_mid, access_right; char limit_high, base_high; }; struct GATE_DESCRIPTOR { short offset_low, selector; char dw_count, access_right; short offset_high; }; void init_gdtidt(void); void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); #define ADR_IDT 0x0026f800 #define LIMIT_IDT 0x000007ff #define ADR_GDT 0x00270000 #define LIMIT_GDT 0x0000ffff #define ADR_BOTPAK 0x00280000 #define LIMIT_BOTPAK 0x0007ffff #define AR_DATA32_RW 0x4092 #define AR_CODE32_ER 0x409a #define AR_INTGATE32 0x008e /* pic.c */ void init_pic(void); #define PIC0_ICW1 0x0020 #define PIC0_OCW2 0x0020 #define PIC0_IMR 0x0021 #define PIC0_ICW2 0x0021 #define PIC0_ICW3 0x0021 #define PIC0_ICW4 0x0021 #define PIC1_ICW1 0x00a0 #define PIC1_OCW2 0x00a0 #define PIC1_IMR 0x00a1 #define PIC1_ICW2 0x00a1 #define PIC1_ICW3 0x00a1 #define PIC1_ICW4 0x00a1
/*interrupt.c*/
void inthandler21(int *esp);
加粗的地方就是增加的地方
naskfunc.asm
; naskfunc ; TAB=4 [FORMAT "WCOFF"] ; 製作目標檔案的模式 [INSTRSET "i486p"] ; 使用到486為止的指令 [BITS 32] ; 3製作32位模式用的機器語言 [FILE "naskfunc.asm"] ; 檔名 GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt GLOBAL _io_load_eflags,_io_store_eflags,_asm_inthandler21 GLOBAL _load_gdtr, _load_idtr EXTERN _inthandler21 [SECTION .text] _io_hlt: ; void io_hlt(void); HLT RET _io_cli: ; void io_cli(void); CLI RET _io_sti: ; void io_sti(void); STI RET _io_get8: ; int io_get8(int port); MOV EDX,[ESP+4] ; port MOV EAX,0 IN AL,DX RET _io_set8: ; void io_set8(int port, int data); MOV EDX,[ESP+4] ; port MOV AL,[ESP+8] ; data OUT DX,AL RET _io_stihlt: ; void io_stihlt(void); STI HLT RET _write_mem8: ; void write_mem8(int addr, int data); MOV ECX,[ESP+4] ; taking content of add MOV AL,[ESP+8] ; taking content of data MOV [ECX],AL ; *ecx=al RET _io_load_eflags: ; int io_load_eflags(void); PUSHFD ; PUSH EFLAGS POP EAX RET _io_store_eflags: ; void io_store_eflags(int eflags); MOV EAX,[ESP+4] PUSH EAX POPFD ; POP EFLAGS RET _load_gdtr: ; void load_gdtr(int limit, int addr); MOV AX,[ESP+4] ; limit MOV [ESP+6],AX LGDT [ESP+6] RET _load_idtr: ; void load_idtr(int limit, int addr); MOV AX,[ESP+4] ; limit MOV [ESP+6],AX LIDT [ESP+6] RET _asm_inthandler21: PUSH ES PUSH DS PUSHAD MOV EAX,ESP PUSH EAX MOV AX,SS MOV DS,AX MOV ES,AX CALL _inthandler21 POP EAX POPAD POP DS POP ES IRETD
加粗的地方就是要修改的地方
IDT-->_asm_inthandler21-->_inthandler21函式
新建pic.c
/*初始化關係 */ #include "include/head.h" void init_pic(void) /* PIC初始化 */ { io_set8(PIC0_IMR, 0xff ); /* 禁止所有中斷 */ io_set8(PIC1_IMR, 0xff ); /* 禁止所有中斷 */ io_set8(PIC0_ICW1, 0x11 ); /* 邊緣觸發模式(edge trigger mode) */ io_set8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ io_set8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相連 */ io_set8(PIC0_ICW4, 0x01 ); /* 無緩衝區模式 */ io_set8(PIC1_ICW1, 0x11 ); /* 邊緣觸發模式(edge trigger mode) */ io_set8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ io_set8(PIC1_ICW3, 2 ); /* PIC1由IRQ2連線 */ io_set8(PIC1_ICW4, 0x01 ); /* 無緩衝區模式 */ io_set8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ io_set8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中斷 */ return; }
建立interrupt.c
#include "include/head.h" void inthandler21(int *esp) /* 來自PS/2鍵盤的中斷 */ { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; boxfill8(binfo->vram, binfo->scrnx, 7, 0, 0, 32 * 8 - 1, 15); putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, 0, "INT 21 (IRQ-1) :PS/2 keyboard"); for (;;) { io_hlt(); } }
最後修改mian.c
#include "include/head.h" #include <string.h> struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; void Main(void){ int i;char s[256]; init_gdtidt(); init_pic(); io_sti(); init_palette(); boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); sprintf(s, "scrnx = %d", binfo->scrnx); putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s); io_set8(PIC0_IMR, 0xf9); /* 開放PIC1和鍵盤中斷(11111001) */ for (;;) { io_hlt(); } }
別忘了編譯之改一下makefile
執行:
cd class02 ..\z_tools\make.exe run
自制作業系統合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html
專案github地址rick521/My-OS (github.com)給我點顆star