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


12

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

引用维基百科

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

这是我在qemu monitor中找到的:

(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

我不知道该如何处理这些价值观。它看起来不像一个中断描述符表(解引用这些值将得到所有空值)。那我到底在看什么呢?

Answers:


9

无论固件包含什么固件。

在理想的现代系统上,处理器根本不会进入实模式,正如我在SU Q&A题为“ 现代64位Intel芯片PC在引导扇区中运行的模式 ”中所解释的那样,物理记忆的第一个KiB与约翰·迈瑞恩(JohanMyréen)提出的另一个答案无关。但是,许多现代固件(仍然)都具有兼容性支持,这意味着

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

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

受保护模式的系统软件不需要旧的实模式固件API,也不需要在实模式下运行处理器,因此未使用物理内存的前1KiB中的实模式IVT。(记住,v8086保护模式不寻址物理地址00000000及更高版本。它寻址逻辑地址00000000及更高版本,这些地址通过页表进行转换。)在现代EFI系统中,固件将物理内存的内存映射移交给操作系统引导程序,告诉它哪些部分保留给固件以用于其自身的保护模式API,以及哪些部分操作系统可以自由使用并用于其物理内存池。从理论上讲,物理内存的第一页可以在后一类中。

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

[0.000000] efi:mem00:类型= 3,attr = 0xf,范围= [0x0000000000000000-0x0000000000001000)(0MB)
xe用另一个程序以更易于理解的形式解码为:

[#00]类型:EfiBootServicesCode属性:0xF
      物理:0000000000000000-0000000000001000
      病毒值:0000000000000000-0000000000001000

在实践中,第二,Linux明确地忽略了该物理内存范围,即使固件表示可以继续使用它。您会发现,无论是在EFI固件还是非EFI固件上,Linux都有物理内存映射后,都会对其进行修补(在名为的函数中trim_bios_range),从而产生内核日志消息,例如:

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

这并不是要解决现代EFI固件的问题,因为实模式IVT并不是固件API的一部分,而是要解决旧的PC98固件,后者是固件API的一部分,但是固件会报告它(通过该相同的API)作为物理内存,可被操作系统彻底覆盖。

因此,理论上,物理内存范围可以包含任意代码或数据,具体取决于内核内存分配器和按需分页的虚拟内存的瞬时需求;实际上,Linux只是保留了它,因为固件最初是对其进行设置的。

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

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

进一步阅读


不,我是说我写的东西。 英特尔架构软件开发人员手册,第3卷,第20章
§2。– JdeBP,

好吧,现在您已经拥有了,因为它是; 如该部分的第一句话所解释。因此,我怀疑未识别通用缩写“ v8086”是一种颤抖。(-:
JdeBP '18

您需要学习如何阅读定语名词。否则,学习没有蘑菇汤的生活。
JdeBP '18年

7

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

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


这是有道理的。知道那个未使用页面中的剩余内容是什么吗?
rhodeo

在Google搜索中53 ff发现,这实际上很可能是由固件或引导加载程序设置的8086实模式中断向量表。
约翰·迈雷恩(JohanMyréen)

4

转储内存

这是在系统内部转储内存内容的另一种方法,而不必在外部进行:

$ head /dev/mem | hexdump -C
00000000  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
00000010  53 ff 00 f0 53 ff 00 f0  cc e9 00 f0 53 ff 00 f0  |S...S.......S...|
00000020  a5 fe 00 f0 87 e9 00 f0  53 ff 00 f0 46 e7 00 f0  |........S...F...|
00000030  46 e7 00 f0 46 e7 00 f0  57 ef 00 f0 53 ff 00 f0  |F...F...W...S...|
00000040  22 00 00 c0 4d f8 00 f0  41 f8 00 f0 fe e3 00 f0  |"...M...A.......|
00000050  39 e7 00 f0 59 f8 00 f0  2e e8 00 f0 d4 ef 00 f0  |9...Y...........|
00000060  a4 f0 00 f0 f2 e6 00 f0  6e fe 00 f0 53 ff 00 f0  |........n...S...|
00000070  ed ef 00 f0 53 ff 00 f0  c7 ef 00 f0 ed 57 00 c0  |....S........W..|
00000080  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
...
...
000afea0  00 00 00 00 00 00 00 00  aa aa aa 00 aa aa aa 00  |................|
000afeb0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000b0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
000c0000  55 aa 40 e9 62 0a 00 00  00 00 00 00 00 00 00 00  |U.@.b...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

分析

000c0000上方的上部可能与引导加载程序有关。我为什么会怀疑呢?位置上的代码55aah 000c0000通常可以是内存中的标记,用于诸如BIOS来运行辅助引导加载程序的触发器之类的事情。

参考:引导签名-BIOS

  ss#1

但是,鉴于此55aah出现在c0000h-effffh范围内,则此部分更有可能是PNP扩展标头:

参考:BIOS引导规范

3.3具有PnP扩展接头的设备

所有具有选件ROM的IPL设备都必须包含有效的选件ROM头,该头位于系统内存地址C0000h和EFFFFh之间,边界为2k,以55AAh开头。仅当设备具有PnP扩展标头时才可以控制其引导。扩展头的地址位于标准选项ROM头中,偏移量为+ 1Ah,其中包含用于配置设备的重要信息。它还包含指向设备选件ROM(BCV或BEV)中的代码的指针,BIOS将调用该选件从设备引导。有关PnP扩展标题的结构,请参见附录A。具有PnP扩展头的IPL设备有两种引导方式。它必须包含BCV或BEV。

53ff ...

至于开始时的53ffh数据。我不清楚那到底是什么。对其进行进一步研究,可能是BIOS的MBR引导加载移交给Linux内核引导之后,Linux内核在其中写了一些东西。

通常,引导加载程序会将内核加载到内存中,然后跳转到内核。然后,内核将能够回收引导加载程序使用的内存(因为它已经执行了其工作)。但是,可以在引导扇区中包含OS代码,并在OS启动后将其保留在驻留位置。

进一步挖掘,我能够从研究论文中找到这一段:通过/ dev / mem进行恶意代码注入

1个内存设备

/ dev / mem是物理可寻址内存的驱动程序接口。mem和kmem的最初意图是帮助调试内核。我们可以像使用常规字符设备一样使用该设备,使用lseek()选择地址偏移量。kmem设备与之类似,但是在虚拟寻址的情况下提供了内核内存的映像。Xorg服务器利用mem设备访问VESA视频存储器以及位于物理地址0x00000000的BIOS ROM中断向量表(IVT),以在VM86模式下操纵视频模式。DOSEMU还使用它来访问BIOS IVT,以便能够对各种任务(磁盘读取,打印到控制台等)进行BIOS中断。

参考文献

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.