鱼C论坛

 找回密码
 立即注册

Windows内核学习-采用ReactOS源码(3)

热度 2已有 724 次阅读2014-10-25 17:02 |个人分类:Windows

KiIntSystemCall()函数和KiFastSystemCall()的代码是由几段汇编组成的。
首先看KiIntSystemCall的汇编代码:
PUBLIC _KiIntSystemCall@0
.PROC _KiIntSystemCall@0
    FPO 0, 0, 0, 0, 0, FRAME_FPO

    /* 使EDX指向堆栈参数块的七起点并执行中断 */
    lea edx, [esp+8]
    int HEX(2E)

    /* 返回caller */
    ret

.ENDP
再看KiFastSystemCall,采用快速调用函数需要另一段代码KiFastSystemRet配合。
PUBLIC _KiFastSystemCall@0
.PROC _KiFastSystemCall@0
    FPO 0, 0, 0, 0, 0, FRAME_FPO

    /* 将ESP的数据放到EDX内,并执行SYSENTER */
    mov edx, esp
    sysenter

.ENDP

PUBLIC _KiFastSystemCallRet@0
.PROC _KiFastSystemCallRet@0
    FPO 0, 0, 0, 0, 0, FRAME_FPO

    /* 返回caller */
    ret

.ENDP
这些代码都出自./dll/ntdll/dispatch/i386/dispatch.S中。两种方法的不同点在于后者寄存器EDX(8个GPR的一个,32位CPU的数据寄存器,Extended Data Register)不再指向堆栈上的参数块,而是指向KiFastSystemCall()的返回地址所在的位置。两个函数都在用户空间的动态链接库ntdll.dll中,这个dll一直驻留在内存中:不管在什么进程中,其出现位置都是相同的。
内核在初始化阶段,处理器的CPUID判断其是否支持快速系统调用,而从ntdll.dll的映像中找到KiIntSystemCall()和KiFastSystemCall()的地址,将其写入用户空间的地址0x7ffe0300。书中讲系统空间的0xffdf0000与其映射的是同一物理内存(需要依据……)。

何谓CPU进入系统空间?

①CPU的运行状态从用户态转为系统态,拥有了执行"特权指令"的能力。

②CPU进入系统态后,可以访问内存中的系统区(内核所在的区域),而在用户态下是无法访问的。

③当前进程使用的堆栈,从用户态切换到系统态。堆栈原先的内容(用户态),以及用户空间的堆栈指针,被压入系统空间堆栈。同时被压入的,还有EFLAGS、CS、EIP的内容。

④关闭中断,依照中断向量从IDT中找到相应的表项,并根据表项提供的程序入口进入相应的中断服务程序。

中断向量Interrupt vector)是中断服务程序的入口地址,或中断向量表(它是一个数组)的下标,中断服务程序的入口地址存放在该数组中。注意这里所说的中断向量既包括外部中断的也包括异常和自陷。内核入口处的程序对于自陷、中断、异常这三者基本上是相同的。下面是Windows内核中的“中断向量表”IDT的设置:

PUBLIC _KiIdt

_KiIdt:

/* 这是我们在这个文件中处理的软件中断表:        */

idt _KiTrap00,         INT_32_DPL0  /* INT 00: 除法错误 (#DE)           */

idt _KiTrap01,         INT_32_DPL0  /* INT 01: 调试异常 (#DB)           */

idt _KiTrap02,         INT_32_DPL0  /* INT 02: NMI中断                  */

idt _KiTrap03,         INT_32_DPL3  /* INT 03: 断点异常 (#BP)           */

idt _KiTrap04,         INT_32_DPL3  /* INT 04: 溢出异常 (#OF)           */

idt _KiTrap05,         INT_32_DPL0  /* INT 05: 绑定超出范围 (#BR)       */

idt _KiTrap06,         INT_32_DPL0  /* INT 06: 无效的操作码编码 (#UD)   */

idt _KiTrap07,         INT_32_DPL0  /* INT 07: 设备不可用 (#NM)         */

idt _KiTrap08,         INT_32_DPL0  /* INT 08: 双重故障异常 (#DF)       */

idt _KiTrap09,         INT_32_DPL0  /* INT 09: RESERVED               */

idt _KiTrap0A,         INT_32_DPL0  /* INT 0A: 无效TSS异常 (#TS)       */

idt _KiTrap0B,         INT_32_DPL0  /* INT 0B: 段不存在 (#NP)          */

idt _KiTrap0C,         INT_32_DPL0  /* INT 0C: 堆栈错误异常 (#SS)      */

idt _KiTrap0D,         INT_32_DPL0  /* INT 0D: 一般保护 (#GP)          */

idt _KiTrap0E,         INT_32_DPL0  /* INT 0E: 页面错误异常 (#PF)      */

idt _KiTrap0F,         INT_32_DPL0  /* INT 0F: RESERVED               */

idt _KiTrap10,         INT_32_DPL0  /* INT 10: x87 FPU错误 (#MF)      */

idt _KiTrap11,         INT_32_DPL0  /* INT 11: 对齐检查异常 (#AC)      */

idt _KiTrap0F,         INT_32_DPL0  /* INT 12: 机器检查异常 (#MC)      */

idt _KiTrap0F,         INT_32_DPL0  /* INT 13: SIMD FPU异常 (#XF)     */

REPEAT 21

idt _KiTrap0F,         INT_32_DPL0  /* INT 14-28: 未定义中断           */

ENDR

idt _KiRaiseSecurityCheckFailure, INT_32_DPL3

                                    /* INT 29: __fastfail处理程序     */

idt _KiGetTickCount,   INT_32_DPL3  /* INT 2A: 获取时钟计数处理程序    */

idt _KiCallbackReturn, INT_32_DPL3  /* INT 2B: 用户模式回调返回        */

idt _KiRaiseAssertion, INT_32_DPL3  /* INT 2C: 调试断言处理程序        */

idt _KiDebugService,   INT_32_DPL3  /* INT 2D: 调试服务程序            */

idt _KiSystemService,  INT_32_DPL3  /* INT 2E: 系统调用服务处理程序     */

idt _KiTrap0F,         INT_32_DPL0  /* INT 2F: RESERVED              */

i = HEX(30)

REPEAT 208

    GENERATE_IDT_STUB %i

    i = i + 1

ENDR

我们要知道,其实中断向量表每一行都是一段汇编代码,每一行的idt是个宏汇编(出处./ntoskrnl/include/internal/i386/asmmacro.S):

//

// @name IDT

//

// 这个宏为一个给定的处理程序(handler)新建一个IDT条目

//

// @param Handler

//        指向IDT处理程序的指针

//

// @param Bits

//        要关联的位描述符Bits

//

// @remark 无.

//

MACRO(idt, Handler, Bits)

    .long VAL(Handler)

    .short VAL(Bits)

    .short KGDT_R0_CODE

ENDM

从代码的注释可以看出,其中有一行是0x14~0x28共用的,这一行的前后有汇编命令REPEAT 21和ENDR,表示这一行重复出现21次,凡是这个范围内的中断向量每一个都有这么一行。此外,中断向量表最后几行是用来生成0x30~0xff的表项的。以i为参数调用GENERATE_IDT_STUB共208次。每次调用后都递增i。GENERATE_IDT_STUB的定义为

MACRO(GENERATE_IDT_STUB, Vector)

idt _KiUnexpectedInterrupt&Vector, INT_32_DPL0

ENDM

所以一开始所有外部中断向量的处理函数均为KiUnexpectedInterrupt。Unexpected的原因是一开始还没有将这些向量用于任何外部设备,所以不应该有中断。经过汇编工具整理,就会成为一张256行的中断向量表,每行占8个字节,所以共有2k字节。

如前所述,这个中断向量表只是给人看的,不是供CPU用的,因为CPU对中断向量表项的格式有特殊的要求。


路过

鸡蛋
2

鲜花

握手

雷人

刚表态过的朋友 (2 人)

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 15:51

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部