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