第6天:分割处理与中断处理
6.1、分割處理
6.1.1、bootpack.c拆分
6.1.2、MakeFile整理
使用了一般規(guī)則
%.gas : %.c Makefile$(CC1) -o $*.gas $*.c%.nas : %.gas Makefile$(GAS2NASK) $*.gas $*.nas%.obj : %.nas Makefile$(NASK) $*.nas $*.obj $*.lst6.1.3、整理頭文件
bootpack.c文件拆分之后,都包含了很多重復(fù)的函數(shù)、結(jié)構(gòu)體和常量的定義。把這些重復(fù)的地方放到文件頭里(bootpack.h)。使用的時候使用include使用。
#include “bootpack.h”
6.2、段描述符結(jié)構(gòu)體
struct SEGMENT_DESCRIPTOR {short limit_low, base_low;char base_mid, access_right;char limit_high, base_high; };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; }set_segmdesc 用來設(shè)置段描述符,段描述符有8字節(jié),64位。
該函數(shù)主要來設(shè)置:
段的起始地址(base)用32位表示,32位又分為base_low(2字節(jié)),base_mid(1字節(jié)),base_high(1字節(jié))。這三段的位置在哪?回看第五天。為什么分成這個三段?主要是為了與80286時代兼容。是的286的程序兼容386操作系統(tǒng)。
段上限(limit)。它表示一個段有多少字節(jié)。這里有一個問題出現(xiàn)了,段的最大可達(dá)4GB,需要用32位表示,如果直接放進(jìn)去的話,這個就占段描述符的4字節(jié),再加上段的起始地址,8字節(jié)就用完了,沒辦法保存其他信息了。因此限制只能使用20位,就是1MB大小,是不是有種回到16位錯覺。這里有一個巧妙的辦法,既不存放32位數(shù)值,又可以擴(kuò)大表示范圍,就是在段屬性里設(shè)置了一個標(biāo)志位——Gbit,這個標(biāo)志位為1是,limit表示的就是page,而不是字節(jié)byte了,在CPU里默認(rèn)頁的大小為4KB,這樣以來,又是4GB空間了。其實(shí)在現(xiàn)代操作系統(tǒng)里,就是把段給屏蔽了,說是分段+分頁,其實(shí)就是分頁
參考文章(知乎:軒轅之風(fēng))現(xiàn)代操作系統(tǒng)內(nèi)存管理到底是分段還是分頁,段寄存器還有用嗎?
關(guān)于段上限還沒解釋完,limit又分為limit_low(16位)和limit_high(4位)
段屬性(ar或者access_right),高4位是“擴(kuò)展訪問權(quán)”,低8位才是真正的屬性。具體參考下圖:
這里提一下:D/B 如果等于0,是16位模式,但是不能調(diào)試BIOS,只能執(zhí)行16位程序。
6.3、使用中斷
6.3.1、初始化PIC
使用中斷之前,需要初始化PIC(programmable interrupt controller),就是“可編程中斷控制器”。
CPU在設(shè)計(jì)的時候只能單獨(dú)處理一個中斷,這不夠用,需要使用PIC芯片輔助。PIC是將8個中斷信號(IRQ)集合成一個中斷信號的裝置,如果設(shè)備多于8個,就需要串聯(lián)PIC,分別為主從PIC,串聯(lián)結(jié)構(gòu)為:
PIC 8259A
詳解8259A
隨著PIC的初始化, 會產(chǎn)生一次IRQ7中斷, 如果不對該中斷處理程序執(zhí)行STI , 操作系統(tǒng)的啟動會失敗。
IMR:中斷屏蔽
ICW2:IRQx通知CPU,通知有中斷后,CPU讓PIC發(fā)送數(shù)據(jù)D0-7,發(fā)送兩字節(jié)數(shù)據(jù)——0xcd 0x?? ,翻譯成機(jī)器碼就是INT n,CPU就會執(zhí)行這個中斷。
IRQ0 - 15 對應(yīng) INT 0x20-2f。
ICW3:主從PIC連接相關(guān)
6.3.2、中斷程序制作
產(chǎn)生中斷之后,就要處理中斷了,開始寫處理中斷的程序吧。
//int.c void inthandler21(int *esp) /* 來自PS/2鍵盤的中斷 */ {struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15);putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 21 (IRQ-1) : PS/2 keyboard");for (;;) {io_hlt();} }中斷處理完成之后,需要執(zhí)行IRETD(32位,16位是IRET),還需要保存一些寄存器的值。
_asm_inthandler21:PUSH ESPUSH DSPUSHADMOV EAX,ESPPUSH EAXMOV AX,SSMOV DS,AXMOV ES,AXCALL _inthandler21POP EAXPOPADPOP DSPOP ESIRETD把中斷處理程序注冊到IDT中,這個操作可以在初始化init_gatedesc函數(shù)中完成
set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);把a(bǔ)sm_inthandler21注冊在IDT的第0x21號,這樣鍵盤有動作產(chǎn)生,這個中斷程序就會執(zhí)行。
解釋一下第三個參數(shù)2x8:
第三個參數(shù)是設(shè)置段選擇子的。
2是選擇2號段,乘以8是為了左移三位。段選擇子中,最后三位是TI和RPL。
看一下2號段:
set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);理思路:
1、中斷代碼注冊到中斷描述符表
2、發(fā)生鍵盤中斷,會去找0x21中斷
3、如果權(quán)限檢查通過,cs裝入中斷門描述符指定的段選擇子,EIP裝入目標(biāo)代碼偏移(asm_inthandler21)
段選擇子選的是2號段(0x280000),通過asmhead.nas代碼就把bootpack.h的內(nèi)容裝到這個段,bootpack是ORG 0開始的,所以bootpack在這個段中偏移為0的位置開始裝載,函數(shù)地址為偏移地址(目標(biāo)代碼段偏移)。所以:cs指向2號段,EIP指向段內(nèi)的偏移代碼,開始執(zhí)行中斷程序。
補(bǔ)充:
權(quán)限通過:
1、發(fā)生中斷后,中斷門描述符中的段選擇子的 后兩位CPL(RPL),如果小于中斷門描述符的DPL,并且大于等于中斷門描述符所指向段描述符的DPL,就指向段描述符的DPL(意思就是,當(dāng)前CPL權(quán)限不夠,需要提升權(quán)限,使得能夠把代碼調(diào)入段中執(zhí)行,相應(yīng)中斷)。
緊接著,如果CPL等于段描述符的DPL,則是同級權(quán)限,不做棧切換,反之(小于),需要棧切換。如果進(jìn)行棧切換,還需要從 TSS 中加載具體權(quán)限的 SS、ESP,當(dāng)然也要對 SS 中段選擇子指向的段描述符進(jìn)行檢查。
操作系統(tǒng) TSS
總結(jié)
以上是生活随笔為你收集整理的第6天:分割处理与中断处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首款双频GNSS智能手机进入市场
- 下一篇: mevan 的常用命令和参数解释