首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

深入理解 x86/x64 的中断体系

深入理解 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 处,这条指令的作用很大:
  • 更新 CS.base 使 processor 变成纯正的 real mode
  • 跳转到低端内存,使之进入 1M 低端区域
前面说过,此时内存中也不存在 BIOS,也就是说 IVT(中断向量表)也是不存在的,中断系统此时是不可用的,那么由 ROM BIOS 设置 IVT 。
1.1 中断向量表(IVT)IDTR.base 被初始化为 0,ROM BIOS 将不会对 IDTR.base 进行更改,因此如果实模式 OS 不更改 IDTR.base 的值,这意味着 IVT0 的位置上,典型的如: DOS 操作系统。
保护模式IDTR.base 将向不再是中断向量表,而是中断描述符表。不再称为 IVT 而是 IDT。那是因为:
  • 在实模式下,DITR.base 指向的表格项直接给出中断服务例程(Interrupt Service Routine)的入口地址。
  • 在保护模式下,并不直接给出入口地址,而是门描述符(Interrupt/Trap/Task gate),从这些门描述符间接取得中断服务例程入口。
在 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 上,这样完全可以正常工作。正如代码上看到的,我做:
  
  • 使用 sidt 指令取得 IDTR 寄存器的值,即 IVT 的 limit base 值,保存在 old_IVT 里
  • 设置 new_IVT 值,limit 等于 old_IVT 的 limit,base 设为 0x8000
  • 将 IVT 表复制到 0x8000 处
  • 使用 lidt 指令加载 IDTR 寄存器,即设 IVT 表在 0x8000
继承事业,薪火相传
返回列表