ARMv8 Uboot支持MMU和Cache说明

本文详细介绍了Uboot在ARMv8平台上支持MMU和Cache的情况,以及它们对内核解压性能的影响。通过分析,发现未开启Cache导致解压耗时过长。在启用Dcache后,解压性能显著提升。文章还探讨了Uboot中MMU的页表转换机制,并解释了为何选择使用块描述符而非表描述符。
摘要由CSDN通过智能技术生成

ARMv8 Uboot支持MMU和Cache说明

1. 背景介绍

由于Uboot是第一次在我司平台方案上支持,因此存在很多不完善的地方,在启动过程中,客户反馈Uboot在内核解压(gzip压缩内核)这一块耗时过长,影响系统开机时间,需要澄清内核解压耗时原因和解决这个问题。

针对这个问题,由于我司没有硬件解压IP,因此解压都是靠CPU进行软解的,因此主要排查方向存在以下几点:

  1. CPU主频以及相关访问DDR的总线频率、DDR频率。

  2. CPU Cache,特别是Dcache。

经过排查和确认,上述第一点是没有问题的,那主要原因就是cache导致的了,排查代码,发现是uboot阶段没有支持cache特性,因此在uboot阶段支持cache,在进行对比实验,确认相关信息。

Uboot版本:uboot-2021.04-y

2. Uboot支持MMU和Cache

2.1 MMU和Cache关系

2.1.1 MMU介绍

MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权,多用户多进程操作系统。
其功能主要有:

  1. 完成虚拟地址到物理地址的转化
  2. 对相应的地址空间的访问权限控制
  3. 与操作系统的内存管理程序一起协作对内存进行管理

Uboot主要使用了上述第1、2点功能

2.1.2 Cache介绍

Cache是处理器内部的一个高速缓存单元,为了应对处理器和外部存储设备的速度不匹配而设立的,其速度比内存的读写速度要快好多,接近处理器的工作速度,一般处理器从内存中读取数据到cache中,到下次再用到数据时,会先去cache中查找,如果cache中存在的话就不会去访问内存了,用以提高系统性能。一般在各个阶段跳转前,都需要把MMU和Dcache关闭,以免发生不可预料的错误。如preloader跳转bootloader, bootloader跳转kernel等。

Cache分Dcache和Icache两种,在ARM体系架构中,Icache不需要MMU支持,但Dcache需要依赖MMU支持,因此开Dcache需要把MMU打开。

2.2 Uboot MMU的使用

2.2.1 ARM mmu页表翻译介绍

页表翻译,就是指将一个虚拟地址通过查找页表信息,转换成对应的物理地址,这个任务主要是mmu完成的,但mmu完成该项工作,需要我们配置有些相关ARM system相关寄存器才可以,本小节主要结合我司方案Uboot实际使用情况介绍mmu页表转换过程。

ARM64架构下,把页表称为转换表(translation table),最多支持5级,如下所示:

在这里插入图片描述
但实际情况,我们都是使用了4级,因为uboot和内核目前配置的最大虚拟地址都是48bit的,且没有支持large page特性,因此Minus one代表那一级没有使用到。

ARM64架构,支持页长度为4KB、16KB、64KB。

页长度和虚拟地址宽度决定了页转换表的级数,如下图所示:
在这里插入图片描述
ARM64架构下,把转换表的表项称为描述符,使用64bit位长描述符格式(即表项占用8Byte),描述符格式如下图所示:
在这里插入图片描述
从图可以看出,描述符可以表示块描述符(Block)或者表描述符(table),各级转换表中描述符说明如下:

  1. 第0级转换表中,只有表描述符,存放着下一级转换表所在的地址

  2. 块描述符只会出现在第1、2级转换表中,块描述符存放一个内存块的起始地址

  3. 表描述符可以存在第1、2级转换表中,表描述符和块描述符靠BIT1来进行区分,BIT1为1,表示表描述符,BIT1为0,则是块描述符

  4. 在第3级转换中,只存在页描述符

  5. 当BIT0为0时,表示无效描述符,表示该描述符是无效的

  6. 块描述符和页描述符,除了确定对应描述内存的基地址信息外,还有描述了该块内存信息的属性信息,如读写、执行、安全访问等,具体可以看ARM手册了解

描述符格式说明如下图所示(虚拟地址宽度<48Bit情况下):

  1. 无效描述符格式
    在这里插入图片描述
  2. 块描述符格式
    在这里插入图片描述
  3. 表描述符格式
    在这里插入图片描述
    总结如下图所示:
    在这里插入图片描述

2.2.2 ARM MMU在Uboot的相关信息

ARMv8在uboot下,我司的方案是使用了ARM64模式,因此最大寻址范围是2^64Byte,理论上虚拟地址宽度最大可以到64bit,但由于很多方案并不需要这么大的虚拟地址范围,且也没有这么大的物理内存需求,因此也支持其他的虚拟地址宽度,如下图所示:
在这里插入图片描述
在uboot中,根据memmap信息,会自动确认虚拟地址宽度,具体函数如下:

//arch/arm/cpu/armv8/cache_v8.c
u64 get_tcr(int el, u64 *pips, u64 *pva_bits)
{
	u64 max_addr = 0;
	u64 ips, va_bits;
	u64 tcr;
	int i;

	/* Find the largest address we need to support */
	for (i = 0; mem_map[i].size || mem_map[i].attrs; i++)
		max_addr = max(max_addr, mem_map[i].virt + mem_map[i].size);

	/* Calculate the maximum physical (and thus virtual) address */
	if (max_addr > (1ULL << 44)) {
		ips = 5;
		va_bits = 48;
	} else  if (max_addr > (1ULL << 42)) {
		ips = 4;
		va_bits = 44;
	} else  if (max_addr > (1ULL << 40)) {
		ips = 3;
		va_bits = 42;
	} else  if (max_addr > (1ULL << 36)) {
		ips = 2;
		va_bits = 40;
	} else  if (max_addr > (1ULL << 32)) {
		ips = 1;
		va_bits = 36;
	} else {
		ips = 0;
		va_bits = 32;
	}

	if (el == 1) {
		tcr = TCR_EL1_RSVD | (ips << 32) | TCR_EPD1_DISABLE;
	} else if (el == 2) {
		tcr = TCR_EL2_RSVD | (ips << 16);
	} else {
		tcr = TCR_EL3_RSVD | (ips << 16);
	}

	/* PTWs cacheable, inner/outer WBWA and inner shareable */
	tcr |= TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA;
	tcr |= TCR_T0SZ(va_bits);

	if (pips)
		*pips = ips;
	if (pva_bits)
		*pva_bits = va_bits;

	return tcr;
}

从上述代码可知,uboot支持最大的寻址访问为2^48 Byte,虚拟地址宽度最大支持48bit,Uboot支持的页长度为4KB。

由于我司在uboot的memmap如下所示:

static struct mm_region g12a_mem_map[] = {
	{
		/* RAM */
		.virt = 0x40000000UL,
		.phys = 0x40000000UL,
		.size = 0xC0000000UL,	/* 3GB */
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
			 PTE_BLOCK_INNER_SHARE
	}, {
		/* IO SPACE */
		.virt = 0x30000000UL,
		.phys = 0x30000000UL,
		.size = 0x10000000UL,	/* 256MB */
		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
			 PTE_BLOCK_NON_SHARE |
			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
	}, {
		/* List terminator */
		0,
	}
};

struct mm_region *mem_map = g12a_mem_map;

因此在我司方案上,uboot目前使用的虚拟地址有效位宽为32bit(随着映射内存的增大而改变)。

Uboot支持mmu大概流程:

_main
	board_init_f
		setup_dest_addr
		arch_reserve_mmu
		...
	board_init_r
		initr_caches
			enable_caches
				icache_enable
				dcache_enable
					mmu_setup
		...

Uboot地址翻译过程如下:
在这里插入图片描述
log信息

U-Boot 2021.04-gdd07439d-dirty (Dec 10 2021 - 09:40:25 +0800) d9_ref

Model: Semidrive kunlun D9 REF Board
DRAM:dd  reserve_round_4k
TLB table from 13fff0000 to 13fff8000				//TTBL0基地址:13fff0000
reserve_uboot
Reserving 32832k for malloc() at: 13df3f000
3.9 GiB
setup_reloc
Relocation Offset is: df94f000
Relocating to 13ff4f000, new gd at 13df3edd0, sp at 13df1bc40
board_init_r
initr_trace

从虚拟地址,获取到第一级转换表的index为1,可以拿到一级转换表的表项(描述符)为:0x4000711,如下所示:

=> md 000000013fff0008
13fff0008: 40000711 00000000 80000711 00000000    ...@............
13fff0018: c0000711 00000000 00000711 00000001    ................
13fff0028: 00000000 00000000 00000000 00000000    ................
13fff0038: 00000000 00000000 00000000 00000000    ................
13fff0048: 00000000 00000000 00000000 00000000    ................

从该描述符可以确认是块描述符,根据块描述符的含义,可以确认块描述符描述的内存基地址为0x40000000;再从虚拟地址的bit0-bit29获取物理地址的偏移,可以翻译出对应的虚拟地址:0x606023d8。

疑问:

为什么uboot需要使用块描述符而不使用表描述符?

个人见解如下:

  1. Uboot不需要像OS那样,需要对内存进行精细化管理

  2. 使用块描述符映射相对简单

3.性能对比

在打开cache后,解压的性能测试如下:

MMC read: dev # 0, block # 40, count 49152 ... 49152 blocks read: OK
## Loading kernel from FIT Image at 5e000000 ...
   Using 'conf@2' configuration
   Trying 'kernel' kernel subimage
     Description:  scmap1_ref Linux kernel
     Type:         Kernel Image
     Compression:  gzip compressed
     Data Start:   0x5e0000e8
     Data Size:    9604718 Bytes = 9.2 MiB
     Architecture: AArch64
     OS:           Linux
     Load Address: 0x5c480000
     Entry Point:  0x5c480000
     Hash algo:    crc32
     Hash value:   d9dd977c
     Hash algo:    sha1
     Hash value:   424e0624a9c5f846db303640147f2ef6a66cb291
   Verifying Hash Integrity ... crc32+ sha1+ OK
## Flattened Device Tree blob at 47400000
   Booting using the fdt blob at 0x47400000
   Uncompressing Kernel Image
   take time:345 ms

而关闭cache,解压性能如下:

MMC read: dev # 0, block # 40, count 49152 ... 49152 blocks read: OK
## Loading kernel from FIT Image at 5e000000 ...
   Using 'conf@2' configuration
   Trying 'kernel' kernel subimage
     Description:  scmap1_ref Linux kernel
     Type:         Kernel Image
     Compression:  gzip compressed
     Data Start:   0x5e0000e8
     Data Size:    9604718 Bytes = 9.2 MiB
     Architecture: AArch64
     OS:           Linux
     Load Address: 0x5c480000
     Entry Point:  0x5c480000
     Hash algo:    crc32
     Hash value:   d9dd977c
     Hash algo:    sha1
     Hash value:   424e0624a9c5f846db303640147f2ef6a66cb291
   Verifying Hash Integrity ... crc32+ sha1+ OK
## Flattened Device Tree blob at 47400000
   Booting using the fdt blob at 0x47400000
   Uncompressing Kernel Image
   take time:19246 ms

可以看出,打开Dcache后,对解压性能有巨大的影响。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值