進入保護模式(六)保護模式下中斷的安裝

1、中斷

        上篇原本打算先實現個在任務狀態運行的例子,可是代碼有問題(編譯錯代碼了),任務那部分確實還不是很熟悉; html

       本篇的目的:1.實現實例化中斷的描述符 架構

                       2.實現時鐘中斷 oop

        對於中斷分類暫且還沒搞太清楚,這裏先無論,直接看怎麼安裝的。 測試

        中斷在實模式下是直接用的,例如:int 10h spa

        可是保護模式下是的實現,跟裝載GDT很相似。 .net

        只是描述符要用到GDT的選擇子+偏移量構成,也就是經過中斷調用的實際是一個處理的方法。 code

       lidt的描述符結構 htm

 

2、簡單的代碼

       此次代碼是好的  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

3、時鐘中斷的實現

        這裏主要是對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

效果圖可能不是太明顯確實是響應定時中斷產生的輸出:

相關文章
相關標籤/搜索