TLB内存页表 - LoongArch
文章目录
- TLB内存页表 - LoongArch
- 页表操作指令
- TLB相关寄存器
- 页表格式
- CpuSetAttributes
- UEFI Memory attribute
页表操作指令
LDDIR: 用于软件页表遍历过程中目录项的访问.
LDPTE: 用于在软件页表遍历过程中页表项的访问.
INVTLB: 用于无效TLB中的内容.
TLBFILL: 用于将页表项信息填入TLB中.
TLB相关寄存器
CSR 0x88: TLBRENTRY TLB重填例外入口地址.
CSR 0x8b: TLBRSAVE TLB重填例外数据保存.
CSR 0x8c, 0x8d, 0x8e TLBRLO TLBRHI (设置PS与硬件获取BADV) TLB重填例外表项.
CSR 0x19, 0x1a: PGDL PGDH 地址空间全局目录基址.
CSR 0x1b: PGD 全局目录基址 (只读).
CSR 0x1c, 0x1d: PWCL PWCH 页表遍历控制(控制多级页表索引).
页表格式
PGD->PUD->PMD->PTE:
CpuSetAttributes
- 1 初始化PageSize,一般通常页大小采用4K.
ASM_PFX(WriteCsrTlbRefillPageSize):
li.d T0, CSR_TLBREHI_PS_SHIFT
sll.d A0, A0, T0
li.d T0, CSR_TLBREHI_PS
csrxchg A0, T0, LOONGARCH_CSR_TLBREHI
jirl ZERO, RA,0
- 2 将LDDIR,LDPTE,TLBFILL 的页表查找填充处理函数作为TLB异常入口进行设置.
ASM_PFX(HandleTlbRefill):
csrwr T0, LOONGARCH_CSR_TLBRSAVE
csrrd T0, LOONGARCH_CSR_PGD
lddir T0, T0, 3 #Put pud BaseAddress into T0
lddir T0, T0, 2 #Put pmd BaseAddress into T0
lddir T0, T0, 1 #Put pte BaseAddress into T0
ldpte T0, 0
ldpte T0, 1
/*refill hi,lo0,lo1*/
tlbfill
csrrd T0, LOONGARCH_CSR_TLBRSAVE
ertn
HandleTlbRefillEnd:
- 3 根据阶段不同,需要将异常处理函数进行二次内存分配拷贝,防止前期代码执行的内存被释放.
TlbReEntry = AllocatePages (1);
if (TlbReEntry == NULL) {
goto FreeTranslationTable;
}
CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
- 4 根据PWC来设置页表格式. 控制PGD,PUD, PMD, PTE的多级页表宽度,关于多级页表的组成有时间详细来计算.
LoongArchWriteqCsrPwctl0 ((PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
LoongArchWriteqCsrPwctl1 (PgdShift | PgdWide << 6);
- 5 设置PGD页表的目录项供页表遍历的异常处理获取内存页表地址.
LoongArchWriteqCsrPgdl ((UINTN)SwapperPageDir);
LoongArchWriteqCsrPgdh ((UINTN)InvalidPgd);
- 6 根据页表格式与多级页表硬件遍历方式采用软件遍历的方式进行初始化或替换页表,例:设置某些内存或io属性以及执行权限等.
/*Page table property definitions */
#define PAGE_VALID_SHIFT 0
#define PAGE_DIRTY_SHIFT 1
#define PAGE_PLV_SHIFT 2 /* 2~3, two bits */
#define CACHE_SHIFT 4 /* 4~5, two bits */
#define PAGE_GLOBAL_SHIFT 6
#define PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */
#define PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
#define PAGE_PFN_SHIFT 12
#define PAGE_PFN_END_SHIFT 48
#define PAGE_NO_READ_SHIFT 61
#define PAGE_NO_EXEC_SHIFT 62
#define PAGE_RPLV_SHIFT 63
- 7 打开MMU接管地址空间.
以上简述是针对UEFI下CpuSetAttributes接口的底层实现,为了追加内存读写执行保护以及内存CACHE或UNCACHE属性切换所叙述的MMU处理流程.
UEFI Memory attribute
//
// Memory cacheability attributes
//
#define EFI_MEMORY_UC 0x0000000000000001ULL
#define EFI_MEMORY_WC 0x0000000000000002ULL
#define EFI_MEMORY_WT 0x0000000000000004ULL
#define EFI_MEMORY_WB 0x0000000000000008ULL
#define EFI_MEMORY_UCE 0x0000000000000010ULL
//
// Physical memory protection attributes
//
// Note: UEFI spec 2.5 and following: use EFI_MEMORY_RO as write-protected physical memory
// protection attribute. Also, EFI_MEMORY_WP means cacheability attribute.
//
#define EFI_MEMORY_WP 0x0000000000001000ULL
#define EFI_MEMORY_RP 0x0000000000002000ULL
#define EFI_MEMORY_XP 0x0000000000004000ULL
#define EFI_MEMORY_RO 0x0000000000020000ULL
//
根据EFI标准去转换自身架构的内存管理机制:
/*Page table property definitions */
#define PAGE_VALID_SHIFT 0
#define PAGE_DIRTY_SHIFT 1
#define PAGE_PLV_SHIFT 2 /* 2~3, two bits */
#define CACHE_SHIFT 4 /* 4~5, two bits */
#define PAGE_GLOBAL_SHIFT 6
#define PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */
#define PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
#define PAGE_PFN_SHIFT 12
#define PAGE_PFN_END_SHIFT 48
#define PAGE_NO_READ_SHIFT 61
#define PAGE_NO_EXEC_SHIFT 62
#define PAGE_RPLV_SHIFT 63