第10章 IA-32微机的系统编程技术
10.1 处理器管理与初始化 10.1.1 IA-32处理器初始化
硬件复位将使处理器进入到实地址模式,并初始化每一个寄存器。 硬件复位后,单处理器系统中的处理器和多处理器系统中被选作自引导处理器(bootstrap processor, BSP)的那个处理器会立即执行从FFFF0H地址开始的软件初始化代码。 初始化期间多处理器系统中的其他处理器处于等待启动状态,直到软件初始化代码执行完后,BSP会唤醒这些处理器,让其执行自配置代码。 全部处理器初始化、配置和同步完成后,单处理器系统中的处理器和多处理器系统中的BSP开始执行操作系统的初始化部分或者执行起始任务(没有操作系统的时候)。
10.1.2 实地址模式下的软件初始化 IA-32微机在加电和复位后,就进入实地址模式,配置必要的数据结构来执行基本的系统功能,比如配置中断向量表来处理中断和异常。 开始执行位于物理地址FFFF0H处的初始化程序。 如果依然需要运行在实地址模式下,则加载附加的操作系统模块和数据结构 如果需要转到保护模式下运行(如Windows系统那样),则加载运行保护模式所必须的数据结构,并转换到保护模式。
加载包含了处理器进入保护模式后需要执行的代码的代码段 10.1.3 保护模式下的软件初始化 实地址模式初始化 加载 IDT, GDT, TSS, LDT(可选) 否 使用页? 是 至少要加载一个页目录和一张页表 加载包含了处理器进入保护模式后需要执行的代码的代码段 A
加载包含必要的中断和异常处理程序的一个或多个代码模块 A 加载包含必要的中断和异常处理程序的一个或多个代码模块 初始化GDTR, 控制寄存器CR1~CR4, MTRRs 初始化IDTR 处理器就通过设置CR0.PE值来进入保护模式 初始化IDTR IDTR可以在切换到保护模式之前初始化,也可以在刚刚进入保护模式还没有使能中断的时候初始化。
10.1.4 IA-32e模式的初始化 如果需要初始化IA-32e模式,操作系统必须先进入到保护模式,并使能分页机制。同时,IA-32e模式还要求CR4的PAE位为1。 IA-32e模式被激活后,系统地址寄存器(GDTR, LDTR, IDTR, TR)继续指向传统保护模式下的描述符表,这些表都在线性地址空间中的4GBytes以下的区域。进入IA-32e模式后,64位操作系统可以使用LGDT, LLDT, LIDT和LTR指令为系统地址寄存器加载64位描述符表的地址。
10.1.5 模式转换
1.实地址模式转换到保护模式 使用CLI指令屏蔽硬件中断,软件要保证在模式转换期间没有中断和异常产生。NMI也要用附加的硬件电路进行屏蔽。 用LGDT指令将GDT的基地址装载到GDTR中。 执行MOV CR0, reg指令来设置CR0中的PE位(如果允许页式管理还要设置PG位)。 MOV CR0, reg指令后立即执行一句far JMP或者far CALL(通常目的地址就是本指令的下一条指令地址)。此步骤后,系统进入保护模式。 如果要使用局部描述符表,则执行LLDT指令将LDT的段选择符加载到LDTR中。
执行LTR指令加载指向初始的保护模式任务的段选择符到任务寄存器,也可能加载的是指向一段用于存储TSS信息的存储区域的段选择符。 进入保护模式后,段寄存器会继续保留它们在实地址模式下的内容,第4步的远跳会复位CS寄存器,而其它的段寄存器需要进行必要的设置。可以通过重装的方法为其它段寄存器赋值,如果不用ES, FS和GS,需要用null选择符来填充。也可以通过执行一个到新任务的JMP或CALL指令复位段寄存器的值并转移到一个新的代码段。 执行LIDT指令将保护模式IDT的地址和界限装载进IDTR。 执行STI指令来取消对硬件中断的屏蔽。执行必要的硬件操作使能NMI中断。
2. 从保护模式返回到实地址模式 用CLI指令屏蔽硬件中断,NMI用外部硬件电路进行屏蔽 如果保护模式下采用了页式存储管理,则需要将程序控制传送到与物理地址保持一致的线性地址空间中,确认GDT和IDT在具有这样的线性地址的页中,清除CR0中的PG,将0H放入CR3中,使得TLB被清除。 将程序控制传送到一个只有64KB大小的可读段中,这一操作使得CS寄存器中的段符合实地址模式的限制。
为SS, DS, ES, FS和GS加载选择符,该选择符指向的段描述符需要包含符合实地址模式需要的值,如64KB的界限值、G=0, E=0, W=1, P=1,基地址可以任意。这些段寄存器必须加载非空段选择符,否则段寄存器在实地址模式下是不可用的。 执行一条LIDT指令来指向实地址模式的中断向量表,该表应该是在1MB的实地址模式地址空间中。 将CR0.PE清零,转换到实地址模式。 执行一条far JMP指令跳转到实地址模式的程序中。这一操作清空了指令队列,将相应的基地址、访问权限装载进CS寄存器。 根据实地址模式下的需要,装载SS, DS, ES, FS和GS。凡是不使用的段寄存器都填充0。 执行STI指令,取消对硬件中断的屏蔽,执行必要的硬件操作来使能NMI中断。
3. 从保护模式到IA-32e模式的转换 在保护模式下,使用MOV CR0, reg指令,另CR0.PG=0,禁止分页。 设置CR4.PAE=1,使能物理地址扩展。如果这一步失败,则产生一个GP#错误。 将4级页映射表(PML4)的物理基地址装载进CR3。 通过设置IA32_EFER.LME=1来使能IA-32e模式。 通过设置CR0.PG=1来允许页式存储管理。这一操作使处理器设置IA32_EFER.LMA=1
4. 从IA-32e模式到保护模式的转换 先转换到兼容模式。 通过设置CR0.PG=0来撤出IA-32e模式。这一操作使处理器设置IA32_EFER.LMA=0。 将传统页表目录基地址加载到CR3。 设置IA32_EFER.LME=0来禁止IA-32e模式。 设置CR0.PG=1来允许传统页式保护模式。 在MOV CR0, reg指令之后一定要有一条分支指令来允许分页。
10.2 任务管理 10.2.1 任务概述 任务执行空间 代码段 数据段 堆栈段 任务状态段(TSS) 段寄存器、通用寄存器、EFLAG寄存器、EIP寄存器、CR3寄存器、任务寄存器、LDTR寄存器中的内容 I/O映像基地址和I/O映像 特权级0,1,2下堆栈的指针 指向前一个任务的链指针
10.2.2 用于任务管理的数据结构 1. 任务状态段(Task-State Segment, TSS)
2. TSS描述符 D7 D0 段界限 7~0 段界限 15~8 基址 7~0 基址 15~8 基址 23~16 基址 31~24 TYPE S AVL DPL P G D/B L 段界限 19~16 1 2 3 4 5 6 7 TYPE=1001B表示该任务是非活动任务;TYPE=1011B表示该任务处于忙状态(正在执行或被挂起)。
TSS描述符只能放在GDT中,不能在LDT或者IDT中。 任何一个CPL值小于或等于TSS描述符中DPL值的程序或过程,都可以使用CALL或JMP语句调度这个任务。 一般只有那些具有特权级的程序可以执行任务切换。
10.2.3 任务切换 1.任务切换的原因 当前的程序、任务或者过程执行一个到GDT中TSS描述符的JMP或者CALL指令; 当前的程序、任务或过程执行一条到GDT中或当前LDT中任务门描述符的JMP或CALL指令; 一个向量指向IDT中任务门的中断或异常发生; 当EFLAGS寄存器中NT位被置上时,当前任务执行了一个IRET指令。
2.任务切换的步骤 从任务门或者前一任务链接域中获得新任务的TSS段选择符作为JMP或CALL指令的操作数; 检查当前任务是否允许切换新任务。要求当前任务的CPL和新任务段选择符中的RPL一定要小于等于TSS描述符或被引用任务门的DPL。但异常、中断(软中断除外)和IRET指令无需考虑目标任务门或TSS描述符中的DPL就能够产生任务切换。 确认新任务的TSS描述符被标识为当前的,并且段界限大于等于67H。验证新任务是可用的。 确认当前TSS,新TSS以及所有任务切换中用到的段描述符都被分页存储到系统存储器中。 如果任务切换是由JMP或IRET指令引起的,处理器将把当前任务TSS描述符的忙状态位清零,否则该位依然设置为1。 如果是IRET指令引起的任务切换。则在EFLAGS临时映像中清除NT标志,否则,保持该位原来的值。
从任务寄存器中取出当前TSS的基地址并将通用寄存器、段选择符、EFLAGS寄存器的映像和EIP的内容拷贝到当前任务的TSS中。 如果任务切换是由CALL指令,异常或中断引起,则处理器会将新任务的EFLAGS中NT位置1;否则,新任务的EFLAGS中NT位不变。 如果任务切换是由执行CALL,JMP指令、异常或中断引起的,处理器会将新任务的TSS描述符中的忙标志位置1;否则该位不变(还是1)。 从任务寄存器中将新任务TSS的段选择符和描述符取出来。 将新TSS内容装入到处理器中,这包括LDTR寄存器、CR3、EFLAGS寄存器、EIP寄存器、通用寄存器和段选择符的内容。 装入与新任务TSS段选择符相关的描述符。 开始执行新任务
10.3 IA-32微机的BIOS 10.3.1 BIOS及其基本功能 BIOS(Basic Input Output System)是基本输入输出系统,它包含主板上的一片ROM、E2PROM或Flash Memory芯片以及被固化在该芯片中的一组程序,这组程序(BIOS程序)称为固件(Firmware)。系统开机后,BIOS程序被首先启动执行,它为计算机提供最低级的、最直接的硬件初始化和外围设备的控制与支持。
BIOS的功能 系统参数的设置与存放 开机自检(PowerOn SelfTest, POST) 初始化 提供系统功能调用 系统启动自举
10.3.2 BIOS程序的执行流程 引导块启动 POST模块启动 解压Runtime模块 解压COMS Setup模块 按Del键了? 是 否 执行CMOS Setup模块 Runtime模块启动 继续解压POST模块 启动操作系统引导程序 解压POST模块 完成POST
10.3.3 BIOS程序开发 开发人员要熟悉汇编编程。 开发人员要熟悉硬件。 开发人员要规划好上层接口。 分配好模块,组织好存储区。 进行严格的软件测试。 选择好必要的开发工具。
10.4 Windows 2000/XP设备驱动程序设计 可以使DOS应用程序访问x86平台上的硬件,也可以支持Windows 9x下的对端口访问 10.4.1 Windows 2000/XP的设备驱动程序 虚拟设备 驱动程序(VDD) 内核模式 驱动程序 是一种遵循电源管理协议并能在Windows 98和Windows 2000间实现源代码级兼容的PnP驱动程序 文件系统 驱动程序 保留设备 驱动程序 PnP 驱动程序 主要包括Windows NT早期版本的驱动程序,它直接控制一个硬设备而不用其他驱动程序帮助,可以不做修改地在Windows 2000中运行 WDM驱动程序 在本地硬盘或网络上实现标准PC文件系统模型(包括多层次目录结构和命名文件概念) 类驱动程序 迷你驱动程序 过滤器驱动程序 完整功能驱动程序
10.4.2 WDM的基本结构 1. 基本概念 设备对象:系统为帮助软件管理硬件而创建的一个数据结构。一个物理设备可以有多个这样的数据结构。 物理设备对象:简称PDO,处于设备对象栈最底层的设备对象。每个物理设备被创建一个PDO 功能设备对象:简称FDO,在PDO之上,描述设备功能的相关数据结构。 过滤器设备对象:简称FiDOs,在FDO的上面或下面,分别称为上层过滤器和下层过滤器。用于修改现有功能驱动程序的行为。 设备对象栈:设备对象栈代表处理请求的驱动程序层次。
应用程序 Win32子系统 用户态 核心态 I/O系统服务 设备对象栈 IRP FiDO 上层过滤器驱动程序 I/O管理器 FDO 功能驱动程序 FiDO 下层过滤器驱动程序 PDO 总线驱动程序 46页
2. 硬件设备的驱动程序种类 WDM驱动程序模型中,每个硬件设备可以有多个驱动程序: 功能驱动程序 :管理FDO所代表的设备,负责其初始化、处理I/O操作完成时产生的中断事件并为用户提供一种适当的设备控制方式。 过滤器驱动程序:用于监视和修改IRP流。硬件或软件人员可利用过滤器驱动程序修改现有功能驱动程序的行为。 总线驱动程序:负责管理硬件和计算机之间的连接。这个驱动程序实际上和同类设备共同拥有。如PCI总线驱动程序。
PnP管理器为该设备和它的驱动程序在注册表的配置表中添加一些条目 3. 设备驱动程序安装的顺序 硬件接入 总线驱动程序检测到新的硬件 用户使用控制面板中的“添加新硬件”向导安装一个设备 PnP管理器创建PDO PnP管理器为该设备和它的驱动程序在注册表的配置表中添加一些条目 PnP管理器可能需要调整已经分配给已存在设备的资源,使需要的资源对新设备可用
PnP管理器参照注册表中的信息查找与创建的PDO相关的过滤器和功能驱动程序 按照INF文件的指令安装驱动程序 驱动程序被装入后,执行DriverEntry程序。来设置驱动程序中各个例程的入口地址 PnP管理器装入最底层的过滤器驱动程序并调用其AddDevice函数。该函数创建一个FiDO,从而在过滤器驱动程序和FiDO之间建立了水平连接
AddDevice把PDO连接到FiDO上 PnP管理器继续向上执行,依次装入并调用每个低层过滤器、功能驱动程序和每个高层过滤器,直到完成整个设备对象栈 PnP管理器给设备发送各种PnP IRP PnP管理器给发送“启动设备”PnP IRP告诉驱动程序已经给它分配了哪些资源 ,驱动程序使用这些资源分配启动它的设备 驱动程序处于等待处理IRP的状态
当应用程序因要向驱动程序提出各类请求(如读、写数据等)而调用相关函数的时候,就会使得I/O管理器创建一个I/O请求包(IRP)。 通常一个I/O请求包(IRP)先被送到设备对象栈的最上层驱动程序然后逐渐过滤到下面的驱动程序。每一层驱动程序都可以决定如何处理IRP,既可以直接处理完该IRP就不再向下传,也可以处理完后继续传递,还可以只做向下传递的工作。 当下层将请求处理完,返回的信息又通过该包的结构逐层向上传递。 46页
10.4.3 I/O请求包(IRP) I/O请求包(IRP)是驱动程序操作的中心,它是一个内核“对象”,是预先定义的数据结构,带有一组对它进行操作的I/O管理器程序。I/O管理器接收到一个I/O请求后,在把它传递到合适的驱动程序栈中的最高驱动程序之前,分配并初始化一个IRP。一个IRP有一个固定的首部和一个可变数目的I/O栈。
创建IRP的可以是I/O管理器,也可以是其他的驱动程序。能创建IRP的函数有: 创建异步IRP的IoBuildAsynchronousFsdRequest 创建同步IRP的IoBuildSynchronous- FsdRequest 创建同步IRP_MJ_DEVICE_CONTROL或IRP_MJ_INTERNAL_DEVICE_CONTROL请求的IoBuildDeviceIoControlRequest 创建其他种类IRP的IoAllocateIrp 创建某些IRP的子IRP的IoMakeAssociatedIrp。
在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组,它是I/O栈中的一项,它包含的成员包括: MajorFunction(该IRP的主功能码) MinorFunction(该IRP的副功能码) Parameters(IRP参数) DeviceObject(与该栈单元对应的设备对象地址) FileObject(内核文件对象地址) CompletionRoutine(I/O完成程序地址) Context(任意的与上下文相关的值)。
在栈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)。
大部分参数可以和Win32函数对应起来 参数 Win32 API Creat CreateFile Read ReadFile Write WriteFile DeviceIOControl DeviceIoControl CloseHandle Close 返回
创建完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发送到设备驱动程序 返回
下面是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
10.4.4 WDM驱动程序的结构 WDM驱动程序包含许多函数(例程),操作系统调用这些例程来执行对IRP的各种操作。 基本驱动程序函数 I/O控制函数 派遣函数 DriverEntry StartIO DispatchPnp AddDevice AdapterControl DispatchPower OnInterrupt DispatchWmi DpcForIsr DispatchRead DispatchWrite StartIO处理请求队列、 AdapterControl处理DMA操作 OnInterrupt处理中断。
在每个WDM驱动程序中,下列函数必须有: DriverEntry函数:这个例程是每一个设备驱动程序的入口。在这个例程中完成某些全局初始化工作,还要设置响应各种用户请求的分发例程与I/O控制例程的入口。 AddDevice函数:对于功能驱动程序,其AddDevice函数的基本职责是创建一个设备对象并把它连接到以PDO为底的设备堆栈中。 DispatchPnp函数:用于处理IRP_MJ_PNP消息,以便能实现即插即用的功能。 DispatchPower函数:用于实现对电源管理的支持。 DispatchWmi函数:WMI是微软实现的基于Web的企业管理工业标准,该函数用于处理有关的消息。
下面是一段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处理函数的入口地址 返回
// 如果驱动程序需要访问设备的服务键,则备份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; }
添加一个设备 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; …… }
NTSTATUS DispatchXxx(PDEVICE_OBJECT device, PIRP Irp) { PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);//获得栈单元指针 PDEVICE_EXTENSION pdx =(PDEVICE_EXTENSION) device->DeviceExtension; //获得设备扩展 …… //其他IRP处理操作 return STATUS_Xxx; //返回状态码 } 返回
对WDM请求包运行机制的总结 应用程序通过CreateFile等Win32函数来进行有关的请求。 I/O管理器创建IRP。 设置IRP中的主功能代码和对IRP栈做各种初始化工作。如果需要对IRP排队,则调用StartIo处理IRP队列 将IRP发送到派遣程序(按照DriverEntry中指定的入口地址来调用相关的派遣程序)。 执行有关的派遣程序,实际处理对IPR的操作。
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 用户在意外下拔出设备
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; }
10.4.6 数据的读/写 WDM有4个标准的资源类型,分别是: CmResourceTypePort(端口资源) CmResourceTypeMemory(内存资源) CmResourceTypeInterrupt(中断资源) CmResourceTypeDma(DMA资源)
1. 内存与端口访问 尽管PC机的I/O端口是单独编址的,但为了做到和统一编址的机器兼容性,Windows 2000的设计者使用了硬件抽象层(HAL)的概念。无论是单独编址还是统一编址,只需要使用下表8中所给的函数就可以访问端口和内存了。
数据宽度 端口访问函数 内存访问函数 8位 READ_PORT_UCHAR WRITE_PORT_UCHAR READ_REGISTER_UCHAR WRITE_ REGISTER _UCHAR 16位 READ_PORT_USHORT WRITE_PORT_USHORT READ_ REGISTER _USHORT WRITE_ REGISTER _USHORT 32位 READ_PORT_ULONG WRITE_PORT_ULONG READ_ REGISTER _ULONG WRITE_ 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
2. 响应中断 响应中断首先要配置中断,也就是截获中断,然后就需要编写中断处理程序。 配置中断资源是在StartDevice函数中实现的,使用从CmResourceTypeInterrupt描述符中得到的参数来调用IoConnectInterrupt函数。和实模式下一样,在调用IoConnectInterrupt进行中断配置前应该禁止PC机的中断,调用之后再允许设备中断。
10.4.7 WDM驱动程序的安装文件 驱动程序根据INF文件中的指令安装。INF文件含有安装一个WDM设备驱动程序需要的所有必需的信息,包括要复制的文件列表和要创建的注册表项等。 驱动程序可执行文件被复制到正确的位置,通常是Winnt\System32\Drivers目录,然后创建各种注册表项。 INF文件是一个文本文件,它由节组成,每一节从括在方括号中的节名称开始,后面是节的内容,大部分段都含有一系列“keyword = value”形式的项。
节 项 值 描 述 [Version] Signature Provider Class ClassGuid DriverVer $Windows NT$, $Windows 95$或$Chicago$ INF文件创建者 系统定义的类名字,或用户指定的新的类名字 匹配的类GUID 驱动程序的版本号 [Strings] %String%=”Value” 指定一个字符串 [Manufacturer] %manufacturer%=models 指定厂商名和对应的models节的名称 [models] 指定产品名称、对应的install节的名称和硬件ID,0个或多个兼容ID
节 项 值 描 述 [install] Copyfiles=@filename | filelist Addreg=addreg ProfileItems 指定要复制的文件,或列出filelist节的名称 指定addreg节的名称 列出指定要添加到“开始”菜单中的项 [DestinationDirs] DefaultDestDir=dirid,[subdir] filelist= dirid,[subdir] 对默认文件复制和filelist节中的文件复制,指定目录ID和可选的子目录。dirid是一个目录代码,指示存放文件的标准位置。Windows 2000DDK定义了这些代码,如代码10表示Windows目录 [filelist] 要安装的文件列表 [addreg] 添加新的键和值