• 47、Windows驱动程序模型笔记(五),内存管理


    内存管理

    1)内核模式与用户模式地址

    wps_clip_image-4593

    图示 地址空间中用户模式部分和内核模式部分

        每个用户模式进程都有自己的地址上下文,它把用户模式的虚拟地址映射成一组唯一的物理页帧。这意味着,当Windows NT调度器把控制从一个进程的当前线程切换到另一个进程的某个线程时,与进程相对应的虚拟地址空间也被更换。线程切换的一个步骤就是改变处理器当前使用的页表,以便它能引用新线程的进程上下文。

        在编写驱动程序时我们要遵守下面原则:

        决不(或几乎从不)直接引用用户模式的内存地址,无论何时我们需要访问计算机内存,都要使用内核模式的虚拟地址。

    2)页大小

        在虚拟内存系统中,操作系统以固定大小的页帧组织物理内存和交换文件。在WDM驱动程序中,常量PAGE_SIZE指出页的大小。在某些Windows NT计算机中,一页有4096字节;在另一些计算机中,一页有8192字节。有一个相关常量PAGE_SHIFT,你可以从下面语句中看出它的值:

    PAGE_SIZE == 1 << PAGE_SHIFT

    下面预处理宏可以简化页大小的使用:

    •ROUND_TO_PAGES 把指定值舍入为下一个页边界。例如,在4KB页的计算机上,ROUND_TO_PAGES(1)的结果为4096,ROUND_TO_PAGES(4097)的结果为8192。

    •BYTES_TO_PAGES 得出给定的字节量需要多少页来保存。例如,BYTES_TO_PAGES(42)在所有平台上都等于1,而BYTES_TO_PAGES(5000)在4KB页的平台上为2,在8KB页的平台上为1。

    •BYTE_OFFSET 返回虚拟地址的字节偏移部分。例如,在4KB页的计算机上,BYTE_OFFSET(0x12345678)的结果为0x678。

    •PAGE_ALIGN 把虚拟地址舍向上一个页边界。例如,在4KB页的计算机上,PAGE_ALIGN(0x12345678)的结果为0x12345000。

    •ADDRESS_AND_SIZE_TO_SPAN_PAGES 返回从指定虚拟地址开始的指定字节数所跨过的页数。例如,在4KB的计算机上, ADDRESS_AND_SIZE_TO_SPAN_PAGES(0x12345FFF,2)的结果为2,因为这两个字节跨过了页边界。

    3)Windows NT把内核模式地址空间分成分页内存池和非分页内存池。(用户模式地址空间总是分页的) 必须驻留的代码和数据放在非分页池;不必常驻的代码和数据放在分页池中。

    执行在高于或等于DISPATCH_LEVEL级的代码不可以引发页故障。

    #ifdef ALLOC_DATA_PRAGMA

    #pragma data_seg("PAGE")

    #endif

    data_seg编译指示使所有在其后声明的静态数据变量进入分页池。这个编译指示与alloc_text完全不同。一个分页段可以从#pragma data_seg("PAGE")出现的地方开始到#pragma data_seg()出现的地方结束。而Alloc_text仅应用于单个函数。

        为了检测编译器是否是Microsoft的编译器,可以测试预定义宏_MSC_VER是否存在。

    掉电期间是释放锁定内存页的最佳时期。

    服务函数

    描述

    MmLockPagableCodeSection

    锁定含有给定地址的代码段

    MmLockPagableDataSection

    锁定含有给定地址的数据段

    MmLockPagableSectionByHandle

    用MmLockPagableCodeSection返回的句柄锁定代码段(仅用于Windows 2000)

    MmPageEntireDriver

    解锁所有属于某驱动程序的页

    MmResetDriverPaging

    恢复整个驱动程序的编译时分页属性

    MmUnlockPagableImageSection

    为一个锁定代码段或数据段解锁

    服务函数或宏

    描述

    PushEntryList

    向链表顶加入元素

    PopEntryList

    删除最上面的元素

    4)把C/C++编程规范引入驱动编程中

    如RemoveHeadList是一个宏,如果if语句中不用{},则出问题。

    5)图示显示了 lookaside链表的概念。假设有一个可以在水池中直上直下平衡的玻璃杯子。这个杯子就代表lookaside链表对象。当初始化该对象时,你告诉系 统需要多大的内存块(杯中的水滴)。在早期版本的Windows NT中,你还要指出杯子的容量,但现在的操作系统可以自动适应。为了满足一个内存分配请求,系统首先尝试着从链表中取出(删除)一块内存(从杯子中取出一 滴水)。如果连一块内存也没有,系统就从外面内存池中取。相反,释放内存时,系统首先尝试着放到链表上(向杯子中加入一滴水)。但是,如果链表满了,那么 这个内存块就返回到外界的内存池中(杯子中的水溢出到水池)。

    wps_clip_image-21083

    图示. Lookaside链表

    4、字符串

    String Manipulation

    http://msdn.microsoft.com/en-us/library/ee479680.aspx

    Buffer Manipulation

    http://msdn.microsoft.com/en-us/library/ee479504.aspx

    P89串处理函数

    操作

    ANSI串函数

    Unicode串函数

    Length

    strlen

    wcslen

    Concatenate

    strcat, strncat

    wcscat, wcsncat,

    RtlAppendUnicodeStringToString,

    RtlAppendUnicodeToString

    Copy

    strcpy, strncpy,

    RtlCopyString

    wcscpy, wcsncpy,

    RtlCopyUnicodeString

    Reverse

    _strrev

    _wcsrev

    Compare

    strcmp, strncmp,

    _stricmp, _strnicmp,

    RtlCompareString,

    RtlEqualString

    wcscmp, wcsncmp, _wcsicmp,

    _wcsnicmp,

    RtlCompareUnicodeString,

    RtlEqualUnicodeString,

    RtlPrefixUnicodeString

    Initialize

    _strset, _strnset,

    RtlInitAnsiString,

    RtlInitString

    _wcsnset, RtlInitUnicodeString

    Search

    strchr, strrchr, strspn,

    strstr

    wcschr, wcsrchr, wcsspn, wcsstr

    Upper/lowercase

    _strlwr, _strupr,

    RtlUpperString

    _wcslwr, _wcsupr,

    RtlUpcaseUnicodeString

    Character

    isdigit, islower, isprint,

    isspace, isupper, isxdigit,

    tolower, toupper,

    RtlUpperChar

    towlower, towupper,

    RtlUpcaseUnicodeChar

    Format

    sprintf, vsprintf, _snprintf,

    _vsnprintf

    swprintf, _snwprintf

    String conversion

    atoi, atol, _itoa

    _itow, RtlIntegerToUnicodeString,

    RtlUnicodeStringToInteger

    Type conversion

    RtlAnsiStringToUnicodeS

    ize, RtlAnsiStringToUnicodeS

    tring

    RtlUnicodeStringToAnsiString

    Memory release

    RtlFreeAnsiString

    RtlFreeUnicodeString

    1)处理blob数据的服务函数

    . 处理blob数据的服务函数

    服务函数或宏

    描述

    memchr

    blob中寻找一个字节

    memcpy, RtlCopyBytes, RtlCopyMemory

    复制字节,不允许重叠

    memmove, RtlMoveMemory

    复制字节,允许重叠

    memset, RtlFillBytes, RtlFillMemory

    用给定的值填充blob

    memcmp, RtlCompareMemory, RtlEqualMemory

    比较两个blob

    memset, RtlZeroBytes, RtlZeroMemory

    blob清零

    •内存的“copy”和“move”操作之间的区别在于可否容忍源和目的相重叠。move操作不管源和目的是否重叠。而copy操作在源和目的有任何重叠时不工作。

    •“byte” 操作和“memory”操作的区别是操作的间隔尺寸。byte操作保证按字节为单位执行。而memory操作可以在内部使用更大的块,所有这些块的和等于 指定的字节数。这个区别会根据平台的不同而改变,在32位Intel计算机上,byte操作实际上是对应memory操作的宏。但在Alpha平台 上,RtlCopyBytes与RtlCopyMemory是完全不同的函数。

    5、注册表

    服务函数

    描述

    IoOpenDeviceRegistryKey

    打开PDO专用键

    IoOpenDeviceInterfaceRegistryKey

    打开与注册设备接口相连的键

    RtlDeleteRegistryValue

    删除一个注册表值

    RtlQueryRegistryValues

    从注册表中读取多个值

    RtlWriteRegistryValue

    向注册表写一个值

    ZwClose

    关闭注册表键句柄

    ZwCreateKey

    创建一个注册表键

    ZwDeleteKey

    删除一个注册表键

    ZwEnumerateKey

    枚举子键

    ZwEnumerateValueKey

    枚举某注册表键中的值

    ZwFlushKey

    把注册表更改提交到磁盘

    ZwOpenKey

    打开一个注册表键

    ZwQueryKey

    取关于某注册表键的信息

    ZwQueryValueKey

    取某个注册表键中的值

    ZwSetValueKey

    置某个注册表键中的值

    表示. 注册表访问函数

    6、浮点数

        在Intel处理器上,浮点协处理器还可以执行MMX指令。在历史上,驱动程序在执行浮点运算上有两个问题。对于没有浮点协处理器的计算机,操作系统将用 软件仿真一个,但是仿真的浮点协处理器会消耗很大的CPU处理能力,并且需要一个处理器异常来捕捉浮点指令。在内核模式中处理异常,尤其是在提升的 IRQL级上,是困难的。另外,在有浮点协处理器的计算机上,由于CPU结构上的原因,当线程上下文切换时,需要一个耗时的操作来保存和恢复浮点协处理器 的状态。所以,通常的做法是禁止在内核模式驱动程序中使用浮点运算。

        Microsoft建议,除非必要,应避免在内核模式驱动程序中使用浮点运算。

    关于如何使用及更多信息,可以参见《Windows驱动程序模型设计》,P99

  • 相关阅读:
    Linux 下没有 my.cnf 文件的解决方式,完全是我自己整的,好多教程都是瞎扯的 (zhuan)
    Virtualbox虚拟机安装CentOS6.5图文详细教程(zhuan)
    virtualbox中centos系统配置nat+host only上网(zhuan)
    VirtualBox的网络配置,Host Only+NAT方式 (zhuan)
    Linux上安装Mysql后除了本机其他机器不能访问的问题(zhuan)
    VirtualBox没有64位选项,无法安装64位的解决方法(zhuan)
    CentOS查看内核版本,位数,版本号 (zhuan)
    datagrid实现单行的选择、取消
    datagrid实现行的上移和下移
    Excel 、数据库 一言不合就转换 (zhuan)
  • 原文地址:https://www.cnblogs.com/mydomain/p/1925441.html
Copyright © 2020-2023  润新知