Skip to content

Commit 8cd4a4e

Browse files
committed
feat: arm64 ASID support
Signed-off-by: Shell <[email protected]>
1 parent cc1707e commit 8cd4a4e

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)