上篇原本打算先實現個在任務狀態運行的例子,可是代碼有問題(編譯錯代碼了),任務那部分確實還不是很熟悉; html
本篇的目的:1.實現實例化中斷的描述符 架構
2.實現時鐘中斷 oop
對於中斷分類暫且還沒搞太清楚,這裏先無論,直接看怎麼安裝的。 測試
中斷在實模式下是直接用的,例如:int 10h spa
可是保護模式下是的實現,跟裝載GDT很相似。 .net
只是描述符要用到GDT的選擇子+偏移量構成,也就是經過中斷調用的實際是一個處理的方法。 code
lidt的描述符結構 htm
此次代碼是好的 blog
;目的是中斷門 [org 0x7c00] [bits 16] ;定義全局描述符的常量又不佔用內存空間 gdt_basic equ 0x00007e00 ;#1 數據段 4G data_basic equ 0x0000000 ;#2 當前的程序代碼段 512 code_basic equ 0x00007c00 ;#3 全局堆棧基地址 4kb stack_basic equ 0x00007c00 ;#4 顯示描述基地址 show_basic equ 0x000B8000 ;$1 中斷向量表安裝的位置 interrupt_basic equ 0x00008000 ;這樣高四位0好算 256*8=2^11+ mov ax,cs mov ds,ax call show_style ;設置顯示模式 主要是清屏 ;計算GDT所在的邏輯段地址 mov eax,gdt_basic ;獲得描述符的基地址 xor edx,edx mov ebx,16 div ebx mov ds,eax ;令DS指向該段以進行操做 mov ebx,edx ;段內起始偏移地址 ;建立0#描述符,它是空描述符,這是處理器的要求 ;#1建立1#描述符,這是一個數據段,對應0~4GB的線性地址空間 mov dword [ebx+0x08],0x0000ffff ;基地址爲0,段界限爲0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度爲4KB,存儲器段描述符 ;#2建立保護模式下初始代碼段描述符 mov dword [ebx+0x10],0x7c0001ff ;基地址爲0x00007c00,界限0x1FF mov dword [ebx+0x14],0x00409800 ;粒度爲1個字節,代碼段描述符 ;#3創建保護模式下的堆棧段描述符 ;基地址爲0x00007C00,界限0xFFFFE mov dword [ebx+0x18],0x7c00fffe ;粒度爲4KB mov dword [ebx+0x1c],0x00cf9600 ;#4創建保護模式下的顯示緩衝區描述符 mov dword [ebx+0x20],0x80007fff ;基地址爲0x000B8000,界限0x07FFF mov dword [ebx+0x24],0x0040920b ;粒度爲字節 ;=============================================================== ;初始化描述符表寄存器GDTR ;由於上面吧數據段地址改了因此這利用代碼段 mov word [cs:pgdt], 39 ;描述符表的界限(總字節數減一) n*8-1; lgdt [cs:pgdt] in al,0x92 ;南橋芯片內的端口 or al,0000_0010B out 0x92,al ;打開A20 cli ;保護模式下中斷機制還沒有創建,應 ;禁止中斷 mov eax,cr0 or eax,1 mov cr0,eax ;設置PE位 ;如下進入保護模式... ... jmp dword 0x0010:protect_loader-0x7C00;16位的描述符選擇子:32位偏移 ;hlt ;程序終止 ;===================showStyle============================= show_style: ;設置顯示方式 mov ah,0x00 mov al,0x03 int 10h ret ;========================================================= [bits 32] interrupt_show: pushad xor eax,eax mov eax,0x0020 ;#4顯示段的選擇子 mov es,eax mov eax,0x0008 ;#1數據段選擇子 mov ds,eax xor ebx,ebx mov word bx,[ds:show_position] mov byte [es:ebx],'^' add bx,2 cmp bx,80*2*25 jle .init1 sub bx,80*2*25 .init1: mov word [ds:show_position],bx popad iretd protect_loader: mov eax,0x0018 mov ss,eax xor esp,esp cli ;$1硬件中斷 依據代碼段#2 mov eax,0x0008 mov ds,eax ;4G mov eax,0x0010 ;代碼段描述子 shl eax,16 mov ebx,interrupt_show ;中斷實現的偏移量 sub ebx,0x7c00 ;由於知道高16位確定爲0 and ebx,0x0000FFFF or eax,ebx mov ebx,interrupt_basic ;中斷描述符的地方 mov ecx,256 loop_idt: mov dword [ebx+0x00],eax mov dword [ebx+0x04],0x00008E00 ; add ebx,8 loop loop_idt ;從新初始化鍵盤中斷0x09 lidt [ds:interrupt_des] int 080h ;測試下效果 sti int 009h loop1: jmp loop1; ;--------------數據段-------------------------------------------- show_position dw 0 ;80*25=2000 2^16= pgdt dw 0 dd gdt_basic ;GDT的物理地? interrupt_des dw 256*8-1 ;idt dd interrupt_basic times 510-($-$$) db 0 db 0x55 ;引導識別標示 db 0xaa
這裏主要是對8259a控制器的編寫控制 索引
參考: http://blog.csdn.net/jltxgcy/article/details/8661959
http://wenku.baidu.com/view/dcbef6140b4e767f5acfcef3.html
對於主從控制器的編寫主要是從端口
0x20/0xa0 ICW1 主要設置從片是否鏈接
0x21/0xa1 ICW2 主要負責設置IRO,IR8對應的中斷
0x21/0xa1 ICW3 若是有從片 主片1對應的從片的連接,從片同樣
0x21/0xa1 ICW4 處理器架構的標誌,還有就是個結束的標誌
上面的必須按照順序來設定,下面的好像沒要求
0x21/0xa1 OCW1 中斷屏蔽 置1屏蔽 0開啓
0x20/0xa0 OCW2 優先權控制以及結束
實現響應中斷是根據:8259a的從片 IR80中斷號的重定向與開啓(這裏必需要注意:主片與從片的連接也必須開啓)
經過RTC來實現響應中斷的
下面是代碼: 比上面多添加了8259a的初始化,和RTC的操做
;目的是中斷門 [org 0x7c00] [bits 16] ;定義全局描述符的常量又不佔用內存空間 gdt_basic equ 0x00007e00 ;#1 數據段 4G data_basic equ 0x0000000 ;#2 當前的程序代碼段 512 code_basic equ 0x00007c00 ;#3 全局堆棧基地址 4kb stack_basic equ 0x00007c00 ;#4 顯示描述基地址 show_basic equ 0x000B8000 ;$1 中斷向量表安裝的位置 interrupt_basic equ 0x00008000 ;這樣高四位0好算 256*8=2^11+00009000 mov ax,cs mov ds,ax call show_style ;設置顯示模式 主要是清屏 ;計算GDT所在的邏輯段地址 mov eax,gdt_basic ;獲得描述符的基地址 xor edx,edx mov ebx,16 div ebx mov ds,eax ;令DS指向該段以進行操做 mov ebx,edx ;段內起始偏移地址 ;建立0#描述符,它是空描述符,這是處理器的要求 ;#1建立1#描述符,這是一個數據段,對應0~4GB的線性地址空間 mov dword [ebx+0x08],0x0000ffff ;基地址爲0,段界限爲0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度爲4KB,存儲器段描述符 ;#2建立保護模式下初始代碼段描述符 mov dword [ebx+0x10],0x7c0001ff ;基地址爲0x00007c00,界限0x1FF mov dword [ebx+0x14],0x00409800 ;粒度爲1個字節,代碼段描述符 ;#3創建保護模式下的堆棧段描述符 ;基地址爲0x00007C00,界限0xFFFFE mov dword [ebx+0x18],0x7c00fffe ;粒度爲4KB mov dword [ebx+0x1c],0x00cf9600 ;#4創建保護模式下的顯示緩衝區描述符 mov dword [ebx+0x20],0x80007fff ;基地址爲0x000B8000,界限0x07FFF mov dword [ebx+0x24],0x0040920b ;粒度爲字節 ;=============================================================== ;初始化描述符表寄存器GDTR ;由於上面吧數據段地址改了因此這利用代碼段 mov word [cs:pgdt], 39 ;描述符表的界限(總字節數減一) n*8-1; lgdt [cs:pgdt] in al,0x92 ;南橋芯片內的端口 or al,0000_0010B out 0x92,al ;打開A20 cli ;保護模式下中斷機制還沒有創建,應 ;禁止中斷 mov eax,cr0 or eax,1 mov cr0,eax ;設置PE位 ;如下進入保護模式... ... jmp dword 0x0010:protect_loader-0x7C00;16位的描述符選擇子:32位偏移 ;hlt ;程序終止 ;===================showStyle============================= show_style: ;設置顯示方式 mov ah,0x00 mov al,0x03 int 10h ret ;========================================================= [bits 32] protect_loader: mov eax,0x0018 mov ss,eax xor esp,esp ;cli ;$1硬件中斷 依據代碼段#2 mov eax,0x0008 mov ds,eax ;4G mov eax,0x0010 ;代碼段描述子 shl eax,16 mov ebx,interrupt_show ;中斷實現的偏移量 sub ebx,0x7c00 ;由於知道高16位確定爲0 and ebx,0x0000FFFF or eax,ebx mov ebx,interrupt_basic ;中斷描述符的地方 xor esi,esi mov ecx,256 .loop_idt: mov dword [ebx+esi+0x00],eax mov dword [ebx+esi+0x04],0x00008E00 ; add esi,8 loop .loop_idt ;從新初始化時鐘中斷0x70 mov eax,0x0010 ;代碼段描述子 shl eax,16 mov ebx,time_interrupt ;中斷實現的偏移量 sub ebx,0x7c00 and ebx,0x0000FFFF or eax,ebx mov ebx,interrupt_basic mov dword[ebx+0x28*8],eax mov dword[ebx+0x28*8+4],0x00008E00 lidt [ds:interrupt_des] ;call Init8259A xor eax,eax ;設置8259A中斷控制器 mov al, 011h out 020h, al ; 主8259, ICW1. call io_delay out 0A0h, al ; 從8259, ICW1. call io_delay mov al, 020h ; IRQ0 對應中斷向量 0x20 out 021h, al ; 主8259, ICW2. call io_delay mov al, 028h ; IRQ8 對應中斷向量 0x28 out 0A1h, al ; 從8259, ICW2. call io_delay mov al, 004h ; IR2 對應從8259 out 021h, al ; 主8259, ICW3. call io_delay mov al, 002h ; 對應主8259的 IR2 out 0A1h, al ; 從8259, ICW3. call io_delay mov al, 001h out 021h, al ; 主8259, ICW4. call io_delay out 0A1h, al ; 從8259, ICW4. call io_delay mov al, 11111111b ; 僅僅開啓定時器中斷 ;mov al, 11111111b ; 屏蔽主8259全部中斷 out 021h, al ; 主8259, OCW1. call io_delay mov al, 11111110b ; 屏蔽從8259全部中斷 out 0A1h, al ; 從8259, OCW1. call io_delay ;設置和時鐘中斷相關的硬件 mov al,0x0b ;RTC寄存器B 0000_1011 or al,0x80 ;阻斷NMI 1000_0000 out 0x70,al mov al,0x12 ;設置寄存器B,禁止週期性中斷,開放更 out 0x71,al ;新結束後中斷,BCD碼,24小時制 mov al,0x0c out 0x70,al in al,0x71 ;讀RTC寄存器C,復位未決的中斷狀態 sti ;int 70h .loop: jmp .loop; ;---------------------------------------------------------------- interrupt_show: pushad xor eax,eax mov eax,0x0020 ;#4顯示段的選擇子 mov es,eax mov eax,0x0008 ;#1數據段選擇子 mov ds,eax xor ebx,ebx mov word bx,[ds:show_position] mov byte [es:ebx],'^' add bx,2 call show_index mov word [ds:show_position],bx popad iretd ;------------------------------------------------------------------ show_index: cmp bx,80*2*25 jle .init1 sub bx,80*2*25 .init1: ret ; IR0中斷-----------0x70----------------------------------------------------------- time_interrupt: pushad int 10h mov al,0x20 ;中斷結束命令EOI out 0xa0,al ;向8259A從片發送 out 0x20,al ;向8259A主片發送 mov al,0x0c ;寄存器C的索引。且開放NMI out 0x70,al in al,0x71 ;讀一下RTC的寄存器C,不然只發生一次中斷 ;暫且隨便調用一箇中斷 popad iretd ; Init8259A --------------------------------------------------------------------------------------------- Init8259A: pushad popad ret ; --------------------------------------------------------- io_delay: nop nop nop nop ret ;--------------數據段-------------------------------------------- show_position dw 0 ;80*25=2000 2^16= pgdt dw 0 dd gdt_basic ;GDT的物理地? interrupt_des dw 256*8-1 ;idt dd interrupt_basic times 510-($-$$) db 0 db 0x55 ;引導識別標示 db 0xaa
效果圖可能不是太明顯確實是響應定時中斷產生的輸出: