linux内存管理(一): arm64内核内存布局

1. 内核内存配置

AArch64 Linux通常使用以下配置:

  • 4KB页面, 使用3级或4级转换表,支持39位(512GB)或48位(256TB)的虚拟地址。
  • 64KB页面,使用2级转换表,支持42位(4TB)虚拟地址。

他们的内存布局是一致的。

以内核defconfig默认的4KB page + 4 levels配置为例,LINUX在arm架构上把虚拟地址空间划分为2个空间, 虚拟地址和内核地址, 每个空间最大支持256TB.

		 Start          End         			  Size        Use
 -----------------------------------------------------------------------
 0x0000000000000_0000   0x0000_ffff_ffff_ffff     256TB       user
 0xffff_0000_0000_0000  0xffff_ffff_ffff_ffff     256TB       kernel

2. 内核内存布局的打印

在arm64 4.16的内核之前,内核基本完成内存初始化工作后会打印出内核的内存布局
qemu arm64打印如下:
在这里插入图片描述

这部分打印在mem_init()函数中实现(arch/arm64/mm/init.c)
start_kernel()->mm_init()->mem_init()

#define MLK(b, t) b, t, ((t) - (b)) >> 10
#define MLM(b, t) b, t, ((t) - (b)) >> 20
#define MLG(b, t) b, t, ((t) - (b)) >> 30
#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)

	pr_notice("Virtual kernel memory layout:\n");
#ifdef CONFIG_KASAN
	pr_notice("    kasan   : 0x%16lx - 0x%16lx   (%6ld GB)\n",
		MLG(KASAN_SHADOW_START, KASAN_SHADOW_END));
#endif
	pr_notice("    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n",
		MLM(MODULES_VADDR, MODULES_END));
	pr_notice("    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n",
		MLG(VMALLOC_START, VMALLOC_END));
	pr_notice("      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n",
		MLK_ROUNDUP(_text, _etext));
	pr_notice("    .rodata : 0x%p" " - 0x%p" "   (%6ld KB)\n",
		MLK_ROUNDUP(__start_rodata, __init_begin));
	pr_notice("      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n",
		MLK_ROUNDUP(__init_begin, __init_end));
	pr_notice("      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n",
		MLK_ROUNDUP(_sdata, _edata));
	pr_notice("       .bss : 0x%p" " - 0x%p" "   (%6ld KB)\n",
		MLK_ROUNDUP(__bss_start, __bss_stop));
	pr_notice("    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n",
		MLK(FIXADDR_START, FIXADDR_TOP));
	pr_notice("    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n",
		MLM(PCI_IO_START, PCI_IO_END));
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	pr_notice("    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n",
		MLG(VMEMMAP_START, VMEMMAP_START + VMEMMAP_SIZE));
	pr_notice("              0x%16lx - 0x%16lx   (%6ld MB actual)\n",
		MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()),
		    (unsigned long)virt_to_page(high_memory)));
#endif
	pr_notice("    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n",
		MLM(__phys_to_virt(memblock_start_of_DRAM()),
		    (unsigned long)high_memory));

kasan: KASAN是一个动态检测内存错误的工具, 原理是利用额外的内存标记可用内存的状态. 这部分额外的内存被称作shadow memory(影子区)。KASAN将1/8的内存用作shadow memory。

modules: 128MB的内核模块区域,是内核模块使用的虚拟地址空间

vmalloc: vmalloc函数使用的虚拟地址空间,kernel image也在vmalloc区域,内核镜像的起始地址 = KIMAGE_ADDR + TEXT_OFFSET, TEXT_OFFSET是内存中的内核镜像相对内存起始位置的偏移。
.text: 代码段。 _text是代码段的起始地址,_etext是结束地址, kernel image放在这段位置。
.rodata: read-only-data. 常量区,存放程序中定义为const的全局变量。
.init: 对应大部分模块初始化的数据,初始化结束后就会释放这部分内存。
.data: 数据段。 包含内核大部分已初始化的全局变量。
.bss: 静态内存分配段。 包含所有未初始化或初始化为0的静态全局变量。

fixed: 固定映射区。 在内核的启动过程中,有些模块需要使用虚拟内存并mapping到指定的物理地址上,而且,这些模块也没有办法等待完整的内存管理模块初始化之后再进行地址映射。因此,linux kernel固定分配了一些fixmap的虚拟地址,这些地址有固定的用途,使用该地址的模块在初始化的时候,讲这些固定分配的地址mapping到指定的物理地址上去。(Fix-Mapped Addresses

PCI I/O: pci设备的I/O地址空间

vmemmap: 内存的物理地址如果不连续的话,就会存在内存空洞(稀疏内存),vmemmap就用来存放稀疏内存的page结构体的数据的虚拟地址空间。

memory: 线性映射区,范围是【0xffff_8000_0000_0000, 0xffff_ffff_ffff_ffff】, 一共有128TB, 但这里代码对应的是memblock_start_of_DRAM()和memblock_end_of_DRAM()函数。
memory根据实际物理内存大小做了限制,所以memroy显示了实际能够访问的内存区。

MLM(__phys_to_virt(memblock_start_of_DRAM()), (unsigned long)high_memory))
high_memory = __va(memblock_end_of_DRAM() - 1) + 1;

最终是通过dts或acpi中配置的memory节点确定的。


后面的内核版本删掉了这段打印,如果需要的话可以手动revert掉该补丁。
在这里插入图片描述

3. 内核内存布局图

根据arm64启动的打印信息, 确定arm64 内核内存布局图:
在这里插入图片描述

4. 参考资料:

Memory Layout on AArch64 Linux
Fix-Mapped Addresses

  • 10
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 将ARM Linux移植到特定硬件平台,通常需要进行一系列的步骤和操作。这些步骤可以大致概括为以下几点: 1. 了解目标硬件平台:首先,需要对目标硬件平台的体系结构和特性进行深入了解,包括处理器架构、内存布局、外设接口等方面的信息。这将有助于确定移植过程中需要考虑的关键问题。 2. 配置交叉编译环境:ARM Linux移植需要使用交叉编译器,以便在x86主机上编译适用于ARM架构的代码。需要下载和配置适当的交叉编译工具链。 3. 配置内核选项:根据目标硬件平台的特点,配置Linux内核选项。这包括选择适当的处理器类型、内存大小、设备驱动程序以及特定于硬件平台的选项。可以使用make menuconfig命令来进行交互式配置。 4. 在目标硬件上烧写内核:根据目标硬件平台的启动方式(例如使用SD卡、NAND闪存等),将编译好的内核映像烧录到目标硬件设备上。 5. 移植Bootloader:在启动过程中,Bootloader负责加载内核到RAM中并开始执行。根据目标硬件平台的要求,需要选择、配置并编译适当的Bootloader。 6. 配置设备树:设备树描述了目标硬件平台上的硬件组成和配置信息。需要根据目标硬件平台的要求,编写和配置设备树文件,以确保内核正确地识别和配置硬件设备。 7. 调试和修复:在将ARM Linux移植到目标硬件平台后,可能会出现一些问题,例如驱动不兼容、硬件设备无法正常工作等。需要使用调试工具和方法,逐步定位和解决问题。 总之,ARM Linux移植是一个相对复杂的过程,需要深入了解目标硬件平台,并进行一系列的配置和操作。通过认真分析和调试,最终可以使ARM Linux在目标硬件平台上正常运行。 ### 回答2: arm linux 移植是将 Linux 操作系统移植到 ARM 架构的硬件平台上的过程。ARM 是一种低功耗、高性能的处理器架构,广泛应用于移动设备、嵌入式系统和物联网等领域。移植 Linux 到 ARM 平台可以提供强大的操作系统功能和广泛的软件支持。 在进行 ARM Linux 移植时,首先需要了解目标硬件平台的 CPU 架构、内存布局和硬件接口等信息。然后,在原有的 Linux 内核代码基础上,根据目标硬件平台的特点和要求,对内核进行配置和修改,以适配 ARM 架构。这包括选择合适的内核配置选项、编译内核并生成合适的启动映像(例如 uImage),以及配置和编译设备驱动程序等。 接下来,需要处理 bootloader 的问题。ARM 平台上常用的 bootloader 包括 U-Boot、GRUB 等,通过它们可以完成启动内核的过程。对于移植工作,需要根据实际情况对 bootloader 进行相关配置,确保能够正确加载和启动内核。 另外,还需要进行文件系统的适配。由于 ARM 平台与 x86 平台在字节序、文件系统支持等方面存在差异,需要将文件系统适配为适合 ARM 架构的版本。常见的文件系统包括 ext4、UBIFS、JFFS2 等,需要在移植过程中选择和配置合适的文件系统。 在进行 ARM Linux 移植时,还需要处理各种设备驱动程序的适配问题。ARM 平台上的设备种类繁多,如显示器、触摸屏、网卡、声卡等,需要针对具体的硬件平台编写或适配相应的设备驱动程序,使其能够在 ARM Linux 中正常工作。 综上所述,ARM Linux 移植是一项复杂的工作,需要深入了解 ARM 架构、Linux 内核和目标硬件平台的特点,通过适配内核、bootloader、文件系统和设备驱动程序等,使 Linux 能够在 ARM 平台上稳定运行,并发挥其强大的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值