[mmu/cache]-ARM MMU的学习笔记-一篇就够了

这篇具有很好参考价值的文章主要介绍了[mmu/cache]-ARM MMU的学习笔记-一篇就够了。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

快速链接:
.
👉👉👉 个人博客笔记导读目录(全部) 👈👈👈

  • 付费专栏-付费课程 【购买须知】:
  • 【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈
  • 联系方式-加入交流群 ----联系方式-加入交流群

本文转自 周贺贺,baron,代码改变世界ctw,Arm精选, armv8/armv9,trustzone/tee,secureboot,资深安全架构专家,11年手机安全/SOC底层安全开发经验。擅长trustzone/tee安全产品的设计和开发。

ARMV8-aarch64的MMU

1、MMU概念介绍

MMU分为两个部分: TLB maintenance 和 address translation
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

MMU的作用,主要是完成地址的翻译,无论是main-memory地址(DDR地址),还是IO地址(设备device地址),在开启了MMU的系统中,CPU发起的指令读取、数据读写都是虚拟地址,在ARM Core内部,会先经过MMU将该虚拟地址自动转换成物理地址,然后在将物理地址发送到AXI总线上,完成真正的物理内存、物理设备的读写访问

下图是一个linux kernel系统中宏观的虚拟地址到物理地址转换的视图,可以看出在MMU进行地址转换时,会依赖TTBRx_EL1寄存器指向的一个页表基地址.
其中,TTBR1_EL1指向特权模式的页表基地址,用于特权模式下的地址空间转换;TTBR0_EL0指向非特权模式的页表基地址,用于非特权模式下的地址空间转换.
刚刚我们也提到,CPU发出读写后, MMU会自动的将虚拟地址转换为为例地址,那么我们软件需要做什么呢? 我们软件需要做的其实就是管理这个页表,按照ARM的技术要求去创建一个这样的页表,然后再将其基地址写入到TTBR1_EL1或TTBR0_EL1。当然,根据实际的场景和需要,这个基地址和页表中的内容都会发生动态变化. 例如,两个user进程进行切换时,TTBR0_EL1是要从一个user的页表地址,切换到另外一个user的页表地址。
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

2、MMU地址翻译的过程

using a 64KB granule with a 42-bit virtual address space,地址翻译的过程(只用到一级页表的情况):
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

使用二级页表的情况举例:
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

3、在secure和non-secure中使用MMU

TTBRx_EL1是banked的,在linux和optee双系统的环境下,可同时开启两个系统的MMU.
在secure和non-secure中使用不同的页表.secure的页表可以映射non-secure的内存,而non-secure的页表不能去映射secure的内存,否则在转换时会发生错误
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

4、在不同异常等级中使用MMU

在ARMV8-aarch64架构下,页表基地址寄存器有:

  • TTBR0_EL1 – banked
  • TTBR1_EL1 – banked
  • TTBR1_EL2
  • TTBR1_EL3

在EL0/EL1的系统中,MMU地址转换时,如果虚拟地址在0x00000000_ffffffff - 0x0000ffff_ffffffff范围,MMU会自动使用TTBR0_EL1指向的页表,进行地址转换;如果虚拟地址在0xffff0000_ffffffff - 0xffffffff_ffffffff范围,MMU会自动使用TTBR1_EL1指向的页表,进行地址转换

在EL2系统中,MMU地址转换时,会自动使用TTBR2_EL1指向的页表
在EL3系统中,MMU地址转换时,会自动使用TTBR3_EL1指向的页表

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

5、memory attributes介绍

translation tables为每一块region(entry)都定义了一个memory attributes条目,如同下面这个样子:
TODO:以linux kernel为例,在创建页表的时候,应该会设置这个memory attributes,有待看代码去验证
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
• Unprivileged eXecute Never (UXN) and Privileged eXecute Never (PXN) are execution
permissions.
• AF is the access flag.
• SH is the shareable attribute.
• AP is the access permission.
• NS is the security bit, but only at EL3 and Secure EL1. ---- secure权限配置
• Indx is the index into the MAIR_ELn

在这块region(entry)的memory attributes条目中的BIT4:2(index)指向了系统寄存器MAIR_ELn中的attr,MAIR_ELn共有8中attr选择
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
而每一个attr都有一种配置:
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
有人可能会问,这里的inner和outter是什么意思呢,请参见前面的cache介绍的文章

6、memory tagging介绍
When tagged addressing support is enabled, the top eight bits [63:56] of the virtual address are
ignored by the processor. It internally sets bit [55] to sign-extend the address to 64-bit format. The
top 8 bits can then be used to pass data. These bits are ignored for addressing and translation
faults. The TCR_EL1 has separate enable bits for EL0 and EL1

如果使用memory tagging, 虚拟地址的[63:56]用于传输签名数据,bit[55]表示是否需要签名.TCR_EL1也会有一个bit区分是给EL0用的还是给EL1用的

7、启用hypervisor

(Two Stage Translations)
如果启用了hypervisor那么虚拟地址转换的过程将有VA—>PA变成了VA—>IPA—>PA, 也就是要经过两次转换.在guestos(如linux kernel)中转换的物理地址,其实不是真实的物理地址(假物理地址),然后在EL2通过VTTBR0_EL2基地址的页表转换后的物理地址,才是真实的硬件地址

IPA : intermediate physical address

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

8、Access permissions
Access permissions are controlled through translation table entries. Access permissions control
whether a region is readable or writeable, or both, and can be set separately to EL0 for
unprivileged and access to EL1, EL2, and EL3 for privileged accesses, as shown in the following
table

参考 : SCTLR_EL1.WXN、SCTLR.UWXN

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

执行权限:

  • non-executable (Execute Never (XN))
  • The Unprivileged Execute Never (UXN)
  • Privileged Execute Never (PXN)
9、MMU/cache相关的寄存器总结

MMU(address translation /TLB maintenance)、cache maintenance相关的寄存器

(1)、address translation

address translation 共计14个寄存器
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(2)、TLB maintenance

TLB maintenance数十个寄存器
(以下截取部分)
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(3)、cache maintenance

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(4)、Base system registers

系统寄存器中, 和MMU/Cache相关的寄存器有:

TTBR0_ELx TTBR1_ELx

(aarch64)

  • TTBR0_EL1
  • TTBR0_EL2
  • TTBR0_EL3
  • TTBR1_EL1
  • VTTBR_EL2

(aarch32)

  • TTBR0
  • TTBR1
  • HTTBR
  • VTTBR
TCR_ELx

(aarch64)

  • TCR_EL1
  • TCR_EL2
  • TCR_EL3
  • VTCR_EL2

(aarch32)

  • TTBCR(NS)
  • HTCR
  • TTBCR(S)
  • VTCR
MAIR_ELx
  • MAIR_EL1
  • MAIR_EL2
  • MAIR_EL3
10、系统寄存器 — TCR寄存器介绍

在ARM Core中(aarch64),还有几个相关的系统寄存器:

  • TCR_EL1 banked
  • TCR_EL2
  • TCR_EL3
    [mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
比特位 功能 说明
ORGN1、IRGN1、ORGN0、IRGN0 cache属性** outer/inner cableability的属性(如直写模式、回写模式)
SH1、SH0 cache的共享方式 cache的共享属性配置(如non-shareable, outer/inner shareable)
TG0/TG1 Granule size Granule size(其实就是页面的大小,4k/16k/64k)
IPS 物理地址size 物理地址size,如32bit/36bit/40bit
EPD1、EPD0 - TTBR_EL1/TTBR_EL0的enable和disable
TBI1、TBI0 - top addr是ignore,还是用于MTE的计算
A1 - ASID的选择,是使用TTBR_EL1中的,还是使用TTBR_EL0中的
AS - ASID是使用8bit,还是使用16bit
(1)、T1SZ、T0SZ
  • T1SZ, bits [21:16] 通过TTBR1寻址的内存区域的大小偏移量,也就是TTBR1基地址下的一级页表的大小
  • T0SZ, bits [5:0]
(2)、ORGN1、IRGN1、ORGN0、IRGN0

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
其实可以总结为这样:
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(3)、SH1、SH0

SH1, bits [29:28]
SH0, bits [13:12]
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
其实可以总结为这样:
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
Shareable的很容易理解,就是某个地址的可能被别人使用。我们在定义某个页属性的时候会给出。Non-Shareable就是只有自己使用。当然,定义成Non-Shareable不表示别人不可以用。某个地址A如果在核1上映射成Shareable,核2映射成Non-Shareable,并且两个核通过CCI400相连。那么核1在访问A的时候,总线会去监听核2,而核2访问A的时候,总线直接访问内存,不监听核1。显然这种做法是错误的。

对于Inner和Outer Shareable,有个简单的的理解,就是认为他们都是一个东西。在最近的ARM A系列处理器上上,配置处理器RTL的时候,会选择是不是把inner的传输送到ACE口上。当存在多个处理器簇或者需要双向一致性的GPU时,就需要设成送到ACE端口。这样,内部的操作,无论inner shareable还是outershareable,都会经由CCI广播到别的ACE口上。

(4)、TG0/TG1 - Granule size

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(5)、IPS

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(6)、EPD1、EPD0

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(7)、TBI1、TBI0

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(8)、A1

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

(10)、AS

[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

除了以上介绍的bit之外,剩余的bit都是特有功能使用或reserved的
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

11、代码使用示例展
(1)、设置inner/outer cache的属性(只写模式/回写模式/write allocate/No-write allocate)

如下代码所示:

#define TCR_IRGN_WBWA		((UL(1) << 8) | (UL(1) << 24))   //使用TTBR0和使用TTBR1时后的inner cache的属性设置

#define TCR_ORGN_WBWA		((UL(1) << 10) | (UL(1) << 26))   //使用TTBR0和使用TTBR1时后的outer cache的属性设置

#define TCR_CACHE_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA   // inner + outer cache的属性值


ENTRY(__cpu_setup)
......
	/*
	 * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
	 * both user and kernel.
	 */
	ldr	x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
			TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | TCR_A1
	tcr_set_idmap_t0sz	x10, x9

......
	msr	tcr_el1, x10
	ret					// return to head.S
ENDPROC(__cpu_setup)

属性设置了1,也就是回写模式、write allocate模式
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

optee系统中使用MMU

1、Optee中的TTBR0/TTBR1

我们知道,在linux中将虚拟空间划分为了userspace和kernel space:
例如:
aarch64 :
0x0000_0000_0000_0000 - 0x0000_ffff_ffff_ffff是userspace
0xffff_0000_0000_0000 - 0xffff_ffff_ffff_ffff是kernel space
aarch32 : 0-3G是userspace,3-4G是kernel space

当cpu发起读写内存时,cpu发起的是虚拟地址,如果是kernel地址,那么MMU将自动使用TTBR1做为页表基地址进行转换程物理地址,然后发送到AXI总线,完成真正物理地址的读写;
如果cpu发起的虚拟地址是userspace地址,那么MMU将使用TTBR0做为页表基地址进行转换程物理地址,然后发送到AXI总线,完成真正物理地址的读写;

那么在optee中是怎么样的呢?
在optee中,没用特别的将虚拟地址划分成kernel space和userspace,统一使用0-4G地址空间(无论是aarch32还是aarch64).
在optee初始化时,禁用了TTBR1,所有整个optee的虚拟地址的专业,都是使用TTBR0做为基地址转换成物理地址,发送到AXI总线,完成真正的物理地址读写

void core_init_mmu_regs(void)
{
	uint64_t mair;
	uint64_t tcr;
	paddr_t ttbr0;
	uint64_t ips = calc_physical_addr_size_bits(max_pa);

	ttbr0 = virt_to_phys(l1_xlation_table[0][get_core_pos()]);

	mair  = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
	mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX);
	write_mair_el1(mair);

	tcr = TCR_RES1;
	tcr |= TCR_XRGNX_WBWA << TCR_IRGN0_SHIFT;
	tcr |= TCR_XRGNX_WBWA << TCR_ORGN0_SHIFT;
	tcr |= TCR_SHX_ISH << TCR_SH0_SHIFT;
	tcr |= ips << TCR_EL1_IPS_SHIFT;
	tcr |= 64 - __builtin_ctzl(CFG_LPAE_ADDR_SPACE_SIZE);

	/* Disable the use of TTBR1 */
	tcr |= TCR_EPD1;

	/*
	 * TCR.A1 = 0 => ASID is stored in TTBR0
	 * TCR.AS = 0 => Same ASID size as in Aarch32/ARMv7
	 */

	write_tcr_el1(tcr);
	write_ttbr0_el1(ttbr0);
	write_ttbr1_el1(0);
	}
2、optee中的页表

optee在在内核中使用一个4GB的大页表,在user mode使用多个32M的小页表
注意下面的图来自官网,有点小问题,代码中没用使用到TTBR1,kernel和user都使用TTBR0
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记

3、tee内核页表基地址的配置

将基地址写入到TTBR0

在optee的start函数和cpu_on_handler函数中,都会调用core_init_mmu_regs()

FUNC _start , :
......
	bl	core_init_mmu_regs

FUNC cpu_on_handler , :
......
	bl	core_init_mmu_regs

在core_init_mmu_regs中,获取当前cpu的页表基地址,写入到ttbr0寄存器中

void core_init_mmu_regs(void)
{
	uint64_t mair;
	uint64_t tcr;
	paddr_t ttbr0;
	uint64_t ips = calc_physical_addr_size_bits(max_pa);

	ttbr0 = virt_to_phys(l1_xlation_table[0][get_core_pos()]);  //获取当前cpu的页表基地址

	mair  = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
	mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX);
	write_mair_el1(mair);

	tcr = TCR_RES1;
	tcr |= TCR_XRGNX_WBWA << TCR_IRGN0_SHIFT;
	tcr |= TCR_XRGNX_WBWA << TCR_ORGN0_SHIFT;
	tcr |= TCR_SHX_ISH << TCR_SH0_SHIFT;
	tcr |= ips << TCR_EL1_IPS_SHIFT;
	tcr |= 64 - __builtin_ctzl(CFG_LPAE_ADDR_SPACE_SIZE);

	/* Disable the use of TTBR1 */
	tcr |= TCR_EPD1;

	/*
	 * TCR.A1 = 0 => ASID is stored in TTBR0
	 * TCR.AS = 0 => Same ASID size as in Aarch32/ARMv7
	 */

	write_tcr_el1(tcr);
	write_ttbr0_el1(ttbr0);   //将页表基地址写入到ttbr0寄存器
	write_ttbr1_el1(0);
}
4、tee内核页表填充

在optee内核中,实现的是一个4G的大页表(一级页表, 32bit可表示4G空间)

在section段定义了一个三元数组,用于存放页表

uint64_t l1_xlation_table[NUM_L1_TABLES][CFG_TEE_CORE_NB_CORE][NUM_L1_ENTRIES]
	__aligned(NUM_L1_ENTRIES * XLAT_ENTRY_SIZE) __section(".nozi.mmu.l1");

形态入下图所示
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记
填充页表,那么要将哪些地址填进去呢?
在core_init_mmu_map()函数中,调用core_init_mmu_tables创建页表,参数static_memory_map是一个数组,它指向系统中向optee已注册了的所有内存区域的地址

void core_init_mmu_map(void)
{
......
	core_init_mmu_tables(static_memory_map);
......
}
static struct tee_mmap_region static_memory_map[CFG_MMAP_REGIONS + 1];
#define CFG_MMAP_REGIONS 13//表示当前optee,最多支持注册13块内存区域

调用core_init_mmu_tables()填充的页表
参数mm就是刚才的static_memory_map,小于等于13块的内存区域, 填充方法如下

void core_init_mmu_tables(struct tee_mmap_region *mm)
{
	uint64_t max_va = 0;
	size_t n;

#ifdef CFG_CORE_UNMAP_CORE_AT_EL0
	COMPILE_TIME_ASSERT(CORE_MMU_L1_TBL_OFFSET ==
			   sizeof(l1_xlation_table) / 2);
#endif
	max_pa = get_nsec_ddr_max_pa();

	for (n = 0; !core_mmap_is_end_of_table(mm + n); n++) {
		paddr_t pa_end;
		vaddr_t va_end;

		debug_print(" %010" PRIxVA " %010" PRIxPA " %10zx %x",
			    mm[n].va, mm[n].pa, mm[n].size, mm[n].attr);

		if (!IS_PAGE_ALIGNED(mm[n].pa) || !IS_PAGE_ALIGNED(mm[n].size))
			panic("unaligned region");

		pa_end = mm[n].pa + mm[n].size - 1;
		va_end = mm[n].va + mm[n].size - 1;
		if (pa_end > max_pa)
			max_pa = pa_end;
		if (va_end > max_va)
			max_va = va_end;
	}

	/* Clear table before use */
	memset(l1_xlation_table, 0, sizeof(l1_xlation_table));   ------------------------清空页表

	for (n = 0; !core_mmap_is_end_of_table(mm + n); n++)
		if (!core_mmu_is_dynamic_vaspace(mm + n))
			core_mmu_map_region(mm + n);   ------------------------填充当前cpu的页表

	/*
	 * Primary mapping table is ready at index `get_core_pos()`
	 * whose value may not be ZERO. Take this index as copy source.
	 */
	for (n = 0; n < CFG_TEE_CORE_NB_CORE; n++) {
		if (n == get_core_pos())
			continue;

		memcpy(l1_xlation_table[0][n],
		       l1_xlation_table[0][get_core_pos()],   ------------------------将当前cpu的页表,拷贝到其它cpu的页表中
		       XLAT_ENTRY_SIZE * NUM_L1_ENTRIES);
	}

	for (n = 1; n < NUM_L1_ENTRIES; n++) {
		if (!l1_xlation_table[0][0][n]) {
			user_va_idx = n;
			break;
		}
	}
	assert(user_va_idx != -1);

	COMPILE_TIME_ASSERT(CFG_LPAE_ADDR_SPACE_SIZE > 0);
	assert(max_va < CFG_LPAE_ADDR_SPACE_SIZE);
}

在下列段代码中,循环遍历mm遍历,对于每个内存区域,做core_mmu_map_region运算

for (n = 0; !core_mmap_is_end_of_table(mm + n); n++)
		if (!core_mmu_is_dynamic_vaspace(mm + n))
			core_mmu_map_region(mm + n);

core_mmu_map_region就是将每块内存区域,进行拆分,拆分程若干entry

void core_mmu_map_region(struct tee_mmap_region *mm)
{
	struct core_mmu_table_info tbl_info;
	unsigned int idx;
	vaddr_t vaddr = mm->va;
	paddr_t paddr = mm->pa;
	ssize_t size_left = mm->size;
	int level;
	bool table_found;
	uint32_t old_attr;

	assert(!((vaddr | paddr) & SMALL_PAGE_MASK));

	while (size_left > 0) {
		level = 1;

		while (true) {
			assert(level <= CORE_MMU_PGDIR_LEVEL);

			table_found = core_mmu_find_table(vaddr, level,
							  &tbl_info);
			if (!table_found)
				panic("can't find table for mapping");

			idx = core_mmu_va2idx(&tbl_info, vaddr);

			if (!can_map_at_level(paddr, vaddr, size_left,
					      1 << tbl_info.shift, mm)) {
				/*
				 * This part of the region can't be mapped at
				 * this level. Need to go deeper.
				 */
				if (!core_mmu_entry_to_finer_grained(&tbl_info,
					      idx, mm->attr & TEE_MATTR_SECURE))
					panic("Can't divide MMU entry");
				level++;
				continue;
			}

			/* We can map part of the region at current level */
			core_mmu_get_entry(&tbl_info, idx, NULL, &old_attr);
			if (old_attr)
				panic("Page is already mapped");

			core_mmu_set_entry(&tbl_info, idx, paddr, mm->attr);
			paddr += 1 << tbl_info.shift;
			vaddr += 1 << tbl_info.shift;
			size_left -= 1 << tbl_info.shift;

			break;
		}
	}
}
5、virt_to_phys转换的过程的举例

通过画图讲述了,在optee中,构建页表,然后完成一个virt_to_phys转换的过程.

  • 1、系统注册了的若干块内存,划分为若干个大小为4K/8K的region,每个region的地址,写入到页表的entry中,这样就构建出了页表.
  • 2、将页表物理地址写入到TTBR0中
  • 3、开启MMU
  • 4、调用virt_to_phys时,使用MMU的AT S1E1R指令,将虚拟地址写入到MMU的Address translation中
  • 5、从par_el1中读出的物理地址,就是经过MMU转换后的

注意:
1、在optee中禁止了TTBR1,所以在optee的kernel mode中,也是使用TTBR0
2、optee中,只使用到了一级页表
[mmu/cache]-ARM MMU的学习笔记-一篇就够了,ARM,arm开发,学习,ARM,armv9,armv8,MMU,笔记文章来源地址https://www.toymoban.com/news/detail-843091.html


推荐
  • ARMv8/ARMv9架构从入门到精通 --博客专栏
  • 《Armv8/Armv9架构从入门到精通 第二期》 --大课程
  • 8天入门ARM架构 --入门课程

到了这里,关于[mmu/cache]-ARM MMU的学习笔记-一篇就够了的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Arm Trustzone与ATF安全介绍 - 一篇就够了

    随着时代的发展、科技的进步,安全需求的趋势也越来越明显,ARM也一直在调整和更新其新架构,很多都是和安全相关的。如下列出了一些和安全相关的架构 基于Trust Zone技术,硬件被静态隔离,可预先分配硬件归属于关键应用域或非关键应用域,不需要hypervisor的支持,相关

    2024年02月05日
    浏览(33)
  • ARM aarch64架构安装Redis看这一篇就够了

    一. 环境准备 系统:Mac OS M1 Linux版本:CentOS 9 Linux架构:aarch64 使用uname -m命令确认自己系统的架构 二. 安装Redis 安装gcc 在安装 Redis 时需要安装 GCC 是因为 Redis 需要编译 C 语言源代码,并将其转换为二进制可执行文件。GCC 是一种广泛使用的编译器,可以将 C 代码编译成机器码

    2024年02月05日
    浏览(34)
  • 学习SpringSecurity这一篇就够了

    案例源码地址:https://gitee.com/gzl_com/spring-security.git 1.1、概要 Spring Security 是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。 安全方面的两个主要区域是“ 认证 ”和“ 授权 ”。在Web 应用又称之为 用户认证 和 用户授权 两个部

    2024年02月11日
    浏览(37)
  • 学习C++这一篇就够了(基础篇)

    在C++中如何使用C语言打包好的库函数 空间分配原则是以“连续空闲”为核心的 运行某个程序后,一定会向内存申请空间 分配内存时,内存空间一定是连续的 分配出来的空间,是不确定位置的 单行注释: //一行的注释内容 多行注释:(模块化注释) /* 多行的注释内容 多行

    2024年02月12日
    浏览(46)
  • 学习C++这一篇就够了(进阶篇)

    C++在执行程序的时候,将内存方向划分为4个区域: 代码区:存放二进制代码,由操作系统进行管理 全局区:存放全局变量、静态变量、常量,程序结束后由操作系统释放 栈区:存放函数参数、局部变量,由编译器自动分配和释放 堆区:由开发者申请分配和释放,若程序员

    2024年02月12日
    浏览(32)
  • 超图(HyperGraph)学习,看这一篇就够了

    最近事多,好久没更新了,随便写写(Ctrl+V)点 一、超图定义 通常图论中的图,一条edge只能连接2个vertex,在超图中,不限量 如何理解呢,就用我正在做的KT问题来看:7道题目-7个顶点;4种概念-4条超边,其中第1,2,3题都是考察概念1的,则构建一个包含了这仨的超边,以此类

    2024年02月02日
    浏览(44)
  • 鸿蒙系统概述(HarmonyOS)学习这一篇就够了!

    我们可以从以下三个主要方面进行概述: 系统定义、技术特征、系统安全 。 目录 鸿蒙系统概述(HarmonyOS) 系统定义  系统定位 技术架构  内核层   系统服务层 框架层 应用层  技术特性 硬件互助,资源共享 一次开发,多端部署 统一OS,弹性部署  系统安全 正确的人 正

    2023年04月08日
    浏览(35)
  • 学习【Git项目管理工具】这一篇就够了

    Git是一个分布式版本控制工具,主要用于管理开发过程中的源代码文件(Java类、ml文件、html页面等),在软件开发过程中被广泛使用。 学完Git之后能做什么? 代码回溯 版本切换 多人协作 远程备份 Git仓库分为两种: 本地仓库:开发人员自己电脑的 Git 仓库 远程仓库:远程服务

    2024年01月19日
    浏览(39)
  • ARM Cortex-A学习(3):MMU内存管理单元

    内存管理单元( MMU )负责虚拟地址到物理地址的转换。MMU通过翻译表将程序使用的虚拟地址映射到实际的物理内存位置,实现对内存的动态管理和隔离。这不仅允许更灵活的内存分配,还提高了系统的安全性和稳定性。了解MMU的工作原理对于开发底层代码、BootLoader和驱动程序

    2024年01月21日
    浏览(30)
  • Python GUI界面界面—tkinter,学习、复习、查阅,这一篇就够了

            PythonGUI程序界面设计tkinter优点:无需另外下载,是自带的、操作简单、易方便;                                                          缺点:界面控件较少,页面不够美观 注:一般来说做小软件tkinter足够了(页面可以用ttkbootstrap美化

    2024年01月17日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包