Board logo

标题: 深入理解 x86/x64 的中断体系 [打印本页]

作者: yuyang911220    时间: 2015-10-20 21:18     标题: 深入理解 x86/x64 的中断体系

1. 实模式下的中断机制x86 processor 在加电后被初始化为 real mode 也称为 real-address mode,关于实模式请详见文章:http://www.mouseos.com/arch/001.html
processor 执行的第一条指针在 0xFFFFFFF0 处,这个地址经过 North Bridge(北桥)和 South ridge(南桥)芯片配合解码,最终会访问到固化的 ROM 块,同时,经过别名机制映射在地址空间低端,实际上等于 ROM 被映射到地址空间最高端低端位置。
此时在系统的内存里其实并不存在 BIOS 代码,ROM BIOS 的一部分职责是负责安装 BIOS 代码进入系统内存。
  
jmp far f000:e05b      
典型是这条指令就是 0xFFFFFFF0 处的 ROM BIOS 指令,执行后它将跳到 0x000FE05B 处,这条指令的作用很大:
前面说过,此时内存中也不存在 BIOS,也就是说 IVT(中断向量表)也是不存在的,中断系统此时是不可用的,那么由 ROM BIOS 设置 IVT 。
1.1 中断向量表(IVT)IDTR.base 被初始化为 0,ROM BIOS 将不会对 IDTR.base 进行更改,因此如果实模式 OS 不更改 IDTR.base 的值,这意味着 IVT0 的位置上,典型的如: DOS 操作系统。
保护模式IDTR.base 将向不再是中断向量表,而是中断描述符表。不再称为 IVT 而是 IDT。那是因为:
在 x86/x64 体系中允许有 256 个中断存在,中断号从 0x00 - 0xff,共 256 个中断,如图:

上面这个图是实模式下的 IVT 表,每个向量占据 4 个字节,中断服务例程入口是以 segmentffset 形式提供的,offset 在低端,segment 在高端,整个 IVT 表从地址 0x0 - 0x3FF,占据了 1024 个字节,即 1K bytes
1.2 改变中断向量表地址事实上,我们完全可以在实模式下更改 IVT 的地址,下面的代码作为示例:
  

; ****************************************************************
; * boot.asm for interrupt demo(real mode) on x86                *
; *                                                              *
; * Copyright (c) 2009-2011                                      *
; * All rights reserved.                                         *
; * mik                                                          *
; * visit web site : www.mouseos.com                             *
; * bug send email : mik@mouseos.com                             *
; *                                                              *
; *                                                              *
; * version 0.01 by mik                                          *  
; ***************************************************************

BOOT_SEG        equ 0x7c00        ; boot module load into BOOT_SEG

;----------------------------------------------------------
; Now, the processor is real mode
;----------------------------------------------------------
        bits 16
        org BOOT_SEG                   ; for int 19
        
start:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, BOOT_SEG
        
        mov si, msg1
        call printmsg
        sidt [old_IVT]                        ; save old IVT
        mov cx, [old_IVT]
        mov [new_IVT], cx                ; limit of new IVT
        mov dword [new_IVT+2], 0x8000        ; base of new IVT
        mov si, [old_IVT+2]
        mov di, [new_IVT+2]
        rep movsb                        
        lidt [new_IVT]                        ; set new IVT
        
        mov si, msg2
        call printmsg

        jmp $

;-----------------------------------
; printmsg() - print message
;-----------------------------------
printmsg:
        mov ah, 0x0e
        xor bh, bh
print_loop:
        lodsb
        test al,al
        jz done
        int 0x10
        jmp print_loop
done:        
        ret

old_IVT         dw 0                        ; limit of IVT
                dd 0                        ; base of IVT
new_IVT         dw 0                        ; limit of IVT
                dd 0                        ; base of IVT

        
msg1            db 'Hi, print message with old IVT', 10,13, 0
msg2            db 'Now,pirnt message with new IVT', 13, 10, 0

        
times 510-($-$$) db 0
        
        dw 0xaa55
        
; end of boot.asm
     
  在 vmware 上这段代码的执行结果如图:
  
  这段代码在实模式下将 IVT 表复制到 0x8000 位置上,然后将 IVT 地址设为 0x8000 上,这样完全可以正常工作。正如代码上看到的,我做:
  




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0