Linux x86:在受保护的内核模式下映射到的实模式地址空间在哪里



在 x86 平台上运行的 Linux 中,在受保护的内核模式下,实模式地址空间映射到哪里?在内核模式下,线程可以直接访问内核地址空间。内核在较低的8MB,页表在某个位置,等等(如此处所述(。但是真正的模式地址空间去哪儿了?可以直接访问吗?例如 BIOS 和 BIOS 插件(见这里(?

(我的x86-fu有点弱。我会添加一些标签,以便其他人可以(希望(纠正我,如果我在任何地方撒谎。

物理地址在实模式和保护模式下是相同的。唯一的区别在于如何从指令中指定的地址(偏移量(获取到物理地址:

  • 在实模式下,物理地址基本上是(segment_reg << 4) + offset

  • 在保护模式下,物理地址为 translate_via_page_table([segment_reg] + offset)

[segment_reg]我的意思是段的基址,在全局或本地描述符表中查找的偏移量为 segment_reg . translate_via_page_table()表示通过分页(如果启用(完成的地址转换。

看这里,似乎BIOS ROM出现在物理地址0x000F0000-0x000FFFFF。若要在保护模式下使用分页获取该内存,必须通过设置正确的页表条目将其映射到虚拟地址空间的某个位置。假设 4 KB 页(通常情况(,映射整个范围应需要 16 ((0xFFFFF-0xF0000+1(/4096( 个条目。

要了解 Linux 内核是如何工作的,您可以研究如何例如 /dev/mem ,它允许读取任意物理地址,被实现。实现在 drivers/char/mem.c 中。

以下命令(例如此答案(将转储内存范围0xC0000-0xFFFFF(这意味着根据上面链接的内存映射,它也包括视频 BIOS(:

$ dd if=/dev/mem bs=1k skip=768 count=256 > bios

1024*768 = 0xC0000,1024*(768+256( - 1 = 0xFFFFF,给出预期的物理内存范围。

稍微

跟踪一下,read_mem()drivers/char/mem.c 调用 xlate_dev_mem_ptr() 中,它在 arch/x86/mm/ioremap.c 中有一个特定于 x86 的实现。如果需要,该函数中的ioremap_cache()调用似乎负责页面中的映射。

请注意,顺便说一下,BIOS 例程在保护模式下不起作用。他们假设 CPU 以实模式运行。

对于 Linux x86 32 位,物理 RAM 的第一896MB映射到从虚拟地址0xC0000000开始的连续虚拟内存块到0xF7FFFFFF。从0xF80000000xFFFFFFFF的虚拟地址动态分配给物理内存的各个部分,因此内核可以将128MB窗口映射到超出896MB限制的物理内存的任何部分。

内核本身在 1MB 及以上的物理地址加载,留下第一个 MB 可用。例如,第一个 MB 用于具有 ISA 设备需要存在的 DMA 缓冲区,因为它们使用 8237 DMA 控制器,该控制器只能映射到此类地址。

因此,从虚拟内存地址读取0xC0000000实际上是从物理地址0x00000000读取(前提是内核已将该页面标记为存在(

最新更新