-
-
[原创]物理地址、线性地址、逻辑地址之我见
-
发表于: 2021-6-26 17:31 11166
-
闲来无事,翻看收藏夹的连接,看到了描述这些地址的文章,看完之后总觉得缺少些什么。思之片刻有感,文章中没有给出简单的证实方法。随后百度之……论坛之……,然而,并未找到想要的结果,反而,产生了新的疑问。在众多文章中对于这些地址的概念描述差异不大,但是,对于范围大小的描述却各有千秋。这在……让我懵逼的同时,也牵动了我较真的神经!因此,本文试图解决以下几个问题:
本节虽名为前言,实则是发帖时才写的。下面的内容原本应为笔记,但独享不如分享!如有谬误,还望海涵,且请!多多指正。
文中内容以 Intel CPU 和 Windows 系统为例。
Physical address: CPU 可访问的地址空间(如 8086 可访问 20 Bits 地址空间)。物理空间的范围为 36 ≤ MAXPHYADDR ≤ 52 Bits(64 GBytes ~ 4 PBytes),MAXPHYADDR 的值由 CPUID.80000008H:EAX[7:0] 查询。(Pentium Pro 之前皆为 32 Bits)。
Linear address: 有时也称 Virtual address。Linear address 是 Physical address 与 Logical address 的中间层,或称隔离层(保护模式隔离用户和资源……个人理解)。空间的范围为 32/48 Bits(4 GBytes/256 TBytes),具体由 CPUID.80000008H:EAX[15:8] 查询(如果 CPUID.80000001H:EDX.LM [29] = 1 则为 48 Bits,否则为 32 Bits。不支持此查询的 CPU 皆为 32 Bits)。
Logical address: 程序代码中使用的地址,在不同的编程环境中略有差异,实则已被削弱(见后文)。
在 Intel 的文档中,同为 6 系列的 CPU 中 MAXPHYADDR 值不同。
物理地址中映射的是什么?答案是各种外部设备。一些地方将物理地址称为内存地址,个人认为亦对亦错,对的原因是 CPU 操作内存最为快捷(似乎也只能操作内存),而物理地址是为了让 CPU 将各种设备都视为内存。错的原因是物理地址中可以映射内存(条),但不局限于此!Intel 的 CPU 有两种物理空间:
Memory: 前面描述的大小为 MAXPHYADDR 的物理空间,这个空间中映射了各种外部设备:显卡、声卡、网卡、SATA、USB、APIC 等等。
I/O Ports: 独立编址的空间,仅有 64 KBytes(0 ~ 0xFFFF),此空间映射的也是各种外部设备。可通过 in/out 指令访问。0 ~ 255 的端口号使用立即数表示,超过 255 的端口号使用 dx 寄存器表示,存取的数据置于 eax/ax/al 中。
Windows 设备管理器按类型列出资源,其中的[内存]和[输入/输出(I/O)]项,即上述两种物理空间所映射的设备。在 x64 Windows 10 的[内存]项中,物理地址的值范围在 2^32 以内,这也许是设备厂商出于向下(x86)兼容的考虑。
做些简单的测试:
x86/x64 CPU 支持 32/64 Bits 寄存器寻址(4 GBytes ~ 16 EBytes),前者(x86)不会有任何问题,因为线性地址范围最小支持 32 Bits(当然也兼容更古老的 CPU)。然而,后者(x64)却引发了问题:CPU 仅支持 48 Bits 线性地址,因此,厂商规定线性地址的高 16 Bits 被作为符号扩展(0x0000... 或 0xFFFF...),这样的线性地址称为 canonical 地址;反之视为 non-canonical 地址(如高 16 Bits 的 0x0001... 或 0xFFF0... 等等),使用 non-canonical 地址将引发异常(Intel 手册描述)。
CPU 线性地址布局:
合法线性地址的 Bit 47 必须和 Bit 48 ~ 63 一致,否则为非法地址。若以后需要更大的空间,只需将符号位上移。
从 x64 Windows 8.1 及其之后的版本线性地址支持 256 TBytes,这与 CPU 描述的线性地址吻合。而之前的版本仅支持 16 TBytes 线性地址(微软描述,实测为 248 TBytes)。
可以通过 windbg 的 !address 命令枚举线性地址布局,还可以使用 !pte 命令查看线性地址是否 canonical:
x64 Win7:
用户模式线性地址空间是固定大小的:0x800`00000000(因从 0 计数,有效地址要 - 1) = 8 TBytes。未知区域(unknown)大小 = 0x7800`00000000 = 120 TBytes。
内核模式从高到低对地址进行布局:HAL - PageTables + 1 = 0xFFFFFFFF`FFFFFFFF - 0xFFFFF680`00000000 + 1 = 0x980`00000000 = 9.5 TBytes。
从上向下数第一块 SystemRange 的 0xFFFF0800`00000000 和 0xFFFF8000`00000000 - 1 这两个地址都是 non-canonical,但如果将这两个地址的高 16 Bits 清零,则与 unknown 吻合(应该是微软将用户模式没有使用的 120 TBytes 归为内核了)。
第二块 SystemRange 的大小 = 118.5 TBytes(128 - 9.5)。综上内核模式共占 248 TBytes(0xFFFFFFFF`FFFFFFFF - 0xFFFF0800`00000000 + 1)。
x64 Win10:
标准的 canonical 地址,用户与内核模式各占 128 TBytes。(SystemRange 块的 EndAddress 的值是随机的……不明所以)。
实模式,或保护模式分段下,线性地址就是物理地址;保护模式分页下,线性地址转物理地址涉及 32/48 Bits 的两种分页模式,论坛中有其他文章介绍,因此,就不赘言了。
言不如表;表不如图。下图截取自 Intel 手册,图中绘出了逻辑地址到线性地址的转换过程。从图中大致可以将逻辑地址归纳为 'Segment:Offset' 形式,通常 Segment 是隐式的。而现今的编程环境基本皆为 Flat Model,也就是说逻辑地址已经被削弱,取而代之的是线性地址,至少 c/c++ 中指针使用线性地址。
Memory Limits for Windows and Windows Server Releases
mov eax,
0x80000008
cpuid
; Intel I7
6850K
:
; Linear address space : ah
=
48
Bits(支持
256
TBytes)
; Phyiscal address space: al
=
46
Bits(支持
64
TBytes)
=
MAXPHYADDR
mov eax,
0x80000008
cpuid
; Intel I7
6850K
:
; Linear address space : ah
=
48
Bits(支持
256
TBytes)
; Phyiscal address space: al
=
46
Bits(支持
64
TBytes)
=
MAXPHYADDR
SYSTEM_INFO info
=
{};
GetSystemInfo (&info);
/
*
x64 Win7:
info.lpMinimumApplicationAddress
=
0x00000000
`
00010000
info.lpMaximumApplicationAddress
=
0x000007FF
`FFFEFFFF
x64 Win10:
info.lpMinimumApplicationAddress
=
0x00000000
`
00010000
info.lpMaximumApplicationAddress
=
0x00007FFF
`FFFEFFFF
*
/
SYSTEM_INFO info
=
{};
GetSystemInfo (&info);
/
*
x64 Win7:
info.lpMinimumApplicationAddress
=
0x00000000
`
00010000
info.lpMaximumApplicationAddress
=
0x000007FF
`FFFEFFFF
x64 Win10:
info.lpMinimumApplicationAddress
=
0x00000000
`
00010000
info.lpMaximumApplicationAddress
=
0x00007FFF
`FFFEFFFF
*
/
kd>!address
....
BaseAddress EndAddress
+
1
RegionSize VaType
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
0
`
00000000
0
`
00010000
0
`
00010000
UserRange
....
7FF
`FFFF0000
800
`
00000000
0
`
00010000
UserProbeArea
800
`
00000000
8000
`
00000000
7800
`
00000000
<unknown>
8000
`
00000000
FFFF8000`
00000000
FFFF0000`
00000000
NonAddressable
FFFF0800`
00000000
FFFF8000`
00000000
7800
`
00000000
SystemRange
FFFF8000`
00000000
FFFFF680`
00000000
7680
`
00000000
SystemRange
FFFFF680`
00000000
FFFFF700`
00000000
80
`
00000000
PageTables
....
FFFFFFFF`FFC00000 FFFFFFFF`FFFFFFFF
0
`
00400000
HAL
kd>!address
....
BaseAddress EndAddress
+
1
RegionSize VaType
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [原创]分页模式之我见(简述) 4729
- [原创]物理地址、线性地址、逻辑地址之我见 11167
- [原创]Windows(x86)页表与虚拟空间之我见 16466