mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-24 05:04:10 +08:00
[rt-smart] kernel virtual memory management layer (#6809)
synchronize virtual memory system works. adding kernel virtual memory management layer for page-based MMU enabled architecture porting libcpu MMU codes porting lwp memory related codes
This commit is contained in:
@@ -183,7 +183,7 @@ rt_hw_get_gtimer_frq:
|
||||
#ifdef RT_USING_LWP
|
||||
BL rt_thread_self
|
||||
MOV X19, X0
|
||||
BL lwp_mmu_switch
|
||||
BL lwp_aspace_switch
|
||||
MOV X0, X19
|
||||
BL lwp_user_setting_restore
|
||||
#endif
|
||||
@@ -514,28 +514,3 @@ vector_serror:
|
||||
STP X0, X1, [SP, #-0x10]!
|
||||
BL rt_hw_trap_serror
|
||||
b .
|
||||
|
||||
.global rt_hw_mmu_switch
|
||||
rt_hw_mmu_switch:
|
||||
MSR TTBR0_EL1, X0
|
||||
MRS X1, TCR_EL1
|
||||
CMP X0, XZR
|
||||
ORR X1, X1, #(1 << 7)
|
||||
BEQ 1f
|
||||
BIC X1, X1, #(1 << 7)
|
||||
1:
|
||||
MSR TCR_EL1, X1
|
||||
DSB SY
|
||||
ISB
|
||||
TLBI VMALLE1
|
||||
DSB SY
|
||||
ISB
|
||||
IC IALLUIS
|
||||
DSB SY
|
||||
ISB
|
||||
RET
|
||||
|
||||
.global rt_hw_mmu_tbl_get
|
||||
rt_hw_mmu_tbl_get:
|
||||
MRS X0, TTBR0_EL1
|
||||
RET
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
static inline rt_uint64_t get_secondary_entry_pa(void)
|
||||
{
|
||||
rt_uint64_t secondary_entry_pa = (rt_uint64_t)rt_hw_mmu_v2p(&mmu_info, _secondary_cpu_entry);
|
||||
rt_uint64_t secondary_entry_pa = (rt_uint64_t)rt_kmem_v2p(_secondary_cpu_entry);
|
||||
|
||||
if (!secondary_entry_pa)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define CPUPORT_H__
|
||||
|
||||
#include <armv8.h>
|
||||
#include <rtdef.h>
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
typedef union {
|
||||
@@ -29,12 +30,22 @@ rt_inline void rt_hw_isb(void)
|
||||
|
||||
rt_inline void rt_hw_dmb(void)
|
||||
{
|
||||
asm volatile ("dmb sy":::"memory");
|
||||
asm volatile ("dmb ish":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_wmb(void)
|
||||
{
|
||||
asm volatile ("dmb ishst":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_rmb(void)
|
||||
{
|
||||
asm volatile ("dmb ishld":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_dsb(void)
|
||||
{
|
||||
asm volatile ("dsb sy":::"memory");
|
||||
asm volatile ("dsb ish":::"memory");
|
||||
}
|
||||
|
||||
#endif /*CPUPORT_H__*/
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
#include "gic.h"
|
||||
#include "gicv3.h"
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
#include "ioremap.h"
|
||||
#else
|
||||
#define rt_ioremap(x, ...) (x)
|
||||
#endif
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc isr_table[MAX_HANDLERS];
|
||||
|
||||
@@ -103,11 +109,11 @@ void rt_hw_interrupt_init(void)
|
||||
|
||||
/* initialize ARM GIC */
|
||||
#ifdef RT_USING_SMART
|
||||
gic_dist_base = (rt_uint64_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_dist_base(), 0x2000, MMU_MAP_K_DEVICE);
|
||||
gic_cpu_base = (rt_uint64_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_cpu_base(), 0x1000, MMU_MAP_K_DEVICE);
|
||||
gic_dist_base = (rt_uint64_t)rt_ioremap((void*)platform_get_gic_dist_base(), 0x2000);
|
||||
gic_cpu_base = (rt_uint64_t)rt_ioremap((void*)platform_get_gic_cpu_base(), 0x1000);
|
||||
#ifdef BSP_USING_GICV3
|
||||
gic_rdist_base = (rt_uint64_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_redist_base(),
|
||||
RT_CPUS_NR * (2 << 16), MMU_MAP_K_DEVICE);
|
||||
gic_rdist_base = (rt_uint64_t)rt_ioremap((void*)platform_get_gic_redist_base(),
|
||||
RT_CPUS_NR * (2 << 16));
|
||||
#endif
|
||||
#else
|
||||
gic_dist_base = platform_get_gic_dist_base();
|
||||
|
||||
+384
-734
File diff suppressed because it is too large
Load Diff
+52
-81
@@ -11,6 +11,7 @@
|
||||
#define __MMU_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <mm_aspace.h>
|
||||
|
||||
/* normal memory wra mapping type */
|
||||
#define NORMAL_MEM 0
|
||||
@@ -25,6 +26,7 @@ struct mem_desc
|
||||
unsigned long vaddr_end;
|
||||
unsigned long paddr_start;
|
||||
unsigned long attr;
|
||||
struct rt_varea varea;
|
||||
};
|
||||
|
||||
#define MMU_AF_SHIFT 10
|
||||
@@ -37,60 +39,17 @@ struct mem_desc
|
||||
#define MMU_AP_KRUN 2UL /* kernel r, user none */
|
||||
#define MMU_AP_KRUR 3UL /* kernel r, user r */
|
||||
|
||||
#define MMU_MAP_K_RO (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KRUN << MMU_AP_SHIFT) |\
|
||||
(NORMAL_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_K_RWCB (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KAUN << MMU_AP_SHIFT) |\
|
||||
(NORMAL_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_K_RW (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KAUN << MMU_AP_SHIFT) |\
|
||||
(NORMAL_NOCACHE_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_K_DEVICE (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KAUN << MMU_AP_SHIFT) |\
|
||||
(DEVICE_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_U_RO (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KRUR << MMU_AP_SHIFT) |\
|
||||
(NORMAL_NOCACHE_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_U_RWCB (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KAUA << MMU_AP_SHIFT) |\
|
||||
(NORMAL_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_U_RW (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KAUA << MMU_AP_SHIFT) |\
|
||||
(NORMAL_NOCACHE_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_U_DEVICE (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
(MMU_AP_KAUA << MMU_AP_SHIFT) |\
|
||||
(DEVICE_MEM << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_CUSTOM(ap, mtype) (\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
((ap) << MMU_AP_SHIFT) |\
|
||||
((mtype) << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_CUSTOM(ap, mtype) \
|
||||
((0x1UL << MMU_AF_SHIFT) | (0x2UL << MMU_SHARED_SHIFT) | \
|
||||
((ap) << MMU_AP_SHIFT) | ((mtype) << MMU_MA_SHIFT))
|
||||
#define MMU_MAP_K_RO MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_MEM)
|
||||
#define MMU_MAP_K_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM)
|
||||
#define MMU_MAP_K_RW MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_NOCACHE_MEM)
|
||||
#define MMU_MAP_K_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUN, DEVICE_MEM)
|
||||
#define MMU_MAP_U_RO MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_NOCACHE_MEM)
|
||||
#define MMU_MAP_U_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_MEM)
|
||||
#define MMU_MAP_U_RW MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_NOCACHE_MEM)
|
||||
#define MMU_MAP_U_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUA, DEVICE_MEM)
|
||||
|
||||
#define ARCH_SECTION_SHIFT 21
|
||||
#define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT)
|
||||
@@ -102,6 +61,7 @@ struct mem_desc
|
||||
#define ARCH_PAGE_TBL_SIZE (1 << ARCH_PAGE_TBL_SHIFT)
|
||||
#define ARCH_PAGE_TBL_MASK (ARCH_PAGE_TBL_SIZE - 1)
|
||||
|
||||
#define ARCH_VADDR_WIDTH 48
|
||||
#define ARCH_ADDRESS_WIDTH_BITS 64
|
||||
|
||||
#define MMU_MAP_ERROR_VANOTALIGN -1
|
||||
@@ -109,37 +69,48 @@ struct mem_desc
|
||||
#define MMU_MAP_ERROR_NOPAGE -3
|
||||
#define MMU_MAP_ERROR_CONFLICT -4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t *vtable;
|
||||
size_t vstart;
|
||||
size_t vend;
|
||||
size_t pv_off;
|
||||
} rt_mmu_info;
|
||||
#define ARCH_MAP_FAILED ((void *)0x1ffffffffffff)
|
||||
|
||||
void rt_hw_mmu_setup_early(unsigned long *tbl0, unsigned long *tbl1, unsigned long size, unsigned long pv_off);
|
||||
void rt_hw_mmu_setup(struct mem_desc *mdesc, int desc_nr);
|
||||
|
||||
int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off);
|
||||
int rt_hw_mmu_ioremap_init(rt_mmu_info *mmu_info, void* v_address, size_t size);
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr);
|
||||
void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr);
|
||||
#else
|
||||
void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr);
|
||||
#endif
|
||||
|
||||
void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size);
|
||||
void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr);
|
||||
struct rt_aspace;
|
||||
|
||||
void rt_hw_mmu_ktbl_set(unsigned long tbl);
|
||||
void *rt_hw_mmu_tbl_get();
|
||||
void rt_hw_mmu_switch(void *mmu_table);
|
||||
void rt_hw_mmu_setup_early(unsigned long *tbl0, unsigned long *tbl1,
|
||||
unsigned long size, unsigned long pv_off);
|
||||
void rt_hw_mmu_setup(struct rt_aspace *aspace, struct mem_desc *mdesc,
|
||||
int desc_nr);
|
||||
|
||||
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_size_t desc_nr);
|
||||
void rt_hw_mmu_init(void);
|
||||
int rt_hw_mmu_map_init(struct rt_aspace *aspace, void *v_address,
|
||||
rt_size_t size, rt_size_t *vtable, rt_size_t pv_off);
|
||||
void *rt_hw_mmu_map(struct rt_aspace *aspace, void *v_addr, void *p_addr,
|
||||
size_t size, size_t attr);
|
||||
void rt_hw_mmu_unmap(struct rt_aspace *aspace, void *v_addr, size_t size);
|
||||
void rt_hw_aspace_switch(struct rt_aspace *aspace);
|
||||
void *rt_hw_mmu_v2p(struct rt_aspace *aspace, void *vaddr);
|
||||
void rt_hw_mmu_kernel_map_init(struct rt_aspace *aspace, rt_size_t vaddr_start,
|
||||
rt_size_t size);
|
||||
void rt_hw_mmu_ktbl_set(unsigned long tbl);
|
||||
|
||||
extern rt_mmu_info mmu_info;
|
||||
static inline void *rt_hw_mmu_tbl_get()
|
||||
{
|
||||
uintptr_t tbl;
|
||||
__asm__ volatile("MRS %0, TTBR0_EL1" : "=r"(tbl));
|
||||
return (void *)(tbl & ((1ul << 48) - 2));
|
||||
}
|
||||
|
||||
static inline void *_rt_kmem_v2p(void *vaddr)
|
||||
{
|
||||
return rt_hw_mmu_v2p(&rt_kernel_space, vaddr);
|
||||
}
|
||||
|
||||
static inline void *rt_kmem_v2p(void *vaddr)
|
||||
{
|
||||
MM_PGTBL_LOCK(&rt_kernel_space);
|
||||
void *paddr = _rt_kmem_v2p(vaddr);
|
||||
MM_PGTBL_UNLOCK(&rt_kernel_space);
|
||||
return paddr;
|
||||
}
|
||||
|
||||
int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size,
|
||||
enum rt_mmu_cntl cmd);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-28 WangXiaoyao the first version
|
||||
*/
|
||||
#ifndef __TLB_H__
|
||||
#define __TLB_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "mm_aspace.h"
|
||||
#include "mmu.h"
|
||||
|
||||
#define TLBI_ARG(addr, asid) \
|
||||
({ \
|
||||
uintptr_t arg = (uintptr_t)(addr) >> 12; \
|
||||
arg &= (1ull << 44) - 1; \
|
||||
arg |= (uintptr_t)(asid) << 48; \
|
||||
(void *)arg; \
|
||||
})
|
||||
|
||||
static inline void rt_hw_tlb_invalidate_all(void)
|
||||
{
|
||||
__asm__ volatile(
|
||||
// ensure updates to pte completed
|
||||
"dsb ishst\n"
|
||||
"tlbi vmalle1is\n"
|
||||
"dsb ish\n"
|
||||
// after tlb in new context, refresh inst
|
||||
"isb\n" ::
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void rt_hw_tlb_invalidate_all_local(void)
|
||||
{
|
||||
__asm__ volatile(
|
||||
// ensure updates to pte completed
|
||||
"dsb nshst\n"
|
||||
"tlbi vmalle1is\n"
|
||||
"dsb nsh\n"
|
||||
// after tlb in new context, refresh inst
|
||||
"isb\n" ::
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void rt_hw_tlb_invalidate_aspace(rt_aspace_t aspace)
|
||||
{
|
||||
rt_hw_tlb_invalidate_all_local();
|
||||
}
|
||||
|
||||
static inline void rt_hw_tlb_invalidate_page(rt_aspace_t aspace, void *start)
|
||||
{
|
||||
start = TLBI_ARG(start, 0);
|
||||
__asm__ volatile(
|
||||
"dsb ishst\n"
|
||||
"tlbi vaae1is, %0\n"
|
||||
"dsb ish\n"
|
||||
"isb\n" ::"r"(start)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline void rt_hw_tlb_invalidate_range(rt_aspace_t aspace, void *start,
|
||||
size_t size, size_t stride)
|
||||
{
|
||||
if (size < ARCH_PAGE_SIZE)
|
||||
{
|
||||
rt_hw_tlb_invalidate_page(aspace, start);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_tlb_invalidate_aspace(aspace);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __TLB_H__ */
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <armv8.h>
|
||||
#include "interrupt.h"
|
||||
#include "mm_fault.h"
|
||||
|
||||
#include <backtrace.h>
|
||||
|
||||
@@ -48,6 +49,29 @@ void check_user_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *info)
|
||||
}
|
||||
}
|
||||
|
||||
int _get_type(unsigned long esr)
|
||||
{
|
||||
int ret;
|
||||
int fsc = esr & 0x3f;
|
||||
switch (fsc)
|
||||
{
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
ret = MM_FAULT_TYPE_PAGE_FAULT;
|
||||
break;
|
||||
case 0x9:
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
ret = MM_FAULT_TYPE_ACCESS_FAULT;
|
||||
break;
|
||||
default:
|
||||
ret = MM_FAULT_TYPE_GENERIC;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int check_user_stack(unsigned long esr, struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
unsigned char ec;
|
||||
@@ -55,19 +79,36 @@ int check_user_stack(unsigned long esr, struct rt_hw_exp_stack *regs)
|
||||
int ret = 0;
|
||||
|
||||
ec = (unsigned char)((esr >> 26) & 0x3fU);
|
||||
enum rt_mm_fault_op fault_op;
|
||||
enum rt_mm_fault_type fault_type;
|
||||
switch (ec)
|
||||
{
|
||||
case 0x20:
|
||||
fault_op = MM_FAULT_OP_EXECUTE;
|
||||
fault_type = _get_type(esr);
|
||||
break;
|
||||
case 0x21:
|
||||
case 0x24:
|
||||
fault_op = MM_FAULT_OP_WRITE;
|
||||
fault_type = _get_type(esr);
|
||||
break;
|
||||
default:
|
||||
fault_op = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fault_op)
|
||||
{
|
||||
asm volatile("mrs %0, far_el1":"=r"(dfar));
|
||||
if (arch_expand_user_stack(dfar))
|
||||
struct rt_mm_fault_msg msg = {
|
||||
.fault_op = fault_op,
|
||||
.fault_type = fault_type,
|
||||
.vaddr = dfar,
|
||||
};
|
||||
if (rt_mm_fault_try_fix(&msg))
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -91,10 +91,11 @@ __start:
|
||||
msr cpacr_el1, x1
|
||||
|
||||
/* clear bss */
|
||||
ldr x1, =__bss_start /* get bss start address */
|
||||
ldr x2, =__bss_end
|
||||
adrp x1, __bss_start /* get bss start address */
|
||||
add x1, x1, #:lo12:__bss_start
|
||||
adrp x2, __bss_end
|
||||
add x1, x1, #:lo12:__bss_end
|
||||
sub x2, x2, x1 /* get bss size */
|
||||
add x1, x1, x9
|
||||
|
||||
and x3, x2, #7 /* x3 is < 7 */
|
||||
ldr x4, =~0x7
|
||||
@@ -140,14 +141,14 @@ __start:
|
||||
orr x1, x1, #(1 << 0) /* M */
|
||||
msr sctlr_el1, x1 /* enable MMU */
|
||||
|
||||
dsb sy
|
||||
isb sy
|
||||
dsb ish
|
||||
isb
|
||||
ic ialluis /* Invalidate all instruction caches in Inner Shareable domain to Point of Unification */
|
||||
dsb sy
|
||||
isb sy
|
||||
dsb ish
|
||||
isb
|
||||
tlbi vmalle1 /* Invalidate all stage 1 translations used at EL1 with the current VMID */
|
||||
dsb sy
|
||||
isb sy
|
||||
dsb ish
|
||||
isb
|
||||
ret
|
||||
|
||||
after_mmu_enable:
|
||||
|
||||
Reference in New Issue
Block a user