首页
社区
课程
招聘
[翻译]《深入解析windows操作系统第6版下册》第10章:内存管理(第三部分)
发表于: 2016-1-3 14:43 29551

[翻译]《深入解析windows操作系统第6版下册》第10章:内存管理(第三部分)

2016-1-3 14:43
29551



由于论坛限制了每帖能够引用的外链图片数为40张。因此第三部分译文将接着第二部分的“64 位地址空间布局”一节中未完成的部分继续 ,直到“IA 64 虚拟地址翻译”一节结束。

The detailed IA64 and x64 address space layouts vary slightly. The IA64 address space layout is shown in Figure 10-12, and the x64 address space layout is shown in Figure 10-13.
IA64 与 x64 地址空间布局的细节略有差异。        图 10-12 给出了 IA64 的地址空间布局;10-13 给出了 x64 的地址空间布局。(译注:为了能够容纳下译文,将原图划分成了几张子图,并以罗马数字标记,请注意左侧地址的改变及其关联性)














下面是 x64  地址空间布局






(译注:关于 64 位 Windows 的虚拟地址空间布局,上图的介绍可能过于简单,特别是对于某些特定的系统虚拟地址空间区域,有鉴于此,特别翻译了 CodeMachine 站点上一篇对此作了详尽介绍的文章。原文链接为 http://www.codemachine.com/article_x64kvas.html,并把它放在这里与上图对比参照,可以更好的理解。为了区别,以褐色表示来自 CodeMachine 站点的译文。首先援引其中的地址空间布局概要表,如下所示。它与上图 10-13 的 x64 地址空间布局图的每个区域一一对应:



未使用的系统空间(FFFF0800`00000000~FFFFF67F`FFFFFFFF)
这个区域的起始地址保存在内核全局变量 nt!MmSystemRangeStart 中。此区域在  Windows 7 X64 上是未使用的。



PTE 空间(FFFFF680`00000000~FFFFF6FF`FFFFFFFF)
此区域包含 X64 处理器使用的四级页表页面,用于用户模式与内核模式虚拟地址空间的映射。各种类型的 X64 页表页面被映射到下面列出的特定地址范围内:
PTE Pages   FFFFF680`00000000                       
PDE Pages   FFFFF6FB`40000000               
PPE Pages   FFFFF6FB`7DA00000                       
PXE Pages   FFFFF6FB`7DBED000


超空间(FFFFF700`00000000~FFFFF77F`FFFFFFFF)
驻留在物理内存中的进程相关页面称为“工作集”,那么显然这些物理页面需要映射到系统虚拟地址空间中的一个特殊区域进行统一管理,此区域称为“超空间”
进程工作集列表和每进程相关的内存管理数据结构(它们不需要在任意进程的上下文中被访问)都映射到这个 512GB 的区域中。每个进程的 EPROCESS.Vm.VmWorkingSetList 成员存储地址
0xFFFFF700`01080000 的信息(一个 _MMWSL 型指针)。对于每个在进程工作集中的页面(这些页面驻留在物理内存中),在此区域(即 EPROCESS.Vm.VmWorkingSetList 指向的地址)都存在一个对应的 _MMWSL(内存管理器工作集列表)数据结构;还有一个对应的 _MMWSLE(内存管理器工作集列表条目)数据结构也在此区域中,后者的具体位置由 EPROCESS.Vm.VmWorkingSetList.wsle 指向的地址确定。下面以 32 位系统为例:

[FONT="微软雅黑"][SIZE="4"][COLOR="Black"]dt nt!_EPROCESS  -r 872e1d28 (某个进程的 EPROCESS 结构的虚拟地址)

(。。。省略无关输出。。。)
 +0x054 VmWorkingSetList : 0xc0802000 _MMWSL
    +0x000 FirstFree        : 0x5693
    +0x004 FirstDynamic     : 6
    +0x008 LastEntry        : 0x5970
    +0x00c NextSlot         : 6
    +0x010 Wsle             : 0xc0802d08 _MMWSLE

dt nt!_EPROCESS  -r
(。。。省略无关输出。。。)
  +0x054 VmWorkingSetList : Ptr32 _MMWSL
     +0x000 FirstFree        : Uint4B
     +0x004 FirstDynamic     : Uint4B
     +0x008 LastEntry        : Uint4B
     +0x00c NextSlot         : Uint4B
     +0x010 Wsle             : Ptr32 _MMWSLE
[/COLOR][/SIZE][/FONT]


在上面这个例子中,地址 0xc0802000 在 32 位系统上的超空间区域内,_MMWSL 结构位于此处;而 _MMWSLE 结构则位于其后不远的 0xc0802d08 地址处。
超空间也用于临时将物理页面(PFN)映射到系统空间。而超空间内的虚拟地址实际上是从系统 PTE 区域中分配的。其中一个例子就是,除了进程页表中的无效页表条目外,引用的有效页面(例如,当一个页面从备用[standby]列表中被移除时)。
MiMapPageInHyperSpaceWorker() 把一个 PFN 映射到超空间,并返回分配给此映射的虚拟地址。MiMapPageInHyperSpaceWorker() 本应该把驻留在物理内存中的进程页面映射到超空间,但实际上它把这些页面映射到系统 PTE 区域。
MiZeroPhysicalPage(),MiWaitForInPageComplete(),MiCopyHeaderIfResident(),MiRestoreTransitionPte() 等函数,都调用 MiMapPageInHyperSpaceWorker() ,临时获取被映射到超空间内物理页面的虚拟地址。


共享的系统页面(FFFFF780`00000000~FFFFF780`00000FFF)
这个 4KB 的页面在 UVAS(用户虚拟地址空间)与 KVAS(内核虚拟地址空间)之间共享。它提供了一个在用户和内核模式间快速传递信息的方法。与此相关的共享数据结构为
nt!_KUSER_SHARED_DATA


系统缓存工作集(FFFFF780`00001000~FFFFF7FF`FFFFFFFF)
此区域用于映射系统缓存工作集和系统缓存工作集列表条目。
内核变量 nt!MmSystemCacheWs 指向用于系统缓存的工作集数据结构(例如 nt!_MMSUPPORT)。要显示用于系统缓存的工作集列表条目,
使用命令“!wsle 1 @@(((nt!_MMSUPPORT *) @@(nt!MmSystemCacheWs))->VmWorkingSetList)”。工作集修剪器使用这些条目来从系统缓存虚拟地址修剪对应的物理页面。(关于工作集修剪器,请参考第一部分译文的“平衡集管理器”)


由最初的加载器映射(FFFFF800`00000000~FFFFF87F`FFFFFFFF)
在系统引导阶段,winload.exe 将 NTOSKRNL.EXE,HAL.DLL,以及内核调试器 DLL(KDCOM, KD1394, KDUSB)加载到此区域。该区域还包含了空闲线程的栈,DPC(延迟过程调用)的栈,以及 KPCR(内核处理器控制区,Kernel Processor Control Region)和 Idle 线程的数据结构。


分页池区(FFFFF8a0`00000000~FFFFF8bF`FFFFFFFF)
内核变量 nt!MmPagedPoolEnd 存储可分页池的当前结束地址(由此可见它是动态增长或缩减的)。同样的,其当前大小存储在内核变量 nt!MmSizeOfPagedPoolInBytes 中。当调用
MiObtainSystemVa() 时传入 MiVaPagedPool 类型的系统虚拟地址范围时,它就会在此区域中分配。内核位图(Bitmap)——nt!MiPagedPoolVaBitMap——控制从可分页池中分配虚拟地址空间的操作,并且,内核变量 nt!MiPagedPoolVaBitMapHint 存储其分配提示(allocation hint)


PFN 数据库(FFFFFa80`00000000~*nt!MmNonPagedPoolStart-1)
系统中每一个物理页面在 PFN 数据库中都有一个条目来描述其物理页框号(系统上的物理页面总数为,内核变量 nt!MmHighestPossiblePhysicalPage 的值加1),这是为了让 PFN 条目能适应热插拔内存。在内核调试器中,以下表达式:
? poi(nt!MmNonPagedPoolStart) - poi(nt!MmPfnDatabase)
可以用来确定 PFN 数据库的大小。另外,要确定 PFN 数据库中条目的总数,可以使用以下表达式:
?(poi(nt!MmNonPagedPoolStart) - poi(nt!MmPfnDatabase))/ @@(sizeof(nt!_MMPFN))
内核变量  nt!MmPfnDatabase 负责定义此区域(用于 PFN 数据库)的起始地址。
(译注:使用 32 位 Windows 7 客户机版本,在任务管理器中显示的可用物理内存总数为 3.5GB。每个物理页面跨越 4KB 的物理地址范围,这里按 4096 字节计算。
命令 dd nt!MmHighestPossiblePhysicalPage 的输出结果为 000defff,加1为 000dffff,即10进制的 913408,913408 * 4096 B = 3741319168 B ,与 3.5GB 大致相符,验证了上面讨论的部分内容
另外,从命令 ?(poi(nt!MmNonPagedPoolStart) - poi(nt!MmPfnDatabase))/ @@(sizeof(nt!_MMPFN)) 的输出得知, PFN 数据库中条目的总数为 913993,而物理页面总数为 913408,如果按照一个 PFN 条目描述一个 4KB 范围的物理页面,那么数据库中还剩余 585 项未使用 )


非分页池区(*nt!MmNonPagedPoolStart ~ *nt!MmNonPagedPoolEnd)
非分页池区域紧随在 PFN 数据库之后。非分页池的起始地址存储在内核变量 nt!MmNonPagedPoolStart 中。当调用 MiObtainSystemVa() 时传入 MiVaNonPagedPool 类型的系统虚拟地址范围时,它就会在此区域中分配。内核位图——nt!MiNonPagePoolVaBitmap——控制从非分页池中分配虚拟地址空间的操作,并且,内核变量
nt!MiNonPagedPoolVaBitMapHint 存储其分配提示。


HAL 和 winload.exe 映射区域(FFFFFFFF`FFc00000~FFFFFFFF`FFFFFFFF)
内核全局变量 nt!MiLowHalVa 存储此区域的起始地址,即,0xFFFFFFFFFFC00000。此虚拟地址范围结束于 0xFFFFFFFFFFFFFFFF,它同时也是 X64 内核虚拟地址空间的结尾
此区域仅用于系统启动时刻,在 MmInitSystem() 例程的内部逻辑中,会将 HAL 与 winload.exe 映射到此区域。这意味着,在初始化阶段后,系统无法使用属于此地址范围的内存。

(译注:结合前面对“由最初的加载器映射”区域的讨论,可以看出,在系统引导阶段,winload.exe 将 NTOSKRNL.EXE,HAL.DLL 映射到 FFFFF800`00000000~FFFFF87F`FFFFFFFF 范围,然后,控制权转交内核时,也就是进入系统初始化阶段时,内核(NTOSKRNL.EXE 中的 MmInitSystem() 例程)反过来将 HAL 与 winload.exe 映射到 FFFFFFFF`FFc00000~FFFFFFFF`FFFFFFFF 范围,整个过程中,HAD.DLL 分别被映射到2个不同的系统虚拟地址范围。)
在系统初始化结束时刻,MmInitSystem() 调用函数 MiAddHalIoMappings(),后者扫描此虚拟地址范围并判断是否需要向由系统维护的 I/O 映射列表中添加任何 I/O 映射,如果需要,则调用 MiInsertIoSpaceMap() 例程。MiInsertIoSpaceMap() 为每个 I/O 映射创建一个追踪器条目,其带有名称为 MmIo "IO space mapping trackers " 的池标签,并且将该追踪器条目添加到一个双向链表(即 I/O 映射列表)中;内核变量 nt!MmIoHeader 指向此链表头部的地址。该双向链表中每个追踪器条目都代表一个被映射到系统页表条目(SysPTE)区域的物理内存块。
这些追踪器条目中的前几个字段(域)包含一些有趣的信息,描述了物理内存及其虚拟地址的映射。函数 MiInsertIoSpaceMap() 也会被 MmMapIoSpace() 例程调用,以跟踪系统上所有的适配器内存映射。

(译注:换言之,MiAddHalIoMappings() 在 FFFFFFFF`FFc00000~FFFFFFFF`FFFFFFF 区域中扫描,并且调用 MiInsertIoSpaceMap() 在 nt!MmIoHeader 指向的 I/O 映射列表中添加追踪器条目,虽然每个条目都包含一个指针,指向的内核虚拟地址空间属于“系统页表条目”区域,但是,nt!MmIoHeader 变量自身,以及它指向的 I/O 映射列表,不一定会在“系统页表条目”区域中)
下面是 I/O 映射列表(即前述的双向链表)中的追踪器条目的内部结构:

[FONT="微软雅黑"][SIZE="4"][COLOR="Black"]dt nt!_EPROCESS  -r 872e1d28 (某个进程的 EPROCESS 结构的虚拟地址)

(。。。省略无关输出。。。)
 +0x054 VmWorkingSetList : 0xc0802000 _MMWSL
    +0x000 FirstFree        : 0x5693
    +0x004 FirstDynamic     : 6
    +0x008 LastEntry        : 0x5970
    +0x00c NextSlot         : 6
    +0x010 Wsle             : 0xc0802d08 _MMWSLE

dt nt!_EPROCESS  -r
(。。。省略无关输出。。。)
  +0x054 VmWorkingSetList : Ptr32 _MMWSL
     +0x000 FirstFree        : Uint4B
     +0x004 FirstDynamic     : Uint4B
     +0x008 LastEntry        : Uint4B
     +0x00c NextSlot         : Uint4B
     +0x010 Wsle             : Ptr32 _MMWSLE
[/COLOR][/SIZE][/FONT]
[FONT="微软雅黑"][SIZE="4"][COLOR="Black"][B]struct _IO_SPACE_MAPPING_TRACKER {
    LIST_ENTRY Link;
    PHYSICAL_ADDRESS  Pfn;
    ULONGLONG  Pages;
    PVOID Va;
    . . . 
}[/B][/COLOR][/SIZE][/FONT]
[FONT="微软雅黑"][SIZE="4"][COLOR="Black"]typedef struct _MMIO_TRACKER {
    LIST_ENTRY ListEntry;			
[B]    PVOID BaseVa;				//此成员存储的虚拟地址位于“系统PTE”区域内
    PFN_NUMBER PageFrameIndex;		// 虚拟地址映射的物理页框号
    PFN_NUMBER NumberOfPages;		// 追踪器条目使用的物理页面数量[/B]
    MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
    PVOID StackTrace[MI_IO_BACKTRACE_LENGTH];
} MMIO_TRACKER, *PMMIO_TRACKER;[/COLOR][/SIZE][/FONT]
[FONT="微软雅黑"][SIZE="4"][COLOR="Black"]typedef union _SLIST_HEADER {
	ULONGLONG Alignment;
	struct {
		SLIST_ENTRY Next;	      //32 位
		USHORT Depth;	      //16 位
		USHORT Sequence;	      //16 位
	} DUMMYSTRUCTNAME;
} SLIST_HEADER, *PSLIST_HEADER;[/COLOR][/SIZE][/FONT]
[FONT="微软雅黑"][SIZE="4"][COLOR="Black"]struct { // 8-byte header
	ULONGLONG Depth:16;
	ULONGLONG Sequence:9;
	ULONGLONG NextEntry:39;
} Header8;[/COLOR][/SIZE][/FONT]

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (17)
雪    币: 99
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
支持楼主!! mark
2016-1-3 15:56
0
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
建议图片上传到论坛本地,不要用外链,容易失效。

上传的方法:http://bbs.pediy.com/showpost.php?postid=292659

或直接上传word或PDF文档上来。
2016-1-3 16:05
0
雪    币: 6
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢楼主分享。
2016-1-3 19:13
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
这个是大牛啊
2016-1-3 19:54
0
雪    币: 11079
活跃值: (17607)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼主的这个资料做得非常好啊,支持了
2016-1-3 22:41
0
雪    币: 54
活跃值: (75)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
非常好,mark
2016-1-4 04:27
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
8
.
.
对于需要原书第6版英文版下册 PDF 对照阅读的,这里提供了压缩文件,下载后将5个部分一起解压到相同目录即可:
上传的附件:
2016-1-5 01:41
0
雪    币: 206
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这套书确实不错,如能完整消化,对windows系统理解就比较深刻了。谢谢楼主分享!
2016-1-11 09:09
0
雪    币: 1644
活跃值: (53)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢分享。现在用的多的都是x86_64,  IA64的机器应该很少人用吧。
2016-1-23 23:44
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
11
确实,IA64 架构的最初市场定位就比较“窄”一些,不过呢,Windows Server 2008 R2 也有专用于
安腾处理器的版本,多数是一些高端企业或数据中心才会采购比较昂贵的安腾处理器
2016-1-24 01:52
0
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
高深啊...
2016-5-23 13:57
0
雪    币: 206
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
真的是很精彩的书!
2016-5-27 15:35
0
雪    币: 206
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
最棒的是,还是英汉对照版,象我等英文马马虎虎的人,想看英文也不错哈...
2016-5-27 15:38
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
15
感谢支持,最近在酝酿第四部分译文——x86与x64的虚拟-物理地址转译
2016-5-31 22:56
0
雪    币: 222
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
打包成了PDF,字体有点小,不知道怎么调。
上传的附件:
2018-4-9 13:48
0
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
学习了,谢谢分享
2018-4-11 11:19
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
18
geoh 打包成了PDF,字体有点小,不知道怎么调。
感谢您热心的协助科普!
2018-4-12 20:46
0
游客
登录 | 注册 方可回帖
返回
//