Repository navigation
[libcpu][riscv] fix MMU and user fault handling for Smart #11892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,8 @@ | |
| extern long list_thread(void); | ||
| #endif | ||
|
|
||
| void rt_hw_show_register(struct rt_hw_stack_frame *regs); | ||
|
|
||
| #ifdef RT_USING_LWP | ||
| #include <mm_aspace.h> | ||
| #include <lwp.h> | ||
|
|
@@ -46,10 +48,14 @@ static void _check_fault(struct rt_hw_stack_frame *regs, uint32_t pc_adj, char * | |
| { | ||
| rt_thread_t th; | ||
| rt_bool_t is_user_fault = !(regs->xstatus & SR_PP); | ||
| rt_base_t saved_stat = 0; | ||
|
|
||
| if (is_user_fault) | ||
| { | ||
| /* User backtrace and process teardown can acquire sleeping locks. */ | ||
| saved_stat = csr_read_set(CSR_STATUS, SR_IE); | ||
| rt_kprintf("%s! pc = %p\n", info, regs->epc - pc_adj); | ||
| rt_hw_show_register(regs); | ||
| } | ||
|
|
||
| /* User stack backtrace */ | ||
|
|
@@ -65,6 +71,8 @@ static void _check_fault(struct rt_hw_stack_frame *regs, uint32_t pc_adj, char * | |
| lwp_core_dump(regs, pc_adj); | ||
| #endif | ||
| sys_exit_group(-1); | ||
| /* Only reached when there is no LWP to terminate */ | ||
| csr_write(CSR_STATUS, saved_stat); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -296,6 +304,7 @@ void rt_hw_trap(struct rt_hw_stack_frame *regs) | |
| { | ||
| rt_ubase_t xcause = regs->xcause; | ||
| rt_ubase_t tval = csr_read_clear(CSR_TVAL, 0); | ||
| rt_bool_t is_user_fault = !(regs->xstatus & SR_PP); | ||
|
|
||
| /* IRQ */ | ||
| if (xcause & CAUSE_IRQ_FLAG) | ||
|
|
@@ -364,16 +373,23 @@ void rt_hw_trap(struct rt_hw_stack_frame *regs) | |
| case EXC_INST_PAGE_FAULT: | ||
| case EXC_LOAD_PAGE_FAULT: | ||
| case EXC_STORE_PAGE_FAULT: | ||
| #ifdef RT_USING_SMART | ||
| if (!(regs->xstatus & SR_PP) || | ||
| #ifdef RT_USING_SMART | ||
| if (is_user_fault || | ||
| (tval >= USER_VADDR_START && tval < USER_VADDR_TOP)) | ||
| { | ||
| if (user_fault_fixable(regs, xcause, tval)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| /* A failed user mapping must terminate only the LWP. */ | ||
| if (is_user_fault && rt_thread_self()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里用 |
||
| { | ||
| _check_fault(regs, 0, "user fault"); | ||
| return; | ||
| } | ||
| } | ||
| #endif /* RT_USING_SMART */ | ||
| #endif /* RT_USING_SMART */ | ||
|
|
||
| default: | ||
| LOG_E("Unhandle Execption: (%d) %s, TVAL = %p", xcause, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| */ | ||
|
|
||
| #include <rtthread.h> | ||
| #include <rthw.h> | ||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
|
|
||
|
|
@@ -85,6 +86,20 @@ void rt_hw_aspace_switch(rt_aspace_t aspace) | |
| uint32_t hartid = rt_hw_cpu_id(); | ||
| uintptr_t ptr = (uintptr_t)aspace->page_table + (uintptr_t)(hartid * ARCH_PAGE_SIZE); | ||
| uintptr_t page_table = (uintptr_t)rt_kmem_v2p((void *)ptr); | ||
|
|
||
| if (page_table == (uintptr_t)ARCH_MAP_FAILED) | ||
| { | ||
| /* | ||
| * During early K230 bring-up the kernel still runs with low physical | ||
| * pointers after relocation, including MMUTable. The formal kernel | ||
| * aspace does not translate that low pointer yet, but SATP needs the | ||
| * physical page-table address, so use the low address directly. | ||
| */ | ||
| if (ptr < KERNEL_VADDR_START) | ||
| { | ||
| page_table = ptr; | ||
| } | ||
| } | ||
|
Comment on lines
+89
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rt_hw_mmu_setup -> rt_aspace_map_phy_static,应该做好了关于 rt_kernel_space 的映射,包含 MMUTable 所在的内存区域,即使失败应该直接 err 吧。这里 rt_kmem_v2p 返回了 ARCH_MAP_FAILED 也不能把 ptr 直接当成物理地址吧 |
||
| #ifndef RT_USING_SMP | ||
| current_mmu_table = aspace->page_table; | ||
| #else | ||
|
|
@@ -632,14 +647,14 @@ static inline void _init_region(void *vaddr, size_t size) | |
| { | ||
| rt_ioremap_start = vaddr; | ||
| rt_ioremap_size = size; | ||
| rt_mpr_start = rt_ioremap_start - rt_mpr_size; | ||
| rt_mpr_start = (void *)((rt_ubase_t)rt_ioremap_start - rt_mpr_size); | ||
| LOG_D("rt_ioremap_start: %p, rt_mpr_start: %p", rt_ioremap_start, | ||
| rt_mpr_start); | ||
| } | ||
| #else | ||
| static inline void _init_region(void *vaddr, size_t size) | ||
| { | ||
| rt_mpr_start = vaddr - rt_mpr_size; | ||
| rt_mpr_start = (void *)((rt_ubase_t)vaddr - rt_mpr_size); | ||
| } | ||
| #endif | ||
|
|
||
|
|
@@ -1057,6 +1072,9 @@ void rt_hw_mem_setup_early(void *pgtbl, rt_uint64_t hartid) | |
| vs += EARLY_MAP_PAGE_SIZE_2M; | ||
| } | ||
| #endif | ||
| /* flush page table entries from data cache before enabling MMU */ | ||
| rt_hw_cpu_dcache_clean(early_pgtbl, ARCH_PAGE_SIZE); | ||
|
|
||
| /* apply new mapping */ | ||
| asm volatile("sfence.vma x0, x0"); | ||
| write_csr(satp, SATP_BASE | ((size_t)early_pgtbl >> PAGE_OFFSET_BIT)); | ||
|
|
@@ -1078,6 +1096,24 @@ rt_inline int _pgtbl_order(void) | |
| return order; | ||
| } | ||
|
|
||
| #ifdef RT_USING_SMART | ||
| /* | ||
| * Early identity mappings may overlap the user address range. Clear those | ||
| * entries so they are not inherited by a user address space. | ||
| */ | ||
| static void _clear_user_pgtbl_entries(rt_ubase_t *table) | ||
| { | ||
| int i; | ||
| int start_idx = USER_VADDR_START >> VPN2_SHIFT; | ||
| int end_idx = (USER_VADDR_TOP - 1) >> VPN2_SHIFT; | ||
|
|
||
|
Comment on lines
+1107
to
+1109
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 在 a5d9dc8 引入了 SV48/SV57分页机制,可以使用 |
||
| for (i = start_idx; i <= end_idx; i++) | ||
| { | ||
| table[i] = 0; | ||
| } | ||
| } | ||
| #endif /* RT_USING_SMART */ | ||
|
|
||
| /** | ||
| * @brief Creates and initializes a new MMU page table. | ||
| * | ||
|
|
@@ -1111,6 +1147,9 @@ void *rt_hw_mmu_pgtbl_create(void) | |
| rt_ubase_t *dst = (rt_ubase_t *)((rt_ubase_t)mmu_table + | ||
| (rt_ubase_t)(h * ARCH_PAGE_SIZE)); | ||
| rt_memcpy(dst, src, ARCH_PAGE_SIZE); | ||
| #ifdef RT_USING_SMART | ||
| _clear_user_pgtbl_entries(dst); | ||
| #endif | ||
| } | ||
| rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, | ||
| (rt_ubase_t)(1 << order) * ARCH_PAGE_SIZE); | ||
|
|
@@ -1121,6 +1160,11 @@ void *rt_hw_mmu_pgtbl_create(void) | |
| return RT_NULL; | ||
| } | ||
| rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE); | ||
|
|
||
| #ifdef RT_USING_SMART | ||
| _clear_user_pgtbl_entries(mmu_table); | ||
| #endif | ||
|
|
||
| rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); | ||
| #endif | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
熊老师好呀!
sys_exit_group(-1)后面的csr_write按理走不到,IE 会一直开着。是不是先恢复再调更稳?如有误解请指正,谢谢!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里是有意把恢复放在
sys_exit_group()之后的(commit bcde514 仅补充注释说明):sys_exit_group()→lwp_exit()不会返回,csr_write()不会执行;此时保持 IE 开启是必要的:lwp_exit()内部的LWP_LOCK()会调用RT_DEBUG_SCHEDULER_AVAILABLE(1),在 UP + RT_DEBUGING_CONTEXT 下如果中断关闭会直接断言;另外进程 teardown 也可能获取 sleeping lock。lwp_self()为空、sys_exit_group()返回-EINVAL时,csr_write()才会执行并恢复进入前的 sstatus。因此没有把恢复提前,仅在
csr_write()前加了一条注释说明该分支。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
搜噶搜噶