x86 Linux 中的物理地址 0 包含什么?

rho*_*deo 12 memory x86

我不确定这个问题应该在这里还是在reverseengineering.stackexchange.com 中

引自维基百科

在8086处理器中,中断表称为IVT(interrupt vector table)。IVT 始终驻留在内存中的同一位置,范围从 0x0000 到 0x03ff,由 256 个四字节实模式远指针(256 × 4 = 1024 字节内存)组成。

这是我在 qemu 监视器中发现的:

(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
Run Code Online (Sandbox Code Playgroud)

我不确定如何看待这些价值观。它看起来不像中断描述符表(取消引用这些值会给出所有空值)。那么我到底在看什么?

Jde*_*eBP 9

无论您的固件包含什么。

在理想的现代系统上,处理器根本不会进入实模式,正如我在题为“现代 64 位 Intel 芯片 PC 以何种模式运行引导扇区的SU 问答”中所解释的那样,物理内存的第一个 KiB 与 Johan Myréen 在此处的另一个答案中指出的一样无关紧要。但是许多现代固件(仍然)具有兼容性支持,这意味着

  • 它们可以从保护模式退回(是的,退回,因为它们直接从非实模式到保护模式)从保护模式到实模式,以便运行为实模式编写的系统软件,例如旧式 PC/AT 启动程序MBR 和 VBR;和
  • 它们提供旧的实模式固件 API,并为上述系统软件所依赖的这些 API 设置所有数据结构。

这些数据结构之一是实模式IVT。旧的实模式固件 API 基于int指令,实模式 IVT 由固件填充,作为其初始化的一部分,带有指向这些指令的各种固件处理例程的指针。

保护模式系统软件不需要旧的实模式固件 API,并且永远不会在实模式下运行处理器,因此物理内存的前 1KiB 中的实模式 IVT 未被使用。(v8086 保护模式不寻址物理地址 00000000 及以上,记住。它寻址逻辑地址 00000000 及以上,由页表转换。)在现代 EFI 系统中,固件将物理内存的内存映射移交给操作系统bootstrap,告诉它哪些部分保留给固件用于其自身的保护模式 API 目的,以及操作系统可以自由使用哪些部分用于其物理内存池。理论上,物理内存的第一页可以属于后一类。

在实践中,首先,固件通常将物理内存的第一页标记为“引导服务代码”,这意味着操作系统可以声明它并继续使用它作为其物理内存池的一部分,但只有在引导之后—— EFI 固件的时间服务已被操作系统关闭,固件减少为仅提供其运行时服务。在add_efi_memmapFinnbarr P. Murphy 显示的 Linux 内核日志(带有选项)中可以看到一个例子:

[ 0.000000] efi: mem00: type=3, attr=0xf, range=[0x0000000000000000-0x0000000000001000) (0MB)
其中 xe 以更易读的形式与另一个程序解码为:

[#00] 类型:EfiBootServicesCode Attr:0xF
      物理:0000000000000000-0000000000001000
      虚拟:0000000000000000-0000000000001000

在实践中,其次,即使固件说它可以继续使用它,Linux也会明确忽略这个物理内存范围。您会发现,在 EFI 和非 EFI 固件上,一旦 Linux 拥有物理内存映射,它就会对其进行修补(在名为 的函数中trim_bios_range),从而导致内核日志消息,例如:

[ 0.000000] e820:更新 [mem 0x00000000-0x00000fff] 可用 ==> 保留

这不是为了应付现代 EFI 固件,其中实模式 IVT 不是固件 API 的一部分,而是为了应付旧的 PC98 固件,它是固件 API 的一部分,但固件报告它(通过相同的 API)作为可用的物理内存,可以被操作系统轻松覆盖。

因此,虽然理论上物理内存范围可以包含任意代码或数据,这取决于内核内存分配器和按需分页虚拟内存的瞬时需求;在实践中,Linux 只是保持不变,因为固件最初设置了它。

在您的系统上,固件已使用实模式 IVT 条目填充它。当然,实模式 IVT 条目只是 16:16 的远指针,如果您使用 2 字节的十六进制转储查看您的内存,您实际上可以非常清楚地看到这一点。一些例子:

  • 大多数 IVT 条目都指向 F000:FF53,这是实模式固件 ROM 区域中的一个地址。它可能是一个虚拟例程,只做一个iret.
  • IVT 条目 1E指向 F000:6AA4,即同一 ROM 区域中的一个表。
  • IVT 条目 1F指向 C000:8930,这是实模式视频 ROM 固件区域中的一个表。
  • IVT 条目 43指向 C000:6730,这是实模式视频 ROM 固件区域中的另一个表。

进一步阅读


Joh*_*éen 7

最初的 8086 处理器架构(在 80286+ 处理器中实现为实模式)与在保护模式下运行的 Linux 无关。物理地址 0 处没有中断向量表,而是使用包含中断描述符的中断描述符表。IDT 可以位于内存中的任何位置。

Linux 内核从固件(BIOS 或 EFI)获取物理内存映射,该映射指示哪些物理内存页帧可用,哪些是保留的或不存在的。可用页框的范围不是连续的,但通常有很大的漏洞。传统上,x86 Linux 内核会跳过物理内存的开始,即使它被标记为可用。因此,Linux 内核不使用物理地址 0。