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