• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-80  評論-24  文章-0  trackbacks-0
            上一篇日志主要講解了對8259A以及中斷向量表的初始化。
            下面的程序主要是時鐘中斷、硬盤中斷以及系統調用入口函數的實現。

              1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
              2 ; 每個進程的內核態堆棧頂部棧幀應該是這樣的
              3 ; ss
              4 ; esp
              5 ; eflags
              6 ; cs
              7 ; eip
              8 ; eax
              9 ; ecx
             10 ; edx
             11 ; ebx
             12 ; ebp
             13 ; esi
             14 ; edi
             15 ; ds
             16 ; es
             17 ; fs
             18 ; gs
             19 ; 其中ss、esp、eflags、cs、eip是在發生中斷時CPU自動壓棧的
             20 ; 而其他的是由中斷程序壓棧的,這個順序不能改變,否則后果自負
             21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
             22 
             23 CS_OFFSET    equ 0x30
             24 ESP_OFFSET    equ 0x38
             25 SS_OFFSET    equ 0x3c
             26 
             27 ; 一個宏,因為所有的irq中斷函數都是先保存現場并將數據段等堆棧段
             28 ; 切換到內核態,因此,該操作所有的irq中斷入口函數均相同
             29 ; 故寫成宏節省空間^_!
             30 %macro save_all 0
             31     push eax
             32     push ecx
             33     push edx
             34     push ebx
             35     push ebp
             36     push esi
             37     push edi
             38     push ds
             39     push es
             40     push fs
             41     push gs
             42     mov si, ss
             43     mov ds, si
             44     mov es, si
             45     mov gs, si
             46     mov fs, si
             47 %endmacro
             48 
             49 ; 一個宏,恢復現場
             50 %macro recover_all 0
             51     pop gs
             52     pop fs
             53     pop es
             54     pop ds
             55     pop edi
             56     pop esi
             57     pop ebp
             58     pop ebx
             59     pop edx
             60     pop ecx
             61     pop eax
             62 %endmacro
             63 
             64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
             65 ; 時鐘中斷處理程序
             66 ; 這是整個系統中最要求“速度快”的程序,因為時鐘中斷沒隔1/HZ(s)
             67 ; 就發生一次,大概它是整個系統調用最頻繁的函數,所以需要該函數
             68 ; 盡量短,沒有必要的函數調用盡量避免。
             69 ; 另外判斷中斷重入minix和linux采取的方法也是不一樣的,minix采用
             70 ; 一個全局變量,類似于信號量的概念;而linux的方法則比較簡單,它
             71 ; 直接獲取存儲在內核堆棧中的cs段寄存器的RPL值來判斷被中斷的程序
             72 ; 是內核態程序的還是用戶態的進程;我們打算采用linux的辦法,雖然
             73 ; minix方法更酷,但是linux的顯然更加簡單:)
             74 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
             75 int_clock:
             76     save_all
             77     ; 增加心跳數
             78     inc dword [boot_heartbeat]
             79 
             80     ; 發送EOI指令結束本次中斷
             81     mov ax, 0x20
             82     out 0x20, al
             83     sti
             84     
             85     mov eax, [esp + CS_OFFSET]
             86     and eax, 0x03
             87     cmp eax, 0x0 ; 如果CS段寄存器的RPL為0,則說明是由內核態進入時鐘中斷,則是中斷重入
             88     je return
             89     call pre_schedule
             90 return:
             91     recover_all
             92     iretd
             93 
             94 int_keyboard:
             95     save_all
             96 
             97     recover_all
             98     iretd
             99 
            100 int_serial_port2:
            101     save_all
            102 
            103     recover_all
            104     iretd
            105 
            106 int_serial_port1:
            107     save_all
            108 
            109     recover_all
            110     iretd
            111 
            112 int_lpt2:
            113     save_all
            114 
            115     recover_all
            116     iretd
            117 
            118 int_floppy:
            119     save_all
            120 
            121     recover_all
            122     iretd
            123 
            124 int_lpt1:
            125     save_all
            126 
            127     recover_all
            128     iretd
            129 
            130 int_rtc:
            131     save_all
            132 
            133     recover_all
            134     iretd
            135 
            136 int_ps_2_mouse:
            137     save_all
            138 
            139     recover_all
            140     iretd
            141 
            142 int_fpu_fault:
            143     save_all
            144 
            145     recover_all
            146     iretd
            147 
            148 ;硬盤中斷處理程序
            149 int_at_win:
            150     save_all
            151 
            152     mov byte [gs:0xb8006], 'e'; 試驗硬盤中斷是否成功:)
            153 
            154     ; 發送EOI指令給從8259A結束本次中斷
            155     mov ax, 0x20
            156     out 0xa0, al
            157     nop
            158     nop
            159     ; 發送EOI指令給主8259A結束本次中斷
            160     out 0x20, al
            161     nop
            162     nop
            163 
            164     ; 調用該函數使buf_info緩沖區生效
            165     call validate_buffer
            166 
            167     recover_all
            168     iretd
            169 
            170 ; 默認的中斷處理函數,所有的未定義中斷都會調用此函數
            171 int_default:
            172     save_all
            173     recover_all
            174     iretd
            175 
            176 ; 注意從系統調用返回時不需要從棧中彈出eax的值,因為eax保存著調用
            177 ; 對應系統調用之后的返回值
            178 %macro recover_from_sys_call 0
            179     pop gs
            180     pop fs
            181     pop es
            182     pop ds
            183     pop edi
            184     pop esi
            185     pop ebp
            186     pop ebx
            187     pop edx
            188     pop ecx
            189     add esp, 4 * 1
            190 %endmacro
            191 
            192 ; 系統調用框架,系統調用采用0x30號中斷向量,利用int 0x30指令產
            193 ; 生一個軟中斷,之后便進入sys_call函數,該函數先調用save_all框
            194 ; 架保存所有寄存器值,然后調用對應系統調用號的入口函數完成系統調用
            195 ; 注意?。。。。∠到y調用默認有三個參數,分別利用ebx、ecx、edx來
            196 ; 傳遞,其中eax保存系統調用號
            197 sys_call:
            198     save_all
            199 
            200     sti
            201 
            202     push ebx
            203     push ecx
            204     push edx
            205     call [sys_call_table + eax * 4]
            206     add esp, 4 * 3
            207 
            208     recover_from_sys_call
            209 
            210     cli
            211 
            212     iretd
            213 

            目前不打算對時鐘中斷處理函數、硬盤中斷處理函數以及系統調用入口框架做解釋,因為后序部分將會專門分章節進行講解。這里只說在發生類似時鐘中斷、硬盤中斷以及軟中斷int X的系統調用時,CPU如何處理的。
            初始情況下假設CPU正在用戶態執行某一個進程a,此時的CS、DS、ES、FS、SS均指向用戶態進程a的段基地址。
            當時鐘中斷等中斷抑或int X的系統調用到來的時候,CPU會自動從TSS中尋找用戶態進程a預先保存的ring0下的SS0和ESP0,然后將SS和ESP寄存器值轉換成SS0和ESP0,即切換到核心態堆棧段(注意,每個進程都可能會有一個自己獨立的ring0堆棧段,這樣可以更好的實現進程切換時對內核態的保護,linux對此的做法是在創建一個進程的時候在進程頁的末尾申請一塊空間作為該進程對應的ring0堆棧段),然后將用戶態下的SS、ESP、EFLAGS、CS、EIP的值保存在新的SS0:ESP0堆棧段中。注意以上過程都是CPU自動完成的,然后再通過save_all宏手工將eax、ecx、edx、ebx、ebp、esi、edi、ds、es、fs、gs壓入堆棧,然后再執行相應的中斷處理程序。完成之后會通過recover_all再按序恢復所有的常規寄存器。然后調用iretd命令從堆棧中彈出EIP、CS、EFLAGS、ESP、SS寄存器,然后再重新恢復進程a的運行。這一過程需要對GDT、IDT、TSS以及保護模式下的中斷門、陷阱門有所了解才可以。
            不過還有一種情況此處沒有涉及:當發生進程切換的時候現場保護與恢復的過程如何呢?這一過程將在后面敘述。

              1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
              2 ; 以下為庫函數
              3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
              4 
              5 ; 對端口進行寫操作
              6 void out_byte(unsigned short port, unsigned char value);
              7 out_byte:
              8     mov edx, [esp + 4 * 1]
              9     mov al, [esp + 4 * 2]
             10     out dx, al
             11     nop
             12     nop
             13     ret
             14 
             15 ; 對端口進行讀操作
             16 ; uint8 in_byte(unsigned short port);
             17 in_byte:
             18     mov edx, [esp + 4 * 1]
             19     xor eax, eax
             20     in al, dx
             21     nop
             22     nop
             23     ret
             24 
             25 ; 對從指定端口進行讀操作,讀出的n個字節數據放入buf緩沖區中
             26 void read_port(uint16 port, void* buf, int n);
             27 read_port:
             28     mov    edx, [esp + 4 * 1]    ; port
             29     mov    edi, [esp + 4 * 2]    ; buf
             30     mov    ecx, [esp + 4 * 3]    ; n
             31     shr    ecx, 1
             32     cld
             33     rep    insw
             34     ret
             35 
             36 ; 對從指定端口進行寫操作,數據源在buf緩沖區中,寫n個字節
             37 void write_port(uint16 port, void* buf, int n);
             38 write_port:
             39     mov    edx, [esp + 4 * 1]    ; port
             40     mov    edi, [esp + 4 * 2]    ; buf
             41     mov    ecx, [esp + 4 * 3]    ; n
             42     shr    ecx, 1
             43     cld
             44     rep    outsw
             45     ret
             46 
             47 ; 安裝指定中斷號的中斷處理程序
             48 extern int install_int_handler(uint8 INT_IV, void* handler);
             49 install_int_handler:
             50     mov eax, [esp + 4 * 1] ; 中斷向量號
             51     mov ebx, [esp + 4 * 2] ; 中斷程序入口
             52     cmp eax, 256
             53     jae failed
             54     cmp eax, 0
             55     jbe failed
             56     push PRIVILEGE_KERNEL
             57     push ebx
             58     push INT_GATE_386
             59     push eax
             60     call init_idt
             61     add esp, 4 * 4
             62 failed:
             63     ret
             64     
             65 ; 卸載指定中斷號的中斷處理程序
             66 extern int uninstall_int_handler(uint8 INT_IV);
             67 uninstall_int_handler:
             68     mov eax, [esp + 4 * 1] ; 中斷向量號
             69     cmp eax, 256
             70     jae failed
             71     cmp eax, 0
             72     jbe failed
             73     push PRIVILEGE_KERNEL
             74     push int_default
             75     push INT_GATE_386
             76     push eax
             77     call init_idt
             78     add esp, 4 * 4
             79     ret
             80     
             81 ; 安裝指定中斷號的系統調用入口
             82 extern int install_sys_call_handler(uint8 INT_IV, void* handler);
             83 install_sys_call_handler:
             84     mov eax, [esp + 4 * 1] ; 中斷向量號
             85     mov ebx, [esp + 4 * 2] ; 中斷程序入口
             86     cmp eax, 256
             87     jae failed_inst_sys
             88     cmp eax, 0
             89     jbe failed_inst_sys
             90     push PRIVILEGE_USER
             91     push ebx
             92     push INT_TRAP_386
             93     push eax
             94     call init_idt
             95     add esp, 4 * 4
             96 failed_inst_sys:
             97     ret
             98 
             99 ; 打開對應向量號的硬件中斷
            100 ; 注意,這里傳入的參數是硬件中斷對應的中斷向量號
            101 ; 需要將該中斷向量號轉化為在8259A上的索引號
            102 void enable_hwint(uint8 IV);
            103 enable_hwint:
            104     mov ecx, [esp + 4 * 1]
            105     cmp cl, IRQ0_IV
            106     jae master_1
            107     jmp ret_1
            108 master_1:
            109     cmp cl, IRQ8_IV
            110     jae slave_1
            111     push MASTER_CTL_MASK_8259
            112     call in_byte
            113     add esp, 4 * 1
            114     sub cl, IRQ0_IV
            115     mov bl, 1
            116     shl bl, cl
            117     xor bl, 0xff
            118     and al, bl
            119     push eax
            120     push MASTER_CTL_MASK_8259
            121     call out_byte
            122     add esp, 4 * 2
            123     jmp ret_1
            124 slave_1:
            125     cmp cl, IRQ15_IV
            126     ja ret_1
            127     push SLAVE_CTL_MASK_8259
            128     call in_byte
            129     add esp, 4 * 1
            130     sub cl, IRQ8_IV
            131     mov bl, 1
            132     shl bl, cl
            133     xor bl, 0xff
            134     and al, bl
            135     push eax
            136     push SLAVE_CTL_MASK_8259
            137     call out_byte
            138     add esp, 4 * 2
            139 ret_1:
            140     ret
            141 
            142 ; 關閉對應向量號的硬件中斷
            143 ; 注意,這里傳入的參數是硬件中斷對應的中斷向量號
            144 ; 需要將該中斷向量號轉化為在8259A上的索引號
            145 void disable_hwint(uint8 IV);
            146 disable_hwint:
            147     mov ecx, [esp + 4 * 1]
            148     cmp cl, IRQ0_IV
            149     jae master_2
            150     jmp ret_2
            151 master_2:
            152     cmp cl, IRQ8_IV
            153     jae slave_2
            154     push MASTER_CTL_MASK_8259
            155     call in_byte
            156     add esp, 4 * 1
            157     sub cl, IRQ0_IV
            158     mov bl, 1
            159     shl bl, cl
            160     or al, bl
            161     push eax
            162     push MASTER_CTL_MASK_8259
            163     call out_byte
            164     add esp, 4 * 2
            165     jmp ret_2
            166 slave_2:
            167     cmp cl, IRQ15_IV
            168     ja ret_2
            169     push SLAVE_CTL_MASK_8259
            170     call in_byte
            171     add esp, 4 * 1
            172     sub cl, IRQ8_IV
            173     mov bl, 1
            174     shl bl, cl
            175     or al, bl
            176     push eax
            177     push SLAVE_CTL_MASK_8259
            178     call out_byte
            179     add esp, 4 * 2
            180 ret_2:
            181     ret
            182 
            183 [SECTION .data]
            184 idt:
            185         ; idt表共可存放256個中斷門描述符
            186         times 256 * 8 db 0
            187 
            188 idtr:    dw $ - idt - 1
            189         dd idt
            190 

            上面這段函數比較簡單,是一些庫函數,主要包括對端口進行讀、寫操作;以及安裝或者卸載中斷處理程序,方法就是通過接受中斷號,將IDT中對應的中斷描述符置空或初始化;還有安裝系統調用,安裝系統調用和安裝中斷處理程序幾乎相同,唯一的區別就是門描述符的類型以及門描述符的特權級不同,中斷處理程序是中斷門,對應的門描述符DPL為0,系統調用是陷阱門,對應的DPL為3,這是因為中斷門只需要檢查CPL>=處理程序的DPL,而陷阱門除了檢查該條件以外還檢查CPL<=陷阱門描述符的DPL。這樣做的原因是陷阱門是由程序引起的,諸如系統調用之類的,需要從程序中跳入;而中斷是硬件引起的。
            再后面函數就是打開或關閉8259A上的硬件中斷。

            關于init.s文件的描述就到此為止。之后還會對進程切換做進一步的闡釋。
            posted on 2012-02-14 01:06 myjfm 閱讀(520) 評論(0)  編輯 收藏 引用 所屬分類: 操作系統
            麻豆久久久9性大片| 久久久久国色AV免费观看| 久久人人爽人人爽AV片| 久久精品中文字幕无码绿巨人| 中文成人无码精品久久久不卡| 久久午夜无码鲁丝片午夜精品| 久久久久亚洲爆乳少妇无| 国内精品久久久久久久影视麻豆 | 久久婷婷五月综合国产尤物app| 亚洲国产成人久久笫一页| 一本久久a久久精品综合香蕉| 性欧美大战久久久久久久| 青青草原综合久久大伊人| 亚洲国产另类久久久精品黑人 | 久久99精品国产一区二区三区 | 久久综合狠狠色综合伊人| 国产成人无码精品久久久久免费| 大美女久久久久久j久久| 久久久久人妻精品一区三寸蜜桃| 欧美大战日韩91综合一区婷婷久久青草 | 久久亚洲AV无码精品色午夜 | 亚洲AV日韩精品久久久久久| 一本色道久久HEZYO无码| 国产精品久久自在自线观看| 91精品婷婷国产综合久久| 久久久久无码精品国产app| 久久久久久国产精品美女| 精品蜜臀久久久久99网站| 国产精品久久久99| 性欧美丰满熟妇XXXX性久久久| 9久久9久久精品| 亚洲va久久久久| 国内精品久久久久影院免费 | 亚洲人成网亚洲欧洲无码久久| 99久久精品毛片免费播放| 青青草原综合久久大伊人导航| 91精品国产高清91久久久久久| 理论片午午伦夜理片久久 | 久久婷婷五月综合成人D啪| 国产一区二区三区久久| 久久亚洲国产精品123区|