dmesg 中的虚拟内核内存布局意味着什么?

Sen*_*Sen 20 linux kernel memory

在浏览“dmesg 输出”时,我可以看到一个我无法正确理解的值列表。

Memory: 2047804k/2086248k available (3179k kernel code, 37232k reserved, 1935k data, 436k init, 1176944k highmem)
virtual kernel memory layout:
    fixmap  : 0xffc57000 - 0xfffff000   (3744 kB)
    pkmap   : 0xff800000 - 0xffa00000   (2048 kB)
    vmalloc : 0xf7ffe000 - 0xff7fe000   ( 120 MB)
    lowmem  : 0xc0000000 - 0xf77fe000   ( 887 MB)
      .init : 0xc0906000 - 0xc0973000   ( 436 kB)
      .data : 0xc071ae6a - 0xc08feb78   (1935 kB)
      .text : 0xc0400000 - 0xc071ae6a   (3179 kB)
Run Code Online (Sandbox Code Playgroud)

从值中我了解到我有 2GB RAM(物理内存)。但其余的事情对我来说似乎是魔术数字。

我想简要了解每个(fixmap、pkmap 等)(如果有更多疑问,我会将每个作为单独的问题发布)?

有人可以向我解释一下吗?

wag*_*wag 23

首先,32 位系统具有0xffffffff( 4'294'967'295) 线性地址来访问 RAM 上的物理位置。
内核将这些地址划分为用户空间和内核空间。

用户空间(高端内存)可以被用户访问,必要时也可以被内核访问。
十六进制和十进制表示法的地址范围:

0x00000000 - 0xbfffffff
0 - 3'221'225'471
Run Code Online (Sandbox Code Playgroud)

内核空间(低内存)只能由内核访问。
十六进制和十进制表示法的地址范围:

0xc0000000 - 0xffffffff
3'221'225'472 - 4'294'967'295
Run Code Online (Sandbox Code Playgroud)

像这样:

0x00000000             0xc0000000  0xffffffff 
    |                        |          |
    +------------------------+----------+
    |  User                  |  Kernel  |
    |  space                 |  space   |
    +------------------------+----------+
Run Code Online (Sandbox Code Playgroud)

因此,您看到的内存布局dmesg对应于内核空间中线性地址的映射。

首先是 .text、.data 和 .init 序列,它们提供内核自己的页表的初始化(将线性转换为物理地址)。

.text : 0xc0400000 - 0xc071ae6a   (3179 kB)
Run Code Online (Sandbox Code Playgroud)

内核代码所在的范围。

.data : 0xc071ae6a - 0xc08feb78   (1935 kB)
Run Code Online (Sandbox Code Playgroud)

内核数据段所在的范围。

.init : 0xc0906000 - 0xc0973000   ( 436 kB)
Run Code Online (Sandbox Code Playgroud)

内核初始页表所在的范围。

(对于某些动态数据结构,还有另外 128 kB。)

这个最小的地址空间刚好足以在 RAM 中安装内核并初始化其核心数据结构。

它们使用的大小显示在括号内,以内核代码为例:

0xc071ae6a - 0xc0400000 = 31AE6A
Run Code Online (Sandbox Code Playgroud)

以十进制表示法,即3'255'914(3179 kB)。


二、初始化后内核空间的使用情况

lowmem  : 0xc0000000 - 0xf77fe000   ( 887 MB)
Run Code Online (Sandbox Code Playgroud)

内核可以使用 lowmem 范围直接访问物理地址。
这不是完整的 1 GB,因为内核总是需要至少 128 MB 的线性地址来实现非连续内存分配和固定映射线性地址。

vmalloc : 0xf7ffe000 - 0xff7fe000   ( 120 MB)
Run Code Online (Sandbox Code Playgroud)

虚拟内存分配可以基于非连续方案分配页框。这种模式的主要优点是避免外部碎片,这用于交换区域、内核模块或向某些 I/O 设备分配缓冲区。

pkmap   : 0xff800000 - 0xffa00000   (2048 kB)
Run Code Online (Sandbox Code Playgroud)

永久内核映射允许内核建立高内存页帧到内核地址空间的持久映射。当使用 kmap() 映射 HIGHMEM 页时,将从此处分配虚拟地址。

fixmap  : 0xffc57000 - 0xfffff000   (3744 kB)
Run Code Online (Sandbox Code Playgroud)

这些是固定映射的线性地址,可以引用 RAM 中的任何物理地址,而不仅仅是像 lowmem 地址那样的最后 1 GB。Fix-mapped 线性地址比他们的 lowmem 和 pkmap 同事更有效。为固定映射分配了专用的页表描述符,使用 kmap_atomic 的 HIGHMEM 页的映射从这里分配。


如果你想更深入地研究这个兔子洞:
了解 Linux 内核