mmLockPagableCodeSection 宏 (wdm.h)

MmLockPagableCodeSection 例程将驱动程序代码的一部分(包含一组用特殊编译器指令标记的驱动程序例程)锁定到系统空间中。

语法

void MmLockPagableCodeSection(
  [in]  Address
);

参数

[in] Address

指定符号地址。 此地址通常是驱动程序代码部分中的驱动程序函数的名称,该代码部分标有 类似于 #pragma alloc_text (PAGExxxx、driverfunction) 。 然后,当此函数返回时,可以保证将 PAGExxxx 节中的所有函数锁定。

返回值

备注

MmLockPagableCodeSection 返回操作系统用于标识此部分驱动程序代码的不透明值。 此不透明值随后可以传递到 MmLockPagableSectionByHandle (如果驱动程序解锁,然后重新锁定节) 或 MmUnlockPagableImageSection

MmLockPagableCodeSection 例程和 MmUnlockPagableImageSection (执行相反操作的例程,) 支持可执行以下操作的驱动程序:

  • 延迟将驱动程序例程的子集加载到常驻内存中,直到驱动程序设备的传入 I/O 请求使这些例程需要处理 IRP。

  • 当驱动程序例程已完成 I/O 请求的处理并且当前没有针对驱动程序设备的其他请求时,让相同的驱动程序例程子集可用于分页。

MmLockPagableCodeSectionMmLockPagableSectionByHandleMmUnlockPagableImageSection 适用于具有以下特征的设备和中间驱动程序:

  • 驱动程序的代码路径在系统运行时可能不需要,但是,如果需要,驱动程序的代码必须驻留,因为它在任意线程上下文中或在 IRQL >= DISPATCH_LEVEL运行。

  • 驱动程序可以确切地确定应何时加载可分页例程,以及何时可以再次将其分页。

例如,系统提供的容错磁盘驱动程序支持创建镜像集、条带集和卷集。 但是,特定计算机只能配置镜像集、带区集、卷集或这三种可能选项的任意组合。 在这些情况下,系统 ftdisk 驱动程序通过将显式支持镜像、条带和卷集的例程标记为属于可分页代码部分,来减小其加载映像的大小。 在驱动程序初始化期间,仅当用户将磁盘配置为具有镜像、条带或卷集时,可分页代码部分才会驻留。 如果用户动态地重新分区磁盘,则 ftdisk 驱动程序会锁定支持用户请求的任何镜像、条带或卷集所需的任何其他可分页代码部分。

与其他示例一样,系统提供的串行和并行驱动程序具有 DispatchCreateDispatchClose 例程,这些例程分别在为独占 I/O 打开特定端口和释放已打开端口的句柄时调用。 但是,串行和并行 I/O 请求是偶发的,由最终用户当前运行的应用程序以及最终用户当前正在执行的应用程序选项决定。 在这些情况下,系统串行和并行驱动程序通过将许多例程标记为属于 DispatchCreate 例程仅在为 I/O 打开第一个端口时才驻留的可分页代码节来减小其加载映像的大小。

请注意,上述每个系统驱动程序都满足具有可分页节的这两个条件:驱动程序具有在系统运行时可能不需要的代码路径,并且驱动程序可以确切确定何时应加载其可分页节,并且可以再次分页。

由于锁定节是一项成本高昂的操作,因此如果驱动程序在多个位置锁定可分页代码部分,请对第一个请求使用 MmLockPagableCodeSection 。 通过调用 MmLockPagableSectionByHandle 并传递 MmLockPagableCodeSection 返回的句柄,发出后续锁定请求。 句柄锁定可显著提高驱动程序性能,因为内存管理器使用不透明返回值来快速查找相关部分,而不是搜索加载的模块列表。 通过调用 MmUnlockPagableImageSection 解锁锁定的分区。

必须使用以下编译器指令标记可分页代码节中的每个驱动程序例程:

#pragma alloc_text(PAGExxxx, DriverRoutine)

其中 xxxx 是调用方可分页节的可选四字符唯一标识符, DriverRoutine 是要包含在可分页代码节中的入口点。 关键字 (keyword) PAGE 和驱动程序确定的后缀(最多可以包含四个字符)区分大小写;也就是说,PAGE 必须大写。

例如,在驱动程序的 DispatchCreate 例程中对 MmLockPagableCodeSection 进行一次调用会导致整个部分(包含每个标记为同一 PAGExxxx 标识符的驱动程序例程)在系统空间中被锁定。

某些类型的驱动程序例程不能成为任何驱动程序的可分页部分的一部分,包括:

  • 切勿使 ISR 可分页。 即使设备未使用,设备驱动程序也可能接收虚假中断,尤其是在可以共享中断向量的情况下。 通常,即使驱动程序可以在其设备上显式禁用中断,也不应使 ISR 可分页。

  • 如果驱动程序无法控制 DPC 何时排队,例如可能从 ISR 排队的任何 DpcForIsrCustomDpc 例程,则永远不要使 DPC 例程可分页。 通常,在 IRQL >= DISPATCH_LEVEL运行且可在任意线程上下文中调用或响应随机外部事件的驱动程序例程不应成为可分页的。

  • 切勿在任何可能属于系统分页 I/O 路径的驱动程序中使 DispatchReadDispatchWrite 例程可分页。 可能包含系统页文件的磁盘的驱动程序必须具有在系统运行时驻留的 DispatchReadDispatchWrite 例程,此类磁盘驱动程序上层的所有驱动程序也必须如此。

请注意,标有编译器指令的可分页节中的例程 #pragma alloc_text (PAGExxxx, ...) 不同于用 编译器指令 #pragma alloc_text (INIT, ...) 标记的 例程。 INIT 部分中的例程不可分页,一旦驱动程序从其 DriverEntry重新初始化 例程返回(如果有),就会被丢弃。

内存管理器在任何驱动程序的可分页节上维护内部锁计数。 调用 MmLockPagableCodeSection 递增此计数,倒数 MmUnlockPagableImageSection 将递减计数。 驱动程序的可分页部分不可分页,除非此计数为零。

有关创建可分页代码部分的详细信息,请参阅 使驱动程序可分页

要求

要求
目标平台 桌面
标头 wdm.h(包括 Wdm.h、Ntddk.h、Ntifs.h)
Library NtosKrnl.lib
DLL NtosKrnl.exe
IRQL <=APC_LEVEL

另请参阅

MmLockPagableDataSection

MmLockPagableSectionByHandle

MmPageEntireDriver

MmResetDriverPaging

MmUnlockPagableImageSection