Skip to content

Commit dafc5f7

Browse files
committed
feat: arm64 ASID support
Support for ARM64 ASID to enhance virtual memory management efficiency by reducing the need for TLB flushes during address space switches. These changes improve performance especially for multi-process systems. Changes: - Added `ARCH_USING_ASID` configuration in `libcpu/aarch64/Kconfig`. - Defined ASID-related constants in `mmu.h`. - Updated `TLBI_ARG` macro to include ASID manipulation. - Implemented ASID allocation mechanism with spinlock synchronization. - Enhanced TLB invalidation to support ASID-specific operations. - Modified `rt_hw_aspace_switch` to use ASIDs when switching address spaces. - Adjusted debug logging and function documentation to reflect ASID usage. - Refactored AArch64 MMU and TLB handling for ASID integration. Signed-off-by: Shell <[email protected]>
1 parent cc1707e commit dafc5f7

File tree

4 files changed

+105
-27
lines changed

4 files changed

+105
-27
lines changed

libcpu/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ config ARCH_ARMV8
219219
select ARCH_ARM
220220
select ARCH_ARM_MMU
221221
select RT_USING_CPU_FFS
222+
select ARCH_USING_ASID
222223
select ARCH_USING_IRQ_CTX_LIST
223224

224225
config ARCH_MIPS

libcpu/aarch64/common/include/mmu.h

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,38 @@ struct mem_desc
4141
#define RT_HW_MMU_PROT_USER 16
4242
#define RT_HW_MMU_PROT_CACHE 32
4343

44+
#define MMU_ASID_SHIFT 48
45+
#define MMU_NG_SHIFT 11 /* not global bit */
4446
#define MMU_AF_SHIFT 10
4547
#define MMU_SHARED_SHIFT 8
4648
#define MMU_AP_SHIFT 6
4749
#define MMU_MA_SHIFT 2
4850
#define MMU_AP_MASK (0x3 << MMU_AP_SHIFT)
4951

52+
/* we dont support feat detecting for now, so 8-bit is used to fallback */
53+
#define MMU_SUPPORTED_ASID_BITS 8
54+
5055
#define MMU_AP_KAUN 0UL /* kernel r/w, user none */
5156
#define MMU_AP_KAUA 1UL /* kernel r/w, user r/w */
5257
#define MMU_AP_KRUN 2UL /* kernel r, user none */
5358
#define MMU_AP_KRUR 3UL /* kernel r, user r */
5459
#define MMU_ATTR_AF (1ul << MMU_AF_SHIFT) /* the access flag */
5560
#define MMU_ATTR_DBM (1ul << 51) /* the dirty bit modifier */
5661

57-
#define MMU_MAP_CUSTOM(ap, mtype) \
62+
#define MMU_MAP_CUSTOM(ap, mtype, nglobal) \
5863
((0x1UL << MMU_AF_SHIFT) | (0x2UL << MMU_SHARED_SHIFT) | \
59-
((ap) << MMU_AP_SHIFT) | ((mtype) << MMU_MA_SHIFT))
60-
#define MMU_MAP_K_ROCB MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_MEM)
61-
#define MMU_MAP_K_RO MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_NOCACHE_MEM)
62-
#define MMU_MAP_K_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM)
63-
#define MMU_MAP_K_RW MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_NOCACHE_MEM)
64-
#define MMU_MAP_K_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUN, DEVICE_MEM)
65-
#define MMU_MAP_U_ROCB MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_MEM)
66-
#define MMU_MAP_U_RO MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_NOCACHE_MEM)
67-
#define MMU_MAP_U_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_MEM)
68-
#define MMU_MAP_U_RW MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_NOCACHE_MEM)
69-
#define MMU_MAP_U_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUA, DEVICE_MEM)
64+
((ap) << MMU_AP_SHIFT) | ((mtype) << MMU_MA_SHIFT)) | \
65+
((rt_ubase_t)(nglobal) << MMU_NG_SHIFT)
66+
#define MMU_MAP_K_ROCB MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_MEM, 0)
67+
#define MMU_MAP_K_RO MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_NOCACHE_MEM, 0)
68+
#define MMU_MAP_K_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM, 0)
69+
#define MMU_MAP_K_RW MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_NOCACHE_MEM, 0)
70+
#define MMU_MAP_K_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUN, DEVICE_MEM, 0)
71+
#define MMU_MAP_U_ROCB MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_MEM, 1)
72+
#define MMU_MAP_U_RO MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_NOCACHE_MEM, 1)
73+
#define MMU_MAP_U_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_MEM, 1)
74+
#define MMU_MAP_U_RW MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_NOCACHE_MEM, 1)
75+
#define MMU_MAP_U_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUA, DEVICE_MEM, 1)
7076
#define MMU_MAP_TRACE(attr) ((attr) & ~(MMU_ATTR_AF | MMU_ATTR_DBM))
7177

7278
#define ARCH_SECTION_SHIFT 21

libcpu/aarch64/common/include/tlb.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
#define TLBI_ARG(addr, asid) \
2020
({ \
21-
uintptr_t arg = (uintptr_t)(addr) >> 12; \
21+
rt_ubase_t arg = (rt_ubase_t)(addr) >> ARCH_PAGE_SHIFT; \
2222
arg &= (1ull << 44) - 1; \
23-
arg |= (uintptr_t)(asid) << 48; \
23+
arg |= (rt_ubase_t)(asid) << MMU_ASID_SHIFT; \
2424
(void *)arg; \
2525
})
2626

@@ -50,7 +50,18 @@ static inline void rt_hw_tlb_invalidate_all_local(void)
5050

5151
static inline void rt_hw_tlb_invalidate_aspace(rt_aspace_t aspace)
5252
{
53+
#ifdef ARCH_USING_ASID
54+
__asm__ volatile(
55+
// ensure updates to pte completed
56+
"dsb nshst\n"
57+
"tlbi aside1is, %0\n"
58+
"dsb nsh\n"
59+
// after tlb in new context, refresh inst
60+
"isb\n" ::"r"(TLBI_ARG(0ul, aspace->asid))
61+
: "memory");
62+
#else
5363
rt_hw_tlb_invalidate_all();
64+
#endif
5465
}
5566

5667
static inline void rt_hw_tlb_invalidate_page(rt_aspace_t aspace, void *start)

libcpu/aarch64/common/mmu.c

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
* 2012-01-10 bernard porting to AM1808
99
* 2021-11-28 GuEe-GUI first version
1010
* 2022-12-10 WangXiaoyao porting to MM
11+
* 2024-07-08 Shell added support for ASID
1112
*/
1213

1314
#define DBG_TAG "hw.mmu"
14-
#define DBG_LVL DBG_LOG
15+
#define DBG_LVL DBG_INFO
1516
#include <rtdbg.h>
1617

1718
#include <rthw.h>
@@ -138,8 +139,8 @@ static int _kernel_map_4K(unsigned long *lv0_tbl, void *vaddr, void *paddr, unsi
138139
unsigned long *cur_lv_tbl = lv0_tbl;
139140
unsigned long page;
140141
unsigned long off;
141-
intptr_t va = (intptr_t)vaddr;
142-
intptr_t pa = (intptr_t)paddr;
142+
rt_ubase_t va = (rt_ubase_t)vaddr;
143+
rt_ubase_t pa = (rt_ubase_t)paddr;
143144
int level_shift = MMU_ADDRESS_BITS;
144145

145146
if (va & ARCH_PAGE_MASK)
@@ -345,23 +346,82 @@ void rt_hw_mmu_unmap(rt_aspace_t aspace, void *v_addr, size_t size)
345346
}
346347
}
347348

349+
#ifdef ARCH_USING_ASID
350+
/**
351+
* the asid is to identified specialized address space on TLB.
352+
* In the best case, each address space has its own exclusive asid. However,
353+
* ARM only guarantee with 8 bits of ID space, which give us only 254(except
354+
* the reserved 1 ASID for kernel).
355+
*/
356+
357+
static rt_spinlock_t _asid_lock = RT_SPINLOCK_INIT;
358+
359+
rt_uint16_t _aspace_get_asid(rt_aspace_t aspace)
360+
{
361+
static rt_uint16_t _asid_pool = 0;
362+
rt_uint16_t asid_to, asid_from;
363+
rt_ubase_t ttbr0_from;
364+
365+
asid_to = aspace->asid;
366+
if (asid_to == 0)
367+
{
368+
rt_spin_lock(&_asid_lock);
369+
#define MAX_ASID (1ul << MMU_SUPPORTED_ASID_BITS)
370+
if (_asid_pool && _asid_pool < MAX_ASID)
371+
{
372+
asid_to = ++_asid_pool;
373+
LOG_D("Allocated ASID %d to PID %d(aspace %p)", asid_to, lwp_self()->pid, aspace);
374+
}
375+
else
376+
{
377+
asid_to = _asid_pool = 1;
378+
LOG_D("Overflowed ASID %d to PID %d(aspace %p)", asid_to, lwp_self()->pid, aspace);
379+
}
380+
381+
rt_spin_unlock(&_asid_lock);
382+
383+
aspace->asid = asid_to;
384+
rt_hw_tlb_invalidate_aspace(aspace);
385+
}
386+
387+
__asm__ volatile("mrs %0, ttbr0_el1" :"=r"(ttbr0_from));
388+
asid_from = ttbr0_from >> MMU_ASID_SHIFT;
389+
if (asid_from == asid_to)
390+
{
391+
LOG_D("Conflict ASID. from %d, to %d", asid_from, asid_to);
392+
rt_hw_tlb_invalidate_aspace(aspace);
393+
}
394+
else
395+
{
396+
LOG_D("ASID switched. from %d, to %d", asid_from, asid_to);
397+
}
398+
399+
return asid_to;
400+
}
401+
402+
#else
403+
404+
405+
rt_uint16_t _aspace_get_asid(rt_aspace_t aspace)
406+
{
407+
rt_hw_tlb_invalidate_all();
408+
return 0;
409+
}
410+
#endif /* ARCH_USING_ASID */
411+
412+
#define CREATE_TTBR0(pgtbl, asid) ((rt_ubase_t)(pgtbl) | (rt_ubase_t)(asid) << MMU_ASID_SHIFT)
348413
void rt_hw_aspace_switch(rt_aspace_t aspace)
349414
{
350415
if (aspace != &rt_kernel_space)
351416
{
417+
rt_ubase_t ttbr0;
352418
void *pgtbl = aspace->page_table;
353419
pgtbl = rt_kmem_v2p(pgtbl);
354-
rt_ubase_t tcr;
355-
356-
__asm__ volatile("msr ttbr0_el1, %0" ::"r"(pgtbl) : "memory");
357420

358-
__asm__ volatile("mrs %0, tcr_el1" : "=r"(tcr));
359-
tcr &= ~(1ul << 7);
360-
__asm__ volatile("msr tcr_el1, %0\n"
361-
"isb" ::"r"(tcr)
362-
: "memory");
421+
ttbr0 = CREATE_TTBR0(pgtbl, _aspace_get_asid(aspace));
363422

364-
rt_hw_tlb_invalidate_all_local();
423+
__asm__ volatile("msr ttbr0_el1, %0" ::"r"(ttbr0));
424+
__asm__ volatile("isb" ::: "memory");
365425
}
366426
}
367427

@@ -836,7 +896,7 @@ void rt_hw_mem_setup_early(unsigned long *tbl0, unsigned long *tbl1,
836896
{
837897
int ret;
838898
unsigned long count = (size + ARCH_SECTION_MASK) >> ARCH_SECTION_SHIFT;
839-
unsigned long normal_attr = MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM);
899+
unsigned long normal_attr = MMU_MAP_K_RWCB;
840900
extern unsigned char _start;
841901
unsigned long va = (unsigned long) &_start - pv_off;
842902
va = RT_ALIGN_DOWN(va, 0x200000);

0 commit comments

Comments
 (0)