riscv_machdep.c revision 1.17 1 /* $NetBSD: riscv_machdep.c,v 1.17 2022/09/20 06:53:36 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2014, 2019 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33
34 #include "opt_modular.h"
35 __RCSID("$NetBSD: riscv_machdep.c,v 1.17 2022/09/20 06:53:36 skrll Exp $");
36
37 #include <sys/param.h>
38
39 #include <sys/cpu.h>
40 #include <sys/exec.h>
41 #include <sys/kmem.h>
42 #include <sys/ktrace.h>
43 #include <sys/lwp.h>
44 #include <sys/module.h>
45 #include <sys/proc.h>
46 #include <sys/reboot.h>
47 #include <sys/syscall.h>
48 #include <sys/systm.h>
49
50 #include <uvm/uvm_extern.h>
51
52 #include <riscv/locore.h>
53
54 int cpu_printfataltraps;
55 char machine[] = MACHINE;
56 char machine_arch[] = MACHINE_ARCH;
57
58 struct vm_map *phys_map;
59
60 struct trapframe cpu_ddb_regs;
61
62 struct cpu_info cpu_info_store = {
63 .ci_cpl = IPL_HIGH,
64 .ci_ddb_regs = &cpu_ddb_regs,
65 };
66
67 const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
68 #ifdef FPE
69 [PCU_FPU] = &pcu_fpu_ops,
70 #endif
71 };
72
73 void
74 delay(unsigned long us)
75 {
76 const uint32_t cycles_per_us = curcpu()->ci_data.cpu_cc_freq / 1000000;
77 const uint64_t cycles = (uint64_t)us * cycles_per_us;
78 const uint64_t finish = riscvreg_cycle_read() + cycles;
79
80 while (riscvreg_cycle_read() < finish) {
81 /* spin, baby spin */
82 }
83 }
84
85 #ifdef MODULAR
86 /*
87 * Push any modules loaded by the boot loader.
88 */
89 void
90 module_init_md(void)
91 {
92 }
93 #endif /* MODULAR */
94
95 /*
96 * Set registers on exec.
97 * Clear all registers except sp, pc, and t9.
98 * $sp is set to the stack pointer passed in. $pc is set to the entry
99 * point given by the exec_package passed in, as is $t9 (used for PIC
100 * code by the MIPS elf abi).
101 */
102 void
103 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
104 {
105 struct trapframe * const tf = l->l_md.md_utf;
106 struct proc * const p = l->l_proc;
107
108 memset(tf, 0, sizeof(struct trapframe));
109 tf->tf_sp = (intptr_t)stack_align(stack);
110 tf->tf_pc = (intptr_t)pack->ep_entry & ~1;
111 #ifdef _LP64
112 tf->tf_sr = (p->p_flag & PK_32) ? SR_USER32 : SR_USER;
113 #else
114 tf->tf_sr = SR_USER;
115 #endif
116 // Set up arguments for _start(obj, cleanup, ps_strings)
117 tf->tf_a0 = 0; // obj
118 tf->tf_a1 = 0; // cleanup
119 tf->tf_a2 = p->p_psstrp; // ps_strings
120 }
121
122 void
123 md_child_return(struct lwp *l)
124 {
125 struct trapframe * const tf = l->l_md.md_utf;
126
127 tf->tf_a0 = 0;
128 tf->tf_a1 = 1;
129 #ifdef FPE
130 tf->tf_sr &= ~SR_EF; /* Disable FP as we can't be them. */
131 #endif
132 }
133
134 void
135 cpu_spawn_return(struct lwp *l)
136 {
137 userret(l);
138 }
139
140 /*
141 * Start a new LWP
142 */
143 void
144 startlwp(void *arg)
145 {
146 ucontext_t * const uc = arg;
147 lwp_t * const l = curlwp;
148 int error __diagused;
149
150 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
151 KASSERT(error == 0);
152
153 kmem_free(uc, sizeof(ucontext_t));
154 userret(l);
155 }
156
157 // We've worked hard to make sure struct reg and __gregset_t are the same.
158 // Ditto for struct fpreg and fregset_t.
159
160 #ifdef _LP64
161 CTASSERT(sizeof(struct reg) == sizeof(__gregset_t));
162 #endif
163 CTASSERT(sizeof(struct fpreg) == sizeof(__fregset_t));
164
165 void
166 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
167 {
168 const struct trapframe * const tf = l->l_md.md_utf;
169
170 /* Save register context. */
171 *(struct reg *)mcp->__gregs = tf->tf_regs;
172
173 mcp->__private = (intptr_t)l->l_private;
174
175 *flags |= _UC_CPU | _UC_TLSBASE;
176
177 /* Save floating point register context, if any. */
178 KASSERT(l == curlwp);
179 if (fpu_valid_p(l)) {
180 /*
181 * If this process is the current FP owner, dump its
182 * context to the PCB first.
183 */
184 fpu_save(l);
185
186 struct pcb * const pcb = lwp_getpcb(l);
187 *(struct fpreg *)mcp->__fregs = pcb->pcb_fpregs;
188 *flags |= _UC_FPU;
189 }
190 }
191
192 int
193 cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
194 {
195 /*
196 * Verify that at least the PC and SP are user addresses.
197 */
198 if ((intptr_t) mcp->__gregs[_REG_PC] < 0
199 || (intptr_t) mcp->__gregs[_REG_SP] < 0
200 || (mcp->__gregs[_REG_PC] & 1))
201 return EINVAL;
202
203 return 0;
204 }
205
206 int
207 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
208 {
209 struct trapframe * const tf = l->l_md.md_utf;
210 struct proc * const p = l->l_proc;
211 const __greg_t * const gr = mcp->__gregs;
212 int error;
213
214 /* Restore register context, if any. */
215 if (flags & _UC_CPU) {
216 error = cpu_mcontext_validate(l, mcp);
217 if (error)
218 return error;
219
220 /* Save register context. */
221 tf->tf_regs = *(const struct reg *)gr;
222 }
223
224 /* Restore the private thread context */
225 if (flags & _UC_TLSBASE) {
226 lwp_setprivate(l, (void *)(intptr_t)mcp->__private);
227 }
228
229 /* Restore floating point register context, if any. */
230 if (flags & _UC_FPU) {
231 KASSERT(l == curlwp);
232 /* Tell PCU we are replacing the FPU contents. */
233 fpu_replace(l);
234
235 /*
236 * The PCB FP regs struct includes the FP CSR, so use the
237 * proper size of fpreg when copying.
238 */
239 struct pcb * const pcb = lwp_getpcb(l);
240 pcb->pcb_fpregs = *(const struct fpreg *)mcp->__fregs;
241 }
242
243 mutex_enter(p->p_lock);
244 if (flags & _UC_SETSTACK)
245 l->l_sigstk.ss_flags |= SS_ONSTACK;
246 if (flags & _UC_CLRSTACK)
247 l->l_sigstk.ss_flags &= ~SS_ONSTACK;
248 mutex_exit(p->p_lock);
249
250 return (0);
251 }
252
253 void
254 cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags)
255 {
256 KASSERT(kpreempt_disabled());
257
258 if ((flags & RESCHED_KPREEMPT) != 0) {
259 #ifdef __HAVE_PREEMPTION
260 if ((flags & RESCHED_REMOTE) != 0) {
261 cpu_send_ipi(ci, IPI_KPREEMPT);
262 } else {
263 softint_trigger(SOFTINT_KPREEMPT);
264 }
265 #endif
266 return;
267 }
268 if ((flags & RESCHED_REMOTE) != 0) {
269 #ifdef MULTIPROCESSOR
270 cpu_send_ipi(ci, IPI_AST);
271 #endif
272 } else {
273 l->l_md.md_astpending = 1; /* force call to ast() */
274 }
275 }
276
277 void
278 cpu_signotify(struct lwp *l)
279 {
280 KASSERT(kpreempt_disabled());
281 #ifdef __HAVE_FAST_SOFTINTS
282 KASSERT(lwp_locked(l, NULL));
283 #endif
284
285 if (l->l_cpu != curcpu()) {
286 #ifdef MULTIPROCESSOR
287 cpu_send_ipi(ci, IPI_AST);
288 #endif
289 } else {
290 l->l_md.md_astpending = 1; /* force call to ast() */
291 }
292 }
293
294 void
295 cpu_need_proftick(struct lwp *l)
296 {
297 KASSERT(kpreempt_disabled());
298 KASSERT(l->l_cpu == curcpu());
299
300 l->l_pflag |= LP_OWEUPC;
301 l->l_md.md_astpending = 1; /* force call to ast() */
302 }
303
304 void
305 cpu_reboot(int how, char *bootstr)
306 {
307 for (;;) {
308 }
309 }
310
311 void
312 cpu_dumpconf(void)
313 {
314 // TBD!!
315 }
316
317 void
318 cpu_startup(void)
319 {
320 vaddr_t minaddr, maxaddr;
321 char pbuf[9]; /* "99999 MB" */
322
323 /*
324 * Good {morning,afternoon,evening,night}.
325 */
326 printf("%s%s", copyright, version);
327 format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
328 printf("total memory = %s\n", pbuf);
329
330 minaddr = 0;
331 /*
332 * Allocate a submap for physio.
333 */
334 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
335 VM_PHYS_SIZE, 0, FALSE, NULL);
336
337 format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
338 printf("avail memory = %s\n", pbuf);
339 }
340
341 void
342 init_riscv(vaddr_t kernstart, vaddr_t kernend)
343 {
344
345 /* Early VM bootstrap. */
346 pmap_bootstrap();
347 }
348