Skip to content

Commit 8a55951

Browse files
committed
[arch][riscv] fix user space entry routine
Looks like some code rot has set in, make sure the user space entry code zeros out the fpu state in the right order. Also make sure the entry asm puts in a memory barrier to make sure the previous write to memory has been performed by the compiler. GCC 15.2 was skipping the stack write until after the asm block. Formatted file while was in there. When taking an exception from kernel space print tp and gp as it currently is, in case that's helpful.
1 parent 8296581 commit 8a55951

2 files changed

Lines changed: 59 additions & 30 deletions

File tree

arch/riscv/arch.c

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
* license that can be found in the LICENSE file or at
66
* https://opensource.org/licenses/MIT
77
*/
8+
#include <arch.h>
9+
#include <arch/mp.h>
10+
#include <arch/ops.h>
11+
#include <arch/riscv.h>
812
#include <assert.h>
9-
#include <lk/trace.h>
1013
#include <lk/debug.h>
11-
#include <stdint.h>
12-
#include <stdlib.h>
13-
#include <arch/riscv.h>
14-
#include <arch/ops.h>
15-
#include <arch/mp.h>
1614
#include <lk/init.h>
1715
#include <lk/main.h>
16+
#include <lk/trace.h>
1817
#include <platform.h>
19-
#include <arch.h>
18+
#include <stdint.h>
19+
#include <stdlib.h>
2020

2121
#include "arch/riscv/feature.h"
2222
#include "riscv_priv.h"
@@ -65,7 +65,7 @@ void riscv_early_init_percpu(void) {
6565
#endif
6666

6767
// enable cycle counter (disabled for now, unimplemented on sifive-e)
68-
//riscv_csr_set(mcounteren, 1);
68+
// riscv_csr_set(mcounteren, 1);
6969
}
7070

7171
// called very early just after entering C code on boot processor
@@ -147,32 +147,41 @@ void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top) {
147147

148148
thread_t *ct = get_current_thread();
149149

150+
// Compute the top of the current thread's kernel stack, aligned to 16 bytes.
150151
vaddr_t kernel_stack_top = (uintptr_t)ct->stack + ct->stack_size;
151152
kernel_stack_top = ROUNDDOWN(kernel_stack_top, 16);
152153

153-
printf("kernel sstatus %#lx\n", riscv_csr_read(sstatus));
154-
155-
// build a user status register
154+
// build the user space sstatus state
156155
ulong status;
157-
status = RISCV_CSR_XSTATUS_PIE |
158-
RISCV_CSR_XSTATUS_SUM;
156+
status = RISCV_CSR_XSTATUS_PIE | // interrupts enabled
157+
RISCV_CSR_XSTATUS_SUM; // keep SUM set for now so we dont have to
158+
// set it when coming from user space.
159159

160-
printf("user sstatus %#lx\n", status);
160+
LTRACEF("kernel sstatus %#lx\n", riscv_csr_read(sstatus));
161+
LTRACEF("user sstatus %#lx\n", status);
161162

163+
#if RISCV_FPU
164+
// Enable FP access before zeroing registers; riscv_fpu_zero() will leave FS in INITIAL.
165+
status |= RISCV_CSR_XSTATUS_FS_CLEAN;
166+
#endif
167+
168+
// Disable interrupts, now we're committed and cannot tolerate any exceptions
169+
// or interrupts until we get to user space.
162170
arch_disable_ints();
163171

164172
riscv_csr_write(sstatus, status);
165173
riscv_csr_write(sepc, entry_point);
166174
riscv_csr_write(sscratch, kernel_stack_top);
167175

168176
#if RISCV_FPU
169-
status |= RISCV_CSR_XSTATUS_FS_INITIAL; // mark fpu state 'initial'
170177
riscv_fpu_zero();
171178
#endif
172179

173180
// put the current tp (percpu pointer) just below the top of the stack
174181
// the exception code will recover it when coming from user space
175182
((uintptr_t *)kernel_stack_top)[-1] = (uintptr_t)riscv_get_percpu();
183+
184+
// jump to user space
176185
asm volatile(
177186
// set the user stack pointer
178187
"mv sp, %0\n"
@@ -207,29 +216,40 @@ void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top) {
207216
"li ra, 0\n"
208217
"li gp, 0\n"
209218
"li tp, 0\n"
210-
"sret"
211-
:: "r" (user_stack_top)
212-
);
219+
"sret" ::"r"(user_stack_top)
220+
: "memory");
213221

214222
__UNREACHABLE;
215223
}
216224
#endif
217225

218226
/* unimplemented cache operations */
219227
#if RISCV_NO_CACHE_OPS
220-
void arch_disable_cache(uint flags) { }
221-
void arch_enable_cache(uint flags) { }
228+
void arch_disable_cache(uint flags) {}
229+
void arch_enable_cache(uint flags) {}
222230

223-
void arch_clean_cache_range(addr_t start, size_t len) { }
224-
void arch_clean_invalidate_cache_range(addr_t start, size_t len) { }
225-
void arch_invalidate_cache_range(addr_t start, size_t len) { }
226-
void arch_sync_cache_range(addr_t start, size_t len) { }
231+
void arch_clean_cache_range(addr_t start, size_t len) {}
232+
void arch_clean_invalidate_cache_range(addr_t start, size_t len) {}
233+
void arch_invalidate_cache_range(addr_t start, size_t len) {}
234+
void arch_sync_cache_range(addr_t start, size_t len) {}
227235
#else
228-
void arch_disable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
229-
void arch_enable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
236+
void arch_disable_cache(uint flags) {
237+
PANIC_UNIMPLEMENTED;
238+
}
239+
void arch_enable_cache(uint flags) {
240+
PANIC_UNIMPLEMENTED;
241+
}
230242

231-
void arch_clean_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
232-
void arch_clean_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
233-
void arch_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
234-
void arch_sync_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
243+
void arch_clean_cache_range(addr_t start, size_t len) {
244+
PANIC_UNIMPLEMENTED;
245+
}
246+
void arch_clean_invalidate_cache_range(addr_t start, size_t len) {
247+
PANIC_UNIMPLEMENTED;
248+
}
249+
void arch_invalidate_cache_range(addr_t start, size_t len) {
250+
PANIC_UNIMPLEMENTED;
251+
}
252+
void arch_sync_cache_range(addr_t start, size_t len) {
253+
PANIC_UNIMPLEMENTED;
254+
}
235255
#endif

arch/riscv/exceptions.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,16 @@ static void dump_iframe(struct riscv_short_iframe *frame, bool kernel) {
7979
printf("t0 %#16lx t1 %#16lx t2 %#16lx t3 %#16lx\n", frame->t0, frame->t1, frame->t2, frame->t3);
8080
printf("t5 %#16lx t6 %#16lx\n", frame->t5, frame->t6);
8181
if (!kernel) {
82+
// Old gp/tp/sp are saved when coming from user space in the iframe
8283
printf("gp %#16lx tp %#16lx sp %#lx\n", frame->gp, frame->tp, frame->sp);
84+
} else {
85+
ulong gp, tp;
86+
87+
asm volatile("mv %0, gp" : "=r"(gp));
88+
asm volatile("mv %0, tp" : "=r"(tp));
89+
90+
// gp/tp/sp are not modified when taking a kernel to kernel exception
91+
printf("gp %#16lx tp %#16lx (from registers)\n", gp, tp);
8392
}
8493
}
8594

0 commit comments

Comments
 (0)