740 likes | 900 Views
PC 机的高级编程技术. 应用程序. 驱动程序 操作系统. 实 模 式. BIOS. 直接访问. 裸机. 第一节 软件对接口的访问方式. 返回 3 页. 返回 4 页. 返回 5 页. 返回 6 页. 一、 直接访问层次. 特点: 可以直接进行内存和端口的访问,也可以自行决定是否在实模式和保护模式间切换。 通常所有端口和内存都是对程序员开放的。 工具: 汇编语言或 C 语言。. 应用: BIOS 都是基于这种低级层次编写的;驱动程序也有使用这种方法的;实模式下应用程序也可以使用这种方法。. 优点: 编写的代码执行速度最快,占用空间最小。
E N D
应用程序 驱动程序 操作系统 实 模 式 BIOS 直接访问 裸机 第一节 软件对接口的访问方式 返回3页 返回4页 返回5页 返回6页
一、直接访问层次 特点:可以直接进行内存和端口的访问,也可以自行决定是否在实模式和保护模式间切换。 通常所有端口和内存都是对程序员开放的。 工具:汇编语言或C语言。 应用:BIOS都是基于这种低级层次编写的;驱动程序也有使用这种方法的;实模式下应用程序也可以使用这种方法。 优点:编写的代码执行速度最快,占用空间最小。 缺点:需要对硬件和接口有很熟悉的了解; 熟悉汇编,或熟练使用C语言的指针; 不利于增加对新设备的控制。 转2页
二、BIOS访问层次 特点:通过BIOS提供的功能调用间接地对内存或端口访问,从而控制硬件。 工具:汇编语言或C语言。 应用:驱动程序有些会使用这些功能调用; 需要获得高效率的应用程序也采用此方法。 优点:编写的代码执行速度较快; 编写的代码不需要直接对硬件进行控制。 缺点:需要对底层信号有所了解; 增加对新设备的控制不很方便,但好于低级层次。 转2页
三、驱动程序层次 特点:使用BIOS功能调用、操作系统功能调用和直接访问的方法编写符合特定操作系统管理规范的设备驱动程序。 工具:VC++与DDK开发包,或第三方开发工具如DriverStudio。 应用:在操作系统层面上的设备控制,并为应用程序提供API支持。 优点:既能够控制硬件,又保证操作系统的完整与安全。 缺点:需要对底层信号有所了解; 需要对操作系统各管理模块有深入的了解。 转2页
四、应用程序层次 特点:使用操作系统和各种驱动程序所提供的功能调用或API函数间接对硬件或内存进行访问。 工具:VC++、Delphi、Java等。 应用:编写面向终端用户的各类应用程序。 优点:无需对硬件控制有太多了解,只需完成应用层面的工作就可以,而且还保证操作系统的完整与安全。 缺点:需要了解大量的API和功能调用函数的功能; 由于是间接调用,所以代码的效率和编译系统有很大的关系。 转2页
(左移四位) 16位段地址 软件地址: 16位段地址 : 16位段内偏移 物理地址: 16位段内偏移 + = 20位物理地址 第二节 Pentium 4的内存管理 一、实模式的存储管理(同PC/XT) 采用内存分段的办法,内存分为若干段,段的大小根据需要决定,最大为64KB。 思考:软件地址到物理地址变换的二义性及应用? 段地址大小设置与地址变换的关联?
000000 存放用户程序和DOS驻留部分 640KB常规内存 0A0000 存放显存、网卡和部分用户的DOS驱动程序和BIOS 384KB高端内存块 UMB 100000 存放部分DOS驻留程序 64KB高端内存区 HMA 110000 大于1M以上的 扩展内存,DOS下不能直接访问,需要用XMS规范使用。可利用DOS调用或BIOS调用来使用。 1~4095MB扩展内存块 EMB ≈ ≈ FFFFFF 内存区分配:
二、保护模式下的系统地址寄存器 1、系统地址寄存器汇总表 说明:① GDTR、IDTR 在进入保护模式前设置,TR、LDTR在任 务切换时设置。 ② GDT、IDT整个系统各一个,TSS、LDT每个任务一个。 ③选择符与描述符含义不同。
选择符 描述符长均为8Byte 门描述符 TR(16bit) 段描述符 …… TSS描述符 选择符 …… 2 门描述符 LDTR(16bit) 1 0 2 LDT描述符 界限 界限 IDT 基址 1 基址 0 GDTR(48bit) IDTR(48bit) GDT 段寄存器选择符 选择符 …… …… TSS描述符 LDT描述符 选择符 段描述符 2 选择符 界限 1 TSS结构 界限 基址 0 基址 线性地址 LDT 2、系统地址寄存器与系统表关系 返回下页 返回12页 返回13页
说明1: GDT表项类型—LDT描述符、TSS描述符、段描述符; IDT表项类型—中断门描述符、陷阱门描述符、任务门描 述符、调用门描述符; LDT表项类型—段描述符。 说明2: 不同类型描述符通过第5字节的D3~D0区分。 转19页 说明3: 表或结构长度=(界限)+1。 转上页 例:GDTR的内容为00F0000000FFH,求GDT的首地址和末地址及该表含有多少个描述符? 解:GDT首址=00F00000H; GDT末址=00F00000H+0FFH=00F000FFH; GDT描述符个数=GDT长度/8=(0FFH+1)/8=32。
TSS结构 I/O允许位映象(最大8K) 中断重定向位映象(32字节) 操作系统可利用(长度可变) I/O允许位映象域基址 0 T 0 任务LDT选择符 0 GS、FS选择符 0 DS、SS选择符 0 CS、ES选择符 EDI、ESI、EBP、EBX、EDX、ECX、EAX EFLAG、EIP CR3 0 SS2(特权级2) ESP2 0 SS1(特权级1) ESP1 0 SS0(特权级0) ESP0 0 反向链 TSS段限 虚拟8086模式且CR4中VME=1时有效 68H 64H 当前任务LDTR 60H 选择符 58H 当前任务的段选择符 50H 48H 28H 20H 当前任务的优先级可改变,堆栈的优先级也要相应改变。 系统为任务的0~2级堆栈指针用SSi和ESPi表示。 1cH 18H 14H 10H 0cH 08H 上一任务TR 04H 选择符 00H 3、TSS与LDT关系 转10页
IDT GDT/LDT IDTR 代码段 基地址 偏移 选择符 基地址 门描述符 段描述符 属性 属性 EIP 中断服务子程序 偏移 边界 线性地址 段选择符 或TSS选择符 4、门描述符与段选择符关系 说明:利用段选择符的bit2确定查询GDT或LDT。 段选择符指向一个段描述符。 对任务门而言,选择符为TSS选择符。 转10页 任务的切换:通过直接改变TR方式, 或通过任务门间接方式实现。
45 32 31 0 逻辑地址 段寄存器的15~2位 偏移量 段基址 段描述符 段表 物理地址 32位线性地址 三、保护模式下Pentium 4的段式存储管理 1、段式管理的地址变换 Pentium 系列的虚拟地址空间是246=64TB。 注意:保护模式下段寄存器的含义已变为段选择符, 通常称段寄存器为段选择符。
15 2 1 0 段选择符 RPL TI 索引 TI=0 TI=1 段描述符 段描述符 …… …… 2 2 段描述符 段描述符 1 1 0 0 LDT GDT 2、段描述符表与段选择符
D7 D0 段界限 7~0 0 段界限 15~8 1 基址 7~0 2 基址 15~8 3 基址 23~16 4 P DPL S TYPE 5 G D/B 段界限 19~16 0 AVL 6 7 基址 31~24 3、段描述符 返回20页
D7 D0 G D/B 段界限 19~16 0 AVL 用户/操作系统可用位 D/B位 粒度位 D=1 使用32位操作系统和32位寻址方式 代码段(D位) D=0 使用16位操作系统和16位寻址方式 D/B位 B=1 堆栈使用ESP寄存器,上限为FFFFFFFFH 数据段(B位) B=0 堆栈使用SP寄存器,上限为FFFFH 段描述符中的第6字节: 思考:如何知道该段为代码段或数据段?
数据段标志 可写位 扩展方向位 D7 D0 兼容位 访问位 存在位 特权位 代码段标志 可读位 S=1是非系统段 S=0是系统描述符 E=0 ED W DPL S=1 P A E=1 C R 段描述符中非系统段的第5字节:
D7 D0 P DPL S TYPE 返回11页 段描述符中系统段的第5字节:
#include "stdafx.h" #include <stdio.h> #include <wtypes.h>// wtypes.h定义了DWORDLONG,DWORD,WORD等数据类型 DWORDLONG gdtr,savegdt; //下面是GDT中将创建的数据段描述符表,基地址0X00000F00,段界限为0XFFFF,优先级为 //3的在内存中的可写数据段,同P16段描述符 WORD descriptor[4]={0xFFFF,0X0F00,0XF200,0X0040}; int result[10]; int main(int argc, char* argv[]) {_asm {pushebp sgdtgdtr// 将GDTR寄存器的内容读取到gdtr开始的6个字节中,其中 // 前两个字节给出GDT的界限值,高4个字节给出GDT的基地址 movebp,dword ptr [gdtr+2] // 将gdt的基地址读到EBP中 addebp,70h // 我们选择70H偏移下的段描述符(GDT中第14个描述符) leaedi,savegdt movesi,ebp movsdmovsd // 以上4条指令保存原来在70H偏移上的描述符 movedi,ebp lea esi,descriptor; movsd movsd// 把我们的数据段描述符装入70H偏移上 pushes movax,0073h// 选择字为描述符偏移70H拼接上低3位控制位元, // 其中Ti为0,表示访问GDT,RPL为11,说明3级优先级,所以就为73H 转16页
moves,ax// ES装入选择字73H leaedi,result// 将存放输出结果的变量的地址放在EDI中 moveax,1 movebx,1 } _asm {movcx,10 a1:moves:[eax],eax addeax,4 loopa1// 上面4条指令将向物理地址0X00000F00处写10个双字 } _asm {movcx,10 a2:moveax,es:[ebx] mov[edi],eax addebx,4 addedi,4 loopa2// 以上从物理地址0X00000F00处依次读出10个数据存放在 // result数组中 } _asm {popes popebp }
printf("result="); for(int i=0;i<10;i++) printf("%d,",result[i]);// 输出结果 return 0; }
主存 程序1 页面 程序2 页框 程序3 ~ ~ ~ ~ 四、保护模式下Pentium 4的虚拟页式存储管理
31 7 6 5 4 3 2 1 0 8 TSD DE PVI CR4 MCE 保留,缺省为全0 PAE PSE PGE VME PCE 1、页面大小选择
31 22 21 12 11 0 页目录项号 偏移 32位线性地址 页面号 CR3 32位物理地址 31 12 11 9 8 7 6 5 4 3 2 1 0 页表 页目录 页目录项 0 A PCD US P D PWT RW 页表基地址31~12 AVL 31 12 11 9 8 7 6 5 4 3 2 1 0 页表项 A PCD US P D PWT RW AVL 页框基地址31~12 2、32位4KB分页方式地址变换 P=出现位,US=用户/监督位,PCD是页Cache禁止,D=Cache“脏”位,RW=读/写位,PWT=页写贯穿位,A=访问位,AVL=用户的操作系统可用位。而第7位(PS)在4KB分页中为0
31 22 21 0 偏移 页目录项号 32位线性地址 CR3 32位物理地址 页目录 31 22 8 7 6 5 4 3 2 1 0 A PCD US P 1 D PWT RW 页框基地址31~22 页目录项 3、 32位4MB分页方式地址变换
31 5 4 3 2 1 0 PCD PWT 32字节对齐的PDPT基地址 CR3寄存器 31 36 35 12 11 6 5 4 3 2 1 0 PCD P AVL PWT 4KB对齐的页目录基地址(高24位) PDPT项 31 30 29 21 20 12 11 0 PDPT项号 页目录项号 偏移 页面号 32位线性地址 CR3 36位物理地址 页目录指针表 页表 页目录 4×64位 512×64位 512×64位 63 36 35 12 11 9 8 7 6 5 4 3 2 1 0 0 A PCD US P PWT RW AVL 页目录项 4KB对齐的页表基地址 63 36 35 12 11 9 8 7 6 5 4 3 2 1 0 G 0 A PCD US P D PWT RW AVL 页表项 4KB对齐的页框基地址 4、36位4KB分页方式地址变换
31 30 29 21 20 0 PDPT项号 页目录项号 偏移 32位线性地址 低21位 CR3 36位物理地址 高15位 页目录指针表 页目录 4×64位 512×64位 63 36 35 21 20 12 11 9 8 7 6 5 4 3 2 1 0 页目录项 G 1 A PCD US P D PWT RW AVL 2MB对齐的页框基地址 5、36位2MB分页方式地址变换
特权级3 特权级0 应用软件 操作系统提供的接口 操作系统内核与VxD 计算机底层硬件 第三节 Windows 9x驱动程序设计 一、虚拟机与VxD的引入
Windows 9x虚拟机环境 SYSVM DOSVM DOSVM Win16程序 Win32程序 Win32程序 DOS程序 DOS程序 …… …… Win16程序 Win16程序 Win32地址空间 Win32地址空间 Win16程序 Win16地址空间 Windows 9x运行环境:
执行in, out指令 是 CPL<IOPL? 否 是 IOPM相关位=0? 否 产生一个一般保护异常 进行I/O操作 二、虚拟机下I/O端口访问 1、保护模式下I/O访问 IOPL用以表示指定的I/O操作处于特权级的哪一级。它在EFLAGS中。 CPL当前段的I/O优先级,它实际上是CS段选择符的第0~第1位。 IOPM是对所有VM都起作用的权限机制,它以位(bit)来代表每个端口。某位为1,则该代表的端口被禁止访问;某位为0,则允许访问该位所代表的端口。 约定:IOPL为0。
执行in, out指令 是 IOPM相关位=0? 否 产生一个一般保护异常 进行I/O操作 2、V86模式下I/O访问 约定:忽略CPL<IOPL的判断。 访问:符合保护模式下的I/O访问规则。 如何捕获一个端口的访问?配置IOPM相关位
外部中断和处理器异常 软中断 否 CPL≤门描述符的DPL ? 是 访问各类门描述符 否 转移后代码段的DPL≤CPL ? 是 禁止访问 执行0特权级别中的中断处理程序 三、虚拟机下中断或异常的处理 约定:外部中断和异常处理的DPL为0; 软中断的DPL不变,为设定值。
硬件中断 VPICD Win32 程序 IRET VxD中 的回调函数 INT x CALL IRET RET 异常处理程序 虚拟机 特权切换:中断处理程序特权级为0; 转移后DPL≤CPL时,运行中断处理程序。 思考:如何使自己从用户级转到核心级? 利用保护模式下中断的处理流程。
例: 在IDT中构造一个中断门描述符,使它的DPL=3,这样它就可以被用户级的程序访问(DPL≤CPL),将该中断门描述符的段选择字设为028H,显然该选择字对应的代码段在GDT中,由于OS代码段基地址为00000000H,段界限为FFFFFFFFH,所以现在中断门的偏移量就实际给出了中断处理程序入口的线性地址,我们只要把一个过程作为中断处理程序,这个过程就处在核心级里了。 程序如下:
#include "stdafx.h" #include <stdio.h> #include <wtypes.h>// wtypes.h定义了DWORDLONG,DWORD,WORD等数据类型 DWORD_cr0;// 用来保存CR0寄存器的值 void _declspec(naked)newint3(void)// 运行在核心级的中断3处理程序 { _asm {moveax,cr0// 这是必须在核心级才能执行的特权指令 mov_cr0,eax } _asmiretd// 中断返回 } int main(int argc, char* argv[]) {DWORDLONG idtr,saveidt; WORDnewgate[4]={0x0000,0x0028,0xee00,0x0000};// 中断门描述符 _asm {sidtidtr// 将IDTR的值存在idtr变量开始的6个字节中 movebx,DWORD ptr[idtr+2]// 把IDT的基地址读入EBX寄存器 addebx,24// 选择中断3作为进入核心级的入口,中断3的门描述符 // 的地址是IDT基地址加上3*8(每个门描述符8个字节) movesi,ebx leaedi,saveidt movsd movsd // 保存原来中断3的门描述符到saveidt中 leaeax,newint3 转下页
中断门描述符: 31 16 15 14 13 12 8 7 6 5 4 0 偏移量31~16 P DPL 01110 000 保留 偏移量15~00 段选择符(28H—C,30H--D) movnewgate,ax shreax,16 mov[newgate+6],ax//向新的中断描述符中填入中断处理程序的偏移量 leaesi,newgate movedi,ebx movsd movsd// 用新中断描述符在IDT中替换原来的中断3描述符 int3h// 触发中断3,使程序跳转到0级执行中断处理程序 leaesi,saveidt movedi,ebx movsd movsd// 恢复原来中断3的门描述符 } printf("cr0=0x%x",_cr0);// 输出结果 return 0; } 返回上页
四、虚拟设备驱动程序(VxD)基础 1、VxD的程序文件结构 VxD包含五个段: VxD_CODE(保护模式下的代码段):含设备驱动程序回调例程、服务程序、API接口函数和控制程序。 VxD_DATA(保护模式下的数据段):包含设备描述块、服务表、全局变量等。 VxD_ICODE(保护模式下的初始化代码段):初始化时用的服务程序和过程,初始化后被丢弃。 VxD_IDATA(保护模式下的初始化数据段):初始化时用的数据,初始化后被丢弃。 VxD_REAL_INIT(实模式下的初始化资料与代码):初始化时调用,该过程返回后被丢弃。 每个VxD装入主存后产生一个对象,每种型号的设备共用一个VxD对象。
2、VxD的设备描述符块DDB typedef struct tagDDB { DWORDDDB_Next;// VMM使用这一项来指出下一个DDB的地址 WORDDDB_SDK_Version; // 建立该VxD所使用的SDK/DDK的版本号 WORD DDB_Req_Device_Number;// 设备ID。UNDEFINED_DEVICE_ID // 表示不使用唯一ID BYTEDDB_Dev_Major_Version;//VxD的主版本号 BYTEDDB_Dev_Minor_Version;//VxD的次版本号 WORDDDB_Flags;// DDB标志位 BYTEDDB_Name[8];//VxD的名字,不足8个字节必须以空格补满 DWORDDDB_ Init_Order;// 指定VxD的初始化顺序,如果没有特别的初 // 始化要求就使用 UNDEFINED_INIT_ORDER DWORDDDB_Control_Proc;//设备控制程序的地址 DWORDDDB_V86_API_Proc;// V86API程序的入口地址 DWORDDDB_PM_API_Proc;// 保护模式API程序的入口地址 DWORDDDB_V86_API_CSIP// V86入口点的CS:IP DWORDDDB_PM_API_CSIP;// 保护模式入口点的CS:IP DWORDDDB_Reference_Data;// 实模式初始化代码设置的参考资料 DWORDDDB_VxD_Service_Table_Ptr; // VxD服务表的地址 DWORDDDB_VxD_Service_Table_Size;// VxD服务表中提供的VxD服务的 // 数目 } DDB; 每个设备(含同型号设备)均有一个DDB。
3、VxD的加载与卸载 加载:使设备与Win32 API挂钩。 动态加载: 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);
Win32 应用程序 调用指令 回调函数 1.Shell_PostMessage()给应用程序消息 2.VWIN32_QueueUserApc()给应用线程事件 3.发通过转换后的Ring0级事件给应用程序 DeviceIoControl() VxD 4、VMM与VxD间的消息 5、Win32与VxD间的通信
虚拟设备 驱动程序(VDD) 内核模式 驱动程序 PnP 驱动程序 文件系统 驱动程序 保留设备 驱动程序 显示 驱动程序 WDM驱动程序 类驱动程序 迷你驱动程序 第四节 Windows 2000/XP设备驱动程序设计 一、Windows 2000/XP的设备驱动程序
虚拟设备驱动程序(Virtual Device Driver,VDD)可使DOS应用程序访问x86平台上的硬件,也可支持Windows 9x下的对端口访问。 WDM驱动程序是一种遵循电源管理协议并能在Win98和Win2000上实现源代码级兼容的PnP驱动程序。WDM驱动程序又可分为类驱动程序(管理已定义类的设备)和迷你驱动程序(提供厂商专有的支持)。 显示驱动程序是用于显示和打印设备的内核模式驱动程序。 文件系统驱动程序在本地磁盘或网络上实现标准PC文件系统模型(含多层次目录结构和命名文件概念)。 保留设备驱动程序主要包括Windows NT早期版本的驱动程序,它直接控制一个硬设备而不用其他驱动程序帮助,可以不做修改地在Windows 2000中运行。
二、WDM的基本结构 1、设备对象及设备对象栈 设备对象:系统为帮助软件管理硬件而创建的一个数据结构(包括PDO、FDO、FiDO)。 硬件仅指某功能设备,多功能设备有几个设备对象。 PDO(物理设备对象):设备对象中的物理型对象。 FDO(功能设备对象):设备对象中的功能型对象。 FiDO(过滤器设备对象):在I/O管理器、FDO和PDO间的监视、修改IRP流的过滤型对象,分上层过滤和下层过滤对象。 设备对象栈:描述对设备对象内部处理请求的驱动层次的栈型结构,是设备对象的内部属性。 转下页
应用程序 Win32子系统 用户态 核心态 I/O系统服务 I/O 管理器 设备对象 IRP 上层过滤器驱动程序 FiDO 设 备 对 象 栈 功能驱动程序 FDO 下层过滤器驱动程序 FiDO 总线驱动程序 PDO 返回上页 返回下页 返回49页 返回50页
2、设备驱动程序 WDM模型中,设备驱动程序有下列几种类型: 功能驱动程序 :管理FDO所代表的设备,负责其初始化、处理I/O操作、I/O操作完成时产生中断事件,为用户提供一种适当的设备控制方式。 总线驱动程序:负责管理PDO硬件和计算机之间的连接。 过滤器驱动程序:管理FiDO所代表的设备,用于监视和修改IRP流,硬件或软件人员可利用过滤器驱动程序修改上级驱动程序的传递过来的操作。 每种硬件设备的驱动程序由上述两到三种驱动程序组成(可以无过滤器驱动程序)。 相同类型的总线共用一种总线驱动程序(如PCI总线驱动程序)。 转上页
3、设备对象与设备驱动程序 a.功能设备与设备对象 每个功能设备对应一个设备对象(设备对象栈为设备对象内部属性),相同型号的多个功能设备对应多个设备对象。 每个设备对象具有不同的私有属性值(如设备ID)。 b.设备驱动程序与设备驱动程序对象 设备驱动程序加载时建立一个设备驱动程序对象。 c.设备对象与驱动程序 相同类型的多个设备对象共用一个过滤驱动程序和功能驱动程序,即指向同一个驱动程序对象。 转47页
4、应用程序对设备对象的操作过程 操作接口:设备驱动程序的Win32 API函数,或重载的设备驱动程序的Win32 API回调函数。 操作参数:设备句柄、操作类型及其它信息。 例:DeviceIoControl(hDevice, DIOC_MY_IO, NULL, 0, NULL, 0, NULL,NULL); Win32子系统处理:将I/O操作转换后交I/O管理器处理, I/O管理器创建一个I/O请求包(IRP)后,送到设备对象栈的最上层设备对象对应的驱动程序。 驱动程序处理:每层驱动程序都可决定如何处理IRP,既可直接处理完该IRP就不再向下传,也可处理完后继续向下传递,还可只做向下传递工作。下层处理完的返回信息又通过该包的结构逐层向上传递。 转47页