http://qsyang.yeah.net
现代微机原理与接口技术
1
第 10章 PC机的高级编程技术
http://qsyang.yeah.net
现代微机原理与接口技术
2
10.1 PC机环境下软件对接口的访问层次裸机
BIOS 直接访问操作系统驱动程序间接访问应用程序
http://qsyang.yeah.net
现代微机原理与接口技术
3
1.直接访问层次特点,可以直接进行内存和端口的访问,也可以自行决定是否在实模式和保护模式间切换
。通常所有的端口和内存都是对程序员开放的。
工具,汇编语言或 C语言。
应用,BIOS都是基于这种低级层次用汇编来编写的。驱动程序也有使用这种方法的。
优点,能够编写速度最快,占用空间最小的有效代码。
缺点,需要对硬件和接口有很熟悉的了解。
要会汇编,或熟练使用 C语言的指针。
不利于增加对新设备的控制。
http://qsyang.yeah.net
现代微机原理与接口技术
4
2.BIOS访问层次特点,通过 BIOS提供的功能调用间接地对内存或端口访问,从而控制硬件。
工具,汇编语言或 C语言。
应用,驱动程序有些会使用这些功能调用。需要获得高效率的应用程序也采用这种方法。
优点,能够编写速度较快的有效代码。
可以不需要编写直接对硬件进行控制的代码。
缺点,需要对底层信号有所了解。
增加对新设备的控制不是很方便,但好于低级层次。
http://qsyang.yeah.net
现代微机原理与接口技术
5
3.驱动程序层次特点,使用 BIOS功能调用和直接内存访问的方法编写符合特定操作系统管理规范的设备驱动程序。
工具,VC++与 DDK开发包,或第三方开发工具如 DriverStudio。
应用,在操作系统层面上的设备控制,并为应用程序提供 API支持。
优点,既控制硬件,又保证操作系统的完整与安全。
缺点,需要对底层信号有所了解。
需要对操作系统的各个管理模块有深入的了解。
http://qsyang.yeah.net
现代微机原理与接口技术
6
4.应用层次特点,使用操作系统各种驱动程序所提供的功能调用或 API函数间接对硬件或内存进行访问。
工具,VC++,Delphi,Java等。
应用,编写面向终端用户的各类应用程序。
优点,无需对硬件控制有太多了解,只需完成应用层面的工作就可以,而且还保证操作系统的完整与安全。
缺点,需要了解大量的 API和功能调用函数的功能。
由于是间接调用,所以代码的效率和编译系统有很大的关系。
http://qsyang.yeah.net
现代微机原理与接口技术
7
16位段地址 16位段内偏移:
16位段地址
16位段内偏移
(左移四位)
+
20位物理地址=
6417H∶ 0100H
6417H× 10H + 0100H = 64170H + 0100H = 64270H
采用了内存分段的办法,内存分为若干段,段的大小根据需要决定,最大为 64KB
10.2.1 实地址模式的存储管理(同 PC/XT)
10.2 Pentium 4的内存管理 ——接口直接访问
http://qsyang.yeah.net
现代微机原理与接口技术
8
000000
0A0000
100000
110000
≈≈
FFFFFF
640KB常规内存
384KB高端内存
64KB高内存区
1~4095MB
扩展内存存放用户程序和
DOS驻留部分存放显存、网卡和部分用户的 DOS驱动程序和
BIOS
存放部分 DOS驻留程序大于 1M以上的 扩展内存,DOS下不能直接访问,需要用 XMS规范使用。可利用 DOS调用或
BIOS调用来使用。
http://qsyang.yeah.net
现代微机原理与接口技术
9
10.2.2 保护模式下使用的系统地址寄存器
GDTR — 48位的全局描述符表寄存器全局描述符表 32位线性地址 16位界限值
IDTR — 48位的中断描述符表寄存器中断描述符表 32位线性地址 16位界限值
TR — 16位的任务状态段寄存器
TSS的 16位选择字
LDTR — 16位的局部描述符选择字寄存器
LDT的 16位选择字
http://qsyang.yeah.net
现代微机原理与接口技术
10
10.2.3 保护模式下 Pentium 4的段式存储管理
1,段式管理的地址变换段寄存器的 15~2位 偏移量
45 32 31 0
段描述符段表
32位线性地址 物理地址逻辑地址段基址
Pentium 系列的虚拟地址空间是 246= 64TB。
http://qsyang.yeah.net
现代微机原理与接口技术
11
2,段描述符
D7 D0
段界限 7~0
段界限 15~8
基址 7~0
基址 15~8
基址 23~16
基址 31~24
TYPES
AVL
DPLP
G D/B 0 段界限 19~16
0
1
2
3
4
5
6
7
http://qsyang.yeah.net
现代微机原理与接口技术
12
D7 D0
AVLG D/B 0 段界限 19~16
用户的操作系统可用位
D/B位代码段 (D位 )
D=1 使用 32位操作系统和 32位寻址方式
D=0 使用 16位操作系统和 16位寻址方式数据段 (B位 )
B=1 使用 ESP寄存器,上限为 FFFFFFFFH
B=0 使用 SP寄存器,上限为 FFFFH
G=0 段长以 1字节为单位
G=1 段长以 4K字节为单位
D/B位粒度位
http://qsyang.yeah.net
现代微机原理与接口技术
13
AWREDCE=0E=1S=1DPLP
D7 D0
存在位 特权位
S=1是非系统段
S=0是系统描述符代码段标志数据段标志兼容位可读位访问位扩展方向位可写位非系统段中的第 5字节可执行位
http://qsyang.yeah.net
现代微机原理与接口技术
14
系统描述符中的 TYPE
http://qsyang.yeah.net
现代微机原理与接口技术
15
RPLTi
选择符(段寄存器)
15 2 1 0
索引
Ti=1 Ti=0
……
01
……
01LDT
LDT
LDT
GDT
基址界限选择符基址界限
LDTR GDTR
22
http://qsyang.yeah.net
现代微机原理与接口技术
16
#include "stdafx.h"
#include <stdio.h>
#include <wtypes.h> // wtypes.h定义了 WORDLONG,
//DWORD,WORD等数据类型
DWORDLONG gdtr,savegdt;
//下面是 GDT中将创建的数据段描述符表,基地址 0X00000F00,
//段界限为 0XFFFF,优先级为 3的在内存中的可写数据段
WORD descriptor[4]= {0xFFFF,0X0F00,0XF200,
0X0040};
int result[10];
int main( int argc,char* argv[])
{_asm
{ push ebp
sgdt gdtr // 将 GDTR寄存器的内容读取到
//gdtr开始的 6个字节中,其中
// 前两个字节给出 GDT的界限值,
//高 4个字节给出 GDT的基地址
http://qsyang.yeah.net
现代微机原理与接口技术
17
mov ebp,dword ptr [gdtr+2] // 将 gdt的基
// 地址读到 EBP中
add ebp,70h // 我们选择 70H偏移下的段描述
// 符( GDT中第 14个描述符)
lea edi,savegdt
mov esi,ebp
movsd // 以上 4条指令保存原来在 70H偏移上
movsd // 的描述符
mov edi,ebp
lea esi,descriptor;
movsd // 把我们的数据段描述符装入 70H
movsd // 偏移上
push es
mov ax,0073h // 选择字为描述符偏移 70H拼接上
// 低 3位控制位元,其中 Ti为 0,表
// 示访问 GDT,RPL为 11,为 3级优
// 先级,所以就为 73H
http://qsyang.yeah.net
现代微机原理与接口技术
18
mov es,ax // ES装入选择字 73H
lea edi,result // 将存放输出结果的变量
//的地址放在 EDI中
mov eax,1
mov ebx,1
}
_asm
{ mov cx,10
a1,mov es,[eax],eax
add eax,4
loop a1 // 上面 4条指令将向物理地址
// 0X00000F00处写 10个双字
}
_asm
{ mov cx,10
a2,mov eax,es,[ebx]
mov [edi],eax
http://qsyang.yeah.net
现代微机原理与接口技术
19
add ebx,4
add edi,4
loop a2 // 以上从物理地址 0X00000F00
// 处依次读出 10个数据存放在
// result数组中
}
_asm
{ pop es
pop ebp
}
printf( "result=");
for( int i=0; i<10; i++)
printf( "%d,",result[i]); // 输出结果
return 0;
}
http://qsyang.yeah.net
现代微机原理与接口技术
20
10.2.4 保护模式下 Pentium 4的虚拟页式存储管理主存
~
~
~
~
页框页面程序 1
程序 2
程序 3
http://qsyang.yeah.net
现代微机原理与接口技术
21
PGEPCE
831 7 6 5 4 3 2 1 0
MCE PAE PSE DE TSD VMEPVI保留,缺省为全 0 CR4
PAE PSE 物理地址位数 页面大小
0 0 32位 4KB
0 1 32位 4KB/4MB
1 0 36位 4KB
1 1 36位 4KB/2MB
http://qsyang.yeah.net
现代微机原理与接口技术
22
4KB分页方式
31 12 11 9 8 7 6 5 4 3 2 1 0
PWTPCD页表基地址 31~12 PRWUSAVL AD0页目录项
PWTPCD页框基地址 31~12 PRWUSAVL AD页表项
31 12 11 9 8 7 6 5 4 3 2 1 0
P=出现位,US=用户 /监督位,PCD是页 Cache禁止,D=Cache“脏”位,
RW=读 /写位,PWT=页写贯穿位,A=访问位,AVL=用户的操作系统可用位。而第 7位( PS)在 4KB分页中为 0
页目录
32位线性地址页目录项号 页面号 偏移
CR3
32位物理地址
31 22 21 12 11 0
页表低 12位高 20位
http://qsyang.yeah.net
现代微机原理与接口技术
23
4MB分页方式
31 22 8 7 6 5 4 3 2 1 0
PWTPCD页框基地址 31~22 PRWUSAD1页目录项
32位线性地址页目录项号 偏移
CR
3
32位物理地址
31 22 21 0
页目录低 22位高 10位
http://qsyang.yeah.net
现代微机原理与接口技术
24
31 5 4 3 2 1 0
PWTPCD32字节对齐的 PDPT基地址CR3寄存器
63 36 35 12 11 6 5 4 3 2 1 0
PWTPCD PAVLPDPT

4KB对齐的页目录基地址
(高 24位)
63 36 35 12 11 9 8 7 6 5 4 3 2 1 0
PWTPCD4KB对齐的页表基地址 PRWUSAVL A0页目录项
PWTPCD4KB对齐的页框基地址 PRWUSAVL AD页表项
63 36 35 12 11 9 8 7 6 5 4 3 2 1 0
0G
Pentium III 36位地址下的 4KB分页方式地址转换
32位线性地址页目录项号 页面号 偏移
CR3
36位物理地址
31 30 29 21 20 12 11 0
页目录 页表
PDPT项号页目录指针表
4× 64位 512× 64位 512× 64位低 12位高 24位
http://qsyang.yeah.net
现代微机原理与接口技术
25
32位线性地址页目录项号 偏移
CR3
36位物理地址
31 30 29 21 20 0
页目录
PDPT项号页目录指针表
4× 64位 512× 64位页目录项 PWTPCD2MB对齐的页框基地址 PRWUSAVL AD
63 36 35 21 20 12 11 9 8 7 6 5 4 3 2 1 0
1G
低 21位高 15位
Pentium III 36位地址下的 2MB分页方式地址转换
http://qsyang.yeah.net
现代微机原理与接口技术
26
计算机底层硬件操作系统内核与 VxD
操作系统提供的接口应用软件
10.3.1 虚拟机与 VxD的引入特权级 3
特权级 0
10.3 Windows 9x驱动程序编写
http://qsyang.yeah.net
现代微机原理与接口技术
27
Windows 9x
SYSVM
Win16地址空间
Win16程序
Win16程序
Win16程序
Win16程序
Win32程序
Win32地址空间
Win32程序
Win32地址空间
……
DOSVM
DOS程序
DOSVM
DOS程序……
http://qsyang.yeah.net
现代微机原理与接口技术
28
10.3.1保护模式下的 I/O端口访问执行 in,out指令
CPL ≤ IOPL?
IOPM相关位 =0?
进行 I/O操作否否产生一个一般保护异常是是
IOPM是对所有 VM都起作用的权限机制,它以位( bit)来代表每个端口。某位为 1,则该代表的端口被禁止访问;某位为 0;则允许访问该位所代表的端口。
IOPL用以表示指定的 I/O操作处于特权级的哪一级。它在
EFLAGS中。
CPL当前段的 I/O优先级,它实际上是 CS段选择符的第 0~第 1位。
http://qsyang.yeah.net
现代微机原理与接口技术
29
V86模式下( DOSVM)的 I/O端口访问执行 in,out指令
IOPM相关位 =0?
进行 I/O操作否产生一个一般保护异常是如何捕获一个端口的访问?
http://qsyang.yeah.net
现代微机原理与接口技术
30
http://qsyang.yeah.net
现代微机原理与接口技术
31
10.3.2 保护模式下对中断或异常的处理外部中断和处理器异常软中断
CPL ≤门描述符的 DPL?
是访问各类门描述符转移后代码段的 DPL≤CPL?
是执行 0特权级别中的中断处理程序禁止访问否否
http://qsyang.yeah.net
现代微机原理与接口技术
32
CPU根据中断向量表 IDT调用相应的 VMM异常处理程序,从而切换到 0特权级别。
其他各种 VxD可以通过安装回调例程来响应处理各种异常和中断,但是它们不能改变中断描述符表 IDT
中给出的各种 VMM异常处理程序。
VMM异常处理程序通过使用 CALL指令调用安装的各个回调例程 或自身处理异常。
对于硬件中断,VMM则将控制权交给 VPICD(虚拟可编程中断控制器)处理,VPICD就调用其他 VxD
通过系统服务 VPICD_Virtualize_IRQ安装的回调例程处理硬件中断。
一个回调例程要么处理中断和异常,要么忽略该中断,但是 它必须使用 RET指令返回到 VMM异常处理程序。
http://qsyang.yeah.net
现代微机原理与接口技术
33
VMM异常处理程序使用 IRET或 IRETD指令返回到虚拟机中,虚拟机中的应用程序重新获得控制从而继续执行。
Win32
程序虚拟机
VxD中的回调函数异常处理程序
VPICD
INT x CALL
RETIRET
IRET
硬件中断
RET
http://qsyang.yeah.net
现代微机原理与接口技术
34
思路:
在中断描述符表中 构造一个中断门描述符,使它的
DPL=3,这样它就可以被用户级的程序访问,将该中断门描述符的段选择字设为 028H,显然该选择字对应的代码段在 GDT中,由于其基地址为 00000000H,段界限为 FFFFFFFFH,所以现在中断门的偏移量就实际给出了中断处理程序入口的线性地址,我们只要把一个过程作为中断处理程序,这个过程就处在核心级里了。
程序如下:
特殊应用:如何利用保护模式下中断的处理流程设法使自己从用户级转到核心级?
http://qsyang.yeah.net
现代微机原理与接口技术
35
#include "stdafx.h"
#include <stdio.h>
#include <wtypes.h> // wtypes.h定义了 DWORDLONG,
//DWORD,WORD等数据类型
DWORD _cr0; // 用来保存 CR0寄存器的值
void _declspec( naked) newint3( void) // 运行在核心级的
// 中断 3处理程序
{
_asm
{ mov eax,cr0 // 这是必须在核心级才能执行的
// 特权指令
mov _cr0,eax
}
_asm iretd // 中断返回( 为什么不是 ret?)
}
http://qsyang.yeah.net
现代微机原理与接口技术
36
int main( int argc,char* argv[])
{DWORDLONG idtr,saveidt;
WORD newgate[4]={0x0000,0x0028,0xee00,0x0000};
// 中断门描述符,DPL=3
_asm
{ sidt idtr // 将 IDTR的值存在 idtr变量开
// 始的 6个字节中
mov ebx,DWORD ptr[idtr+2] // 把 IDT的
// 基地址读入 EBX寄存器
add ebx,24 // 选择中断 3作为进入核心级的
// 入口,中断 3的门描述符
// 的地址是 IDT基地址加上 3*8
// (每个门描述符 8个字节)
mov esi,ebx
lea edi,saveidt
http://qsyang.yeah.net
现代微机原理与接口技术
37
movsd // 保存原来中断 3的门描述符
movsd // 到 saveidt中
lea eax,newint3
mov newgate,ax
shr eax,16
mov [newgate+6],ax // 向新的中断描述符中填入
// 中断处理程序的入口偏移量
lea esi,newgate
mov edi,ebx
movsd // 用新中断描述符在 IDT中
movsd // 替换原来的中断 3描述符
int 3h // 触发中断 3,使程序跳转到
// 0级执行中断处理程序
http://qsyang.yeah.net
现代微机原理与接口技术
38
lea esi,saveidt
mov edi,ebx
movsd
movsd // 恢复原来中断 3的门描述符
}
printf( "cr0=0x%x",_cr0); // 输出结果
return 0;
}
http://qsyang.yeah.net
现代微机原理与接口技术
39
10.3.3 虚拟设备驱动程序( VxD)基础
1,VxD的文件结构
VxD的五个段
VxD_CODE 保护模式下的代码段含设备驱动程序回调例程、服务程序,API接口函数和控制程序。
VxD_DATA 保护模式下的数据段包含设备描述块、服务表、全局变量等。
VxD_ICODE 保护模式下的初始化代码段初始化的时候用的服务程序和过程。初始化后被丢弃
VxD_IDATA 保护模式下的初始化数据段初始化时用的数据。初始化后被丢弃。
VxD_REAL_INIT 实模式下的初始化资料与代码该过程返回后被丢弃。
http://qsyang.yeah.net
现代微机原理与接口技术
40
typedef struct tagDDB {
DWORD DDB_Next; // VMM使用这一项来指出
// 下一个 DDB的地址
WORD DDB_SDK_Version; // 建立该 VxD所使用的
// SDK/DDK的版本号
WORD DDB_Req_Device_Number; // 设备 ID。
// UNDEFINED_DEVICE_ID表示
// 不使用唯一 ID
BYTE DDB_Dev_Major_Version; // VxD的主版本号
BYTE DDB_Dev_Minor_Version; // VxD的次版本号
WORD DDB_Flags; // DDB标志位
BYTE DDB_Name[8]; // VxD的名字,不足 8个字节必须
// 以空格补满
DWORD DDB_Init_Order; // 指定 VxD的初始化顺序,如果没
// 有特别的初始化要求就使用
// UNDEFINED_INIT_ORDER
DWORD DDB_Control_Proc; // 设备控制程序的地址
DWORD DDB_V86_API_Proc; // V86API程序的入口地址
2,VxD的设备描述符块 DDB
http://qsyang.yeah.net
现代微机原理与接口技术
41
DWORD DDB_PM_API_Proc; // 保护模式 API程序的入口地址
DWORD DDB_V86_API_CSIP // V86入口点的 CS,IP
DWORD DDB_PM_API_CSIP; // 保护模式入口点的 CS,IP
DWORD DDB_Reference_Data; // 实模式初始化代码设置的参
// 考资料
DWORD DDB_VxD_Service_Table_Ptr; // VxD服务表的地址
DWORD DDB_VxD_Service_Table_Size; // VxD服务表中提
// 供的 VxD服务的数目
} DDB;
http://qsyang.yeah.net
现代微机原理与接口技术
42
3,VxD的加载与卸载动态加载
API函数 发的消息 功能
CreateFile Sys_Dynamic_Device_Init 加载 VxD
DeviceIOControl W32_DeviceIOControl 与 VxD进行交互处理
CloseHandle Sys_Dynamic_Device_Exit 卸载 VxD
hDevice=CreateFile( "\\\\.\\myfirst.vxd",0,0,0,OPEN_EXISTING,
FILE_FLAG_DELETE_ON_CLOSE,0);
DeviceIoControl( hDevice,DIOC_MY_IO,NULL,0,NULL,0,
NULL,NULL);
CloseHandle( hDevice);
http://qsyang.yeah.net
现代微机原理与接口技术
43
静态加载
http://qsyang.yeah.net
现代微机原理与接口技术
44
10.4 Windows 2000/XP设备驱动程序设计
10.4.1 Windows 2000/XP的设备驱动程序虚拟设备驱动程序( VDD)
内核模式驱动程序文件系统驱动程序保留设备驱动程序
PnP
驱动程序显示驱动程序
WDM驱动程序类驱动程序 迷你驱动程序可以使 DOS应用程序访问 x86平台上的硬件,也可以支持
indows 9x下的对端口访问是一种遵循电源管理协议并能在 Windows 98和 Windows
2000间实现源代码级兼容的
PnP驱动程序用于显示和打印设备的内核模式驱动程序在本地硬盘或网络上实现标准 PC文件系统模型
(包括多层次目录结构和命名文件概念)
主要包括 Windows NT早期版本的驱动程序,它直接控制一个硬设备而不用其他驱动程序帮助,
可以不做修改地在 Windows
2000中运行
http://qsyang.yeah.net
现代微机原理与接口技术
45
10.4.2 WDM的基本结构
1,基本概念设备对象,系统为帮助软件管理硬件而创建的一个数据结构。一个物理设备可以有多个这样的数据结构。
物理设备对象,简称 PDO,处于设备对象栈最底层的设备对象。每个物理设备被创建一个 PDO
功能设备对象,简称 FDO,在 PDO之上,描述设备功能的相关数据结构。
过滤器设备对象,简称 FiDOs,在 FDO的上面或下面,
分别称为上层过滤器和下层过滤器。用于修改现有功能驱动程序的行为。
设备对象栈,设备对象栈代表处理请求的驱动程序层次。
http://qsyang.yeah.net
现代微机原理与接口技术
46
FiDO
FDO
FiDO
PDO
上层过滤器驱动程序功能驱动程序下层过滤器驱动程序总线驱动程序
IRP
I/O系统服务
Win32子系统应用程序
I/O管理器用户态核心态设备对象栈
46页
http://qsyang.yeah.net
现代微机原理与接口技术
47
WDM驱动程序模型中,每个硬件设备可以有多个驱动程序:
功能驱动程序,管理 FDO所代表的设备,负责其初始化、处理 I/O操作完成时产生的中断事件并为用户提供一种适当的设备控制方式。
过滤器驱动程序,用于监视和修改 IRP流。硬件或软件人员可利用过滤器驱动程序修改现有功能驱动程序的行为。
总线驱动程序,负责管理硬件和计算机之间的连接。这个驱动程序实际上和同类设备共同拥有。如 PCI总线驱动程序。
2,硬件设备的驱动程序种类
http://qsyang.yeah.net
现代微机原理与接口技术
48
总线驱动程序检测到新的硬件用户使用控制面板中的,添加新硬件,向导安装一个设备
PnP管理器为该设备和它的驱动程序在注册表的配置表中添加一些条目
PnP管理器可能需要调整已经分配给已存在设备的资源,使需要的资源对新设备可用
3,设备驱动程序安装的顺序硬件接入
PnP管理器创建 PDO
http://qsyang.yeah.net
现代微机原理与接口技术
49
驱动程序被装入后,执行 DriverEntry程序。
来设置驱动程序中各个例程的入口地址
PnP管理器参照注册表中的信息查找与创建的
PDO相关的过滤器和功能驱动程序
PnP管理器装入最底层的过滤器驱动程序并调用其 AddDevice函数。该函数创建一个 FiDO,
从而在过滤器驱动程序和 FiDO之间建立了水平连接按照 INF文件的指令安装驱动程序
http://qsyang.yeah.net
现代微机原理与接口技术
50
PnP管理器继续向上执行,依次装入并调用每个低层过滤器、功能驱动程序和每个高层过滤器
,直到完成整个设备对象栈
AddDevice把 PDO连接到 FiDO上
PnP管理器给设备发送各种 PnP IRP
PnP管理器给 发送,启动设备,PnP IRP告诉驱动程序已经给它分配了哪些资源,驱动程序使用这些资源分配启动它的设备驱动程序处于等待处理 IRP的状态
http://qsyang.yeah.net
现代微机原理与接口技术
51
当应用程序因要向驱动程序提出各类请求(如读
、写数据等)而调用相关函数的时候,就会使得 I/O
管理器创建一个 I/O请求包( IRP)。
通常一个 I/O请求包 (IRP)先被送到设备对象栈的最上层驱动程序然后逐渐过滤到下面的驱动程序。每一层驱动程序都可以决定如何处理 IRP,既可以直接处理完该 IRP就不再向下传,也可以处理完后继续传递,还可以只做向下传递的工作。
当下层将请求处理完,返回的信息又通过该包的结构逐层向上传递。
4,IRP传递的顺序
46页
http://qsyang.yeah.net
现代微机原理与接口技术
52
10.4.3 I/O请求包 (IRP)
I/O请求包( IRP)是驱动程序操作的中心,它是一个内核,对象,,是预先定义的数据结构,带有一组对它进行操作的 I/O管理器程序 。 I/O管理器接收到一个 I/O请求后,在把它传递到合适的驱动程序栈中的最高驱动程序之前,分配并初始化一个 IRP。
一个 IRP有一个固定的首部和一个可变数目的 I/O栈 。
http://qsyang.yeah.net
现代微机原理与接口技术
53
http://qsyang.yeah.net
现代微机原理与接口技术
54
创建异步 IRP的 IoBuildAsynchronousFsdRequest
创建同步 IRP的 IoBuildSynchronous- FsdRequest
创建同步 IRP_MJ_DEVICE_CONTROL或
IRP_MJ_INTERNAL_DEVICE_CONTROL请求的
IoBuildDeviceIoControlRequest
创建其他种类 IRP的 IoAllocateIrp
创建某些 IRP的子 IRP的 IoMakeAssociatedIrp。
创建 IRP的可以是 I/O管理器,也可以是其他的驱动程序。能创建 IRP的函数有:
http://qsyang.yeah.net
现代微机原理与接口技术
55
在创建一个 IRP时,同时还创建了一个与之关联的
IO_STACK_LOCATION结构数组,它是 I/O栈中的一项,它包含的成员包括,
MajorFunction(该 IRP的主功能码)
MinorFunction(该 IRP的副功能码)
Parameters( IRP参数)
DeviceObject(与该栈单元对应的设备对象地址)
FileObject(内核文件对象地址)
CompletionRoutine( I/O完成程序地址)
Context(任意的与上下文相关的值)。
http://qsyang.yeah.net
现代微机原理与接口技术
56
在栈 Parameters成员中,有几个常用的的参数,
Create( IRP_MJ_CREATE请求,创建 IRP)
Close( IRP_MJ_CLOSE请求,关闭 IRP)
Read( IRP_MJ_READ请求,读 IRP)
Write( IRP_MJ_WRITE请求,写 IRP)
StartDevice( IRP_MJ_PNP的
IRP_MN_START_DEVICE请求,启动设备)
DeviceIOControl( IRP_MJ_IOCTL请求,IOCTL
IRP)。
http://qsyang.yeah.net
现代微机原理与接口技术
57
大部分参数可以和 Win32函数对应起来参数 Win32 API
Creat CreateFile
Read ReadFile
Write WriteFile
DeviceIOControl DeviceIoControl
CloseHandle Close
返回
http://qsyang.yeah.net
现代微机原理与接口技术
58
创建完 IRP后,可以使用下面的代码做必要设置,并把
IRP发送到设备驱动程序 。
PDEVICE_OBJECT DeviceObject; //设备对象结构
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(
Irp) ; //获得该 IRP第一个堆栈单元的指针
stack->MajorFunction = IRP_MJ_Xxx;
//填充 MajorFunction代码
…… //可以对栈做其他初始化的工作
// 这里可能运行 StartIo
NTSTATUS status = IoCallDriver( DeviceObject,Irp) ;
//把 IRP发送到设备驱动程序返回
http://qsyang.yeah.net
现代微机原理与接口技术
59
下面是 IoCallDriver的执行过程:
NTSTATUS IoCallDriver( PDEVICE_OBJECT device,PIRP Irp

{
IoSetNextIrpStackLocation( Irp) ;
PIO_STACK_LOCATION stack =
IoGetCurrentIrpStackLocation ( Irp) ; //获得栈单元指针
stack->DeviceObject = device; //设置设备对象结构地址
ULONG fcn = stack->MajorFunction; //得到主功能号
PDRIVER_OBJECT driver = device->DriverObject;
//获得驱动程序对象的地址
return( *driver->MajorFunction[fcn]) ( device,Irp) ;
//利用主功能号调用相应的派遣函数
}
*driver-> MajorFunction[fcn]是函数指针,它所指向的派遣函数是在 DriverEntry例程中指定的。
返回 Driverentry 返回
http://qsyang.yeah.net
现代微机原理与接口技术
60
10.4.4 WDM驱动程序的结构
WDM驱动程序包含许多函数(例程),操作系统调用这些例程来执行对 IRP的各种操作。
基本驱动程序函数 I/O控制函数 派遣函数
DriverEntry
AddDevice
StartIO
AdapterControl
OnInterrupt
DpcForIsr
DispatchPnp
DispatchPower
DispatchWmi
DispatchRead
DispatchWrite
StartIO处理请求队列,AdapterControl处理 DMA操作
OnInterrupt处理中断。
http://qsyang.yeah.net
现代微机原理与接口技术
61
在每个 WDM驱动程序中,下列函数必须有:
DriverEntry函数:这个例程是每一个设备驱动程序的入口。在这个例程中完成某些全局初始化工作,还要设置响应各种用户请求的分发例程与 I/O控制例程的入口。
AddDevice函数,对于功能驱动程序,其 AddDevice函数的基本职责是创建一个设备对象并把它连接到以
PDO为底的设备堆栈中。
DispatchPnp函数:用于处理 IRP_MJ_PNP消息,以便能实现即插即用的功能。
DispatchPower函数:用于实现对电源管理的支持。
DispatchWmi函数,WMI是微软实现的基于 Web的企业管理工业标准,该函数用于处理有关的消息。
http://qsyang.yeah.net
现代微机原理与接口技术
62
下面是一段 DriverEntry程序的片段,
extern "C"
NTSTATUS
DriverEntry ( IN PDRIVER_OBJECT DriverObject,IN
PUNICODE_STRING RegistryPath)
{
// 初始化函数的入口地址
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->DriverStartIo = StartIo;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER]=
DispatchPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
= DispatchWmi;
…… // 这里可以加入其他 MajorFunction处理函数的入口地址返回
http://qsyang.yeah.net
现代微机原理与接口技术
63
// 如果驱动程序需要访问设备的服务键,则备份 RegistryPath
servkey.Buffer =( PWSTR) ExAllocatePool( PagedPool,
RegistryPath->Length+ sizeof( WCHAR));
if( !servkey.Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
servkey.MaximumLength = RegistryPath->Length + sizeof(
WCHAR);
RtlCopyUnicodeString( &servkey,RegistryPath);
return STATUS_SUCCESS;
}
http://qsyang.yeah.net
现代微机原理与接口技术
64
添加一个设备
NTSTATUS AddDevice ( PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT pdo)
{
NTSTATUS status;
PDEVICE_OBJECT fdo;
Status=IoCreateDevice( DriveObject,
sizeof( WDM_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&fdo) ; //在 fdo中产生我们的功能设备对象
if( NT_ERROR( status))
Return status;
……
}
http://qsyang.yeah.net
现代微机原理与接口技术
65
下面是 IRP派遣函数的一个框架:
NTSTATUS DispatchXxx( PDEVICE_OBJECT device,PIRP Irp)
{
PIO_STACK_LOCATION stack =
IoGetCurrentIrpStackLocation( Irp) ; //获得栈单元指针
PDEVICE_EXTENSION pdx = ( PDEVICE_EXTENSION )
device->DeviceExtension; //获得设备扩展
…… //其他 IRP处理操作
return STATUS_Xxx; //返回状态码
}
返回
http://qsyang.yeah.net
现代微机原理与接口技术
66
对 WDM请求包运行机制的总结
1,应用程序通过 CreateFile等 Win32函数来进行有关的请求。
2,I/O管理器创建 IRP。
3,设置 IRP中的主功能代码和对 IRP栈做各种初始化工作。 如果需要对 IRP排队,则调用 StartIo处理
IRP队列
4,将 IRP发送到派遣程序 (按照 DriverEntry中指定的入口地址来调用相关的派遣程序)。
5,执行有关的派遣程序,实际处理对 IPR的操作 。
http://qsyang.yeah.net
现代微机原理与接口技术
67
10.4.5 即插即用支持即插即用主要是指实现一个 AddDevice程序和一个 IRP_MJ_PNP处理程序。这个 PnP IRP有 8个次功能代码(它们的主功能代码都是 IRP_MJ_PNP)。
· IRP_MN_START_DEVICE 分配资源并启动设备
· IRP_MN_QUERY_REMOVE_DEVICE 询问一个设备是否可以删除
· IRP_MN_REMOVE_DEVICE 设备被拔出,删除设备
· IRP_MN_CANCEL_REMOVE_DEVICE 取消查询删除请求
· IRP_MN_STOP_DEVICE 停止设备进行资源重新分配
· IRP_MN_QUERY_STOP_DEVICE 询问设备是否可以停止
· IRP_MN_CANCEL_STOP_DEVICE 取消查询停止请求
· IRP_MN_SURPRISE_REMOVAL 用户在意外下拔出设备
http://qsyang.yeah.net
现代微机原理与接口技术
68
NTSTATUS DispatchPnp( PDEVICE_OBJECT fdo,PIRP Irp)
{
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(
Irp) ;
ULONG fcn = stack->MinorFunction; // 取副功能码
static NTSTATUS status=STATUS_SUCCESS
switch( fcn) // 按照副功能码调用相关的处理函数
{
case IRP_MN_START_DEVICE,HandleStartDevice( fdo,Irp) ;
break;
case IRP_MN_QUERY_REMOVE_DEVICE,HandleQueryRemove( fdo,
Irp) ;
……
};
if( fcn >= arraysize( fcntab))
return DefaultPnpHandler( fdo,Irp) ;
return status;
}
http://qsyang.yeah.net
现代微机原理与接口技术
69
10.4.6 数据的读 /写
WDM有 4个标准的资源类型,分别是:
CmResourceTypePort(端口资源)
CmResourceTypeMemory(内存资源)
CmResourceTypeInterrupt(中断资源)
CmResourceTypeDma( DMA资源)
http://qsyang.yeah.net
现代微机原理与接口技术
70
1,内存与端口访问尽管 PC机的 I/O端口是单独编址的,但为了做到和统一编址的机器兼容性,Windows 2000的设计者使用了硬件抽象层( HAL)的概念。无论是单独编址还是统一编址,只需要使用下表 8中所给的函数就可以访问端口和内存了。
http://qsyang.yeah.net
现代微机原理与接口技术
71
数据宽度 端口访问函数 内存访问函数
8位 READ_PORT_UCHARWRITE_PORT_UCHAR READ_REGISTER_UCHARWRITE_ REGISTER _UCHAR
16位 READ_PORT_USHORTWRITE_PORT_USHORT READ_ REGISTER _USHORTWRITE_ REGISTER _USHORT
32位 READ_PORT_ULONGWRITE_PORT_ULONG READ_ REGISTER _ULONGWRITE_ REGISTER _ULONG
8 位字符串
READ_PORT_BUFFER_UCHAR
WRITE_PORT_BUFFER_UCHAR
READ_ REGISTER _BUFFER_UCHAR
WRITE_ REGISTER _BUFFER_UCHAR
16位字符串
READ_PORT_BUFFER_USHORT
WRITE_PORT_BUFFER_USHORT
READ_ REGISTER _BUFFER_USHORT
WRITE_ REGISTER _BUFFER_USHORT
32位字符串
READ_PORT_BUFFER_ULONG
WRITE_PORT_BUFFER_ULONG
READ_ REGISTER _BUFFER_ULONG
WRITE_ REGISTER _BUFFER_ULONG
http://qsyang.yeah.net
现代微机原理与接口技术
72
2,响应中断响应中断首先要配置中断,也就是截获中断,然后就需要编写中断处理程序 。
配置中断资源是在 StartDevice函数中实现的,使用从
CmResourceTypeInterrupt描述符中得到的参数来调用
IoConnectInterrupt函数。和实模式下一样,在调用
IoConnectInterrupt进行中断配置前应该禁止 PC机的中断
,调用之后再允许设备中断。
http://qsyang.yeah.net
现代微机原理与接口技术
73
10.4.7 WDM驱动程序的安装文件驱动程序根据 INF文件中的指令安装。 INF文件含有安装一个 WDM设备驱动程序需要的所有必需的信息,包括要复制的文件列表和要创建的注册表项等。
驱动程序可执行文件被复制到正确的位置,通常是
Winnt\System32\Drivers目录,然后创建各种注册表项

INF文件是一个文本文件,它由节组成,每一节从括在方括号中的节名称开始,后面是节的内容,大部分段都含有一系列,keyword = value”形式的项。
http://qsyang.yeah.net
现代微机原理与接口技术
74
节 项 值 描 述
[Version]
Signature
Provider
Class
ClassGuid
DriverVer
$Windows NT$,$Windows 95$ 或
$Chicago$
INF文件创建者系统定义的类名字,或用户指定的新的类名字匹配的类 GUID
驱动程序的版本号
[Strings] %String%=”Value” 指定一个字符串
[Manufactu
rer]
%manufacturer%=mode
ls 指定厂商名和对应的 models节的名称
[models] 指定产品名称,对应的 install节的名称和硬件 ID,0个或多个兼容 ID
http://qsyang.yeah.net
现代微机原理与接口技术
75
节 项 值 描 述
[install]
Copyfiles=@filename
| filelist
Addreg=addreg
ProfileItems
指定要复制的文件,或列出 filelist节的名称指定 addreg节的名称列出指定要添加到,开始,菜单中的项
[Destinati
onDirs]
DefaultDestDir=diri
d,[subdir]
filelist=
dirid,[subdir]
对默认文件复制和 filelist节中的文件复制,指定目录 ID和可选的子目录 。 dirid
是一个目录代码,指示存放文件的标准位置 。 Windows 2000DDK定义了这些代码,
如代码 10表示 Windows目录
[filelist] 要安装的文件列表
[addreg] 添加新的键和值