riscv_machdep.c revision 1.24 1 /* $NetBSD: riscv_machdep.c,v 1.24 2022/11/15 14:33:33 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 2014, 2019, 2022 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, and by Nick Hudson.
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 "opt_modular.h"
33 #include "opt_riscv_debug.h"
34
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: riscv_machdep.c,v 1.24 2022/11/15 14:33:33 simonb Exp $");
37
38 #include <sys/param.h>
39
40 #include <sys/boot_flag.h>
41 #include <sys/cpu.h>
42 #include <sys/exec.h>
43 #include <sys/kmem.h>
44 #include <sys/ktrace.h>
45 #include <sys/lwp.h>
46 #include <sys/module.h>
47 #include <sys/msgbuf.h>
48 #include <sys/proc.h>
49 #include <sys/reboot.h>
50 #include <sys/syscall.h>
51 #include <sys/systm.h>
52
53 #include <dev/cons.h>
54 #include <uvm/uvm_extern.h>
55
56 #include <riscv/locore.h>
57 #include <riscv/machdep.h>
58 #include <riscv/pte.h>
59
60 #include <libfdt.h>
61 #include <dev/fdt/fdtvar.h>
62 #include <dev/fdt/fdt_memory.h>
63
64 int cpu_printfataltraps;
65 char machine[] = MACHINE;
66 char machine_arch[] = MACHINE_ARCH;
67
68 #ifdef VERBOSE_INIT_RISCV
69 #define VPRINTF(...) printf(__VA_ARGS__)
70 #else
71 #define VPRINTF(...) __nothing
72 #endif
73
74 #ifndef FDT_MAX_BOOT_STRING
75 #define FDT_MAX_BOOT_STRING 1024
76 #endif
77
78 char bootargs[FDT_MAX_BOOT_STRING] = "";
79 char *boot_args = NULL;
80
81 static void
82 earlyconsputc(dev_t dev, int c)
83 {
84 uartputc(c);
85 }
86
87 static int
88 earlyconsgetc(dev_t dev)
89 {
90 return uartgetc();
91 }
92
93 static struct consdev earlycons = {
94 .cn_putc = earlyconsputc,
95 .cn_getc = earlyconsgetc,
96 .cn_pollc = nullcnpollc,
97 };
98
99 struct vm_map *phys_map;
100
101 struct trapframe cpu_ddb_regs;
102
103 struct cpu_info cpu_info_store = {
104 .ci_cpl = IPL_HIGH,
105 .ci_ddb_regs = &cpu_ddb_regs,
106 };
107
108 const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
109 #ifdef FPE
110 [PCU_FPU] = &pcu_fpu_ops,
111 #endif
112 };
113
114 /*
115 * Used by PHYSTOV and VTOPHYS -- Will be set be BSS is zeroed so
116 * keep it in data
117 */
118 unsigned long kern_vtopdiff __attribute__((__section__(".data")));
119
120 void
121 delay(unsigned long us)
122 {
123 const uint32_t cycles_per_us = curcpu()->ci_data.cpu_cc_freq / 1000000;
124 const uint64_t cycles = (uint64_t)us * cycles_per_us;
125 const uint64_t finish = csr_cycle_read() + cycles;
126
127 while (csr_cycle_read() < finish) {
128 /* spin, baby spin */
129 }
130 }
131
132 #ifdef MODULAR
133 /*
134 * Push any modules loaded by the boot loader.
135 */
136 void
137 module_init_md(void)
138 {
139 }
140 #endif /* MODULAR */
141
142 /*
143 * Set registers on exec.
144 * Clear all registers except sp, pc, and t9.
145 * $sp is set to the stack pointer passed in. $pc is set to the entry
146 * point given by the exec_package passed in, as is $t9 (used for PIC
147 * code by the MIPS elf abi).
148 */
149 void
150 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
151 {
152 struct trapframe * const tf = l->l_md.md_utf;
153 struct proc * const p = l->l_proc;
154
155 memset(tf, 0, sizeof(struct trapframe));
156 tf->tf_sp = (intptr_t)stack_align(stack);
157 tf->tf_pc = (intptr_t)pack->ep_entry & ~1;
158 #ifdef _LP64
159 tf->tf_sr = (p->p_flag & PK_32) ? SR_USER32 : SR_USER;
160 #else
161 tf->tf_sr = SR_USER;
162 #endif
163 // Set up arguments for _start(obj, cleanup, ps_strings)
164 tf->tf_a0 = 0; // obj
165 tf->tf_a1 = 0; // cleanup
166 tf->tf_a2 = p->p_psstrp; // ps_strings
167 }
168
169 void
170 md_child_return(struct lwp *l)
171 {
172 struct trapframe * const tf = l->l_md.md_utf;
173
174 tf->tf_a0 = 0;
175 tf->tf_a1 = 1;
176 #ifdef FPE
177 tf->tf_sr &= ~SR_EF; /* Disable FP as we can't be them. */
178 #endif
179 }
180
181 void
182 cpu_spawn_return(struct lwp *l)
183 {
184 userret(l);
185 }
186
187 /*
188 * Start a new LWP
189 */
190 void
191 startlwp(void *arg)
192 {
193 ucontext_t * const uc = arg;
194 lwp_t * const l = curlwp;
195 int error __diagused;
196
197 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
198 KASSERT(error == 0);
199
200 kmem_free(uc, sizeof(ucontext_t));
201 userret(l);
202 }
203
204 // We've worked hard to make sure struct reg and __gregset_t are the same.
205 // Ditto for struct fpreg and fregset_t.
206
207 #ifdef _LP64
208 CTASSERT(sizeof(struct reg) == sizeof(__gregset_t));
209 #endif
210 CTASSERT(sizeof(struct fpreg) == sizeof(__fregset_t));
211
212 void
213 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
214 {
215 const struct trapframe * const tf = l->l_md.md_utf;
216
217 /* Save register context. */
218 *(struct reg *)mcp->__gregs = tf->tf_regs;
219
220 mcp->__private = (intptr_t)l->l_private;
221
222 *flags |= _UC_CPU | _UC_TLSBASE;
223
224 /* Save floating point register context, if any. */
225 KASSERT(l == curlwp);
226 if (fpu_valid_p(l)) {
227 /*
228 * If this process is the current FP owner, dump its
229 * context to the PCB first.
230 */
231 fpu_save(l);
232
233 struct pcb * const pcb = lwp_getpcb(l);
234 *(struct fpreg *)mcp->__fregs = pcb->pcb_fpregs;
235 *flags |= _UC_FPU;
236 }
237 }
238
239 int
240 cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
241 {
242 /*
243 * Verify that at least the PC and SP are user addresses.
244 */
245 if ((intptr_t) mcp->__gregs[_REG_PC] < 0
246 || (intptr_t) mcp->__gregs[_REG_SP] < 0
247 || (mcp->__gregs[_REG_PC] & 1))
248 return EINVAL;
249
250 return 0;
251 }
252
253 int
254 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
255 {
256 struct trapframe * const tf = l->l_md.md_utf;
257 struct proc * const p = l->l_proc;
258 const __greg_t * const gr = mcp->__gregs;
259 int error;
260
261 /* Restore register context, if any. */
262 if (flags & _UC_CPU) {
263 error = cpu_mcontext_validate(l, mcp);
264 if (error)
265 return error;
266
267 /* Save register context. */
268 tf->tf_regs = *(const struct reg *)gr;
269 }
270
271 /* Restore the private thread context */
272 if (flags & _UC_TLSBASE) {
273 lwp_setprivate(l, (void *)(intptr_t)mcp->__private);
274 }
275
276 /* Restore floating point register context, if any. */
277 if (flags & _UC_FPU) {
278 KASSERT(l == curlwp);
279 /* Tell PCU we are replacing the FPU contents. */
280 fpu_replace(l);
281
282 /*
283 * The PCB FP regs struct includes the FP CSR, so use the
284 * proper size of fpreg when copying.
285 */
286 struct pcb * const pcb = lwp_getpcb(l);
287 pcb->pcb_fpregs = *(const struct fpreg *)mcp->__fregs;
288 }
289
290 mutex_enter(p->p_lock);
291 if (flags & _UC_SETSTACK)
292 l->l_sigstk.ss_flags |= SS_ONSTACK;
293 if (flags & _UC_CLRSTACK)
294 l->l_sigstk.ss_flags &= ~SS_ONSTACK;
295 mutex_exit(p->p_lock);
296
297 return (0);
298 }
299
300 void
301 cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags)
302 {
303 KASSERT(kpreempt_disabled());
304
305 if ((flags & RESCHED_KPREEMPT) != 0) {
306 #ifdef __HAVE_PREEMPTION
307 if ((flags & RESCHED_REMOTE) != 0) {
308 cpu_send_ipi(ci, IPI_KPREEMPT);
309 } else {
310 softint_trigger(SOFTINT_KPREEMPT);
311 }
312 #endif
313 return;
314 }
315 if ((flags & RESCHED_REMOTE) != 0) {
316 #ifdef MULTIPROCESSOR
317 cpu_send_ipi(ci, IPI_AST);
318 #endif
319 } else {
320 l->l_md.md_astpending = 1; /* force call to ast() */
321 }
322 }
323
324 void
325 cpu_signotify(struct lwp *l)
326 {
327 KASSERT(kpreempt_disabled());
328 #ifdef __HAVE_FAST_SOFTINTS
329 KASSERT(lwp_locked(l, NULL));
330 #endif
331
332 if (l->l_cpu != curcpu()) {
333 #ifdef MULTIPROCESSOR
334 cpu_send_ipi(ci, IPI_AST);
335 #endif
336 } else {
337 l->l_md.md_astpending = 1; /* force call to ast() */
338 }
339 }
340
341 void
342 cpu_need_proftick(struct lwp *l)
343 {
344 KASSERT(kpreempt_disabled());
345 KASSERT(l->l_cpu == curcpu());
346
347 l->l_pflag |= LP_OWEUPC;
348 l->l_md.md_astpending = 1; /* force call to ast() */
349 }
350
351 void
352 cpu_reboot(int how, char *bootstr)
353 {
354 for (;;) {
355 }
356 }
357
358 void
359 cpu_dumpconf(void)
360 {
361 // TBD!!
362 }
363
364 void
365 cpu_startup(void)
366 {
367 vaddr_t minaddr, maxaddr;
368 char pbuf[9]; /* "99999 MB" */
369
370 /*
371 * Good {morning,afternoon,evening,night}.
372 */
373 printf("%s%s", copyright, version);
374 format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
375 printf("total memory = %s\n", pbuf);
376
377 minaddr = 0;
378 /*
379 * Allocate a submap for physio.
380 */
381 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
382 VM_PHYS_SIZE, 0, FALSE, NULL);
383
384 format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
385 printf("avail memory = %s\n", pbuf);
386 }
387
388 static void
389 riscv_init_lwp0_uarea(void)
390 {
391 extern char lwp0uspace[];
392
393 uvm_lwp_setuarea(&lwp0, (vaddr_t)lwp0uspace);
394 memset(&lwp0.l_md, 0, sizeof(lwp0.l_md));
395 memset(lwp_getpcb(&lwp0), 0, sizeof(struct pcb));
396
397 struct trapframe *tf = (struct trapframe *)(lwp0uspace + USPACE) - 1;
398 memset(tf, 0, sizeof(struct trapframe));
399
400 lwp0.l_md.md_utf = lwp0.l_md.md_ktf = tf;
401 }
402
403
404 static void
405 riscv_print_memory(const struct fdt_memory *m, void *arg)
406 {
407
408 VPRINTF("FDT /memory @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
409 m->start, m->end - m->start);
410 }
411
412
413 static void
414 parse_bi_bootargs(char *args)
415 {
416 int howto;
417
418 for (char *cp = args; *cp; cp++) {
419 /* Ignore superfluous '-', if there is one */
420 if (*cp == '-')
421 continue;
422
423 howto = 0;
424 BOOT_FLAG(*cp, howto);
425 if (!howto)
426 printf("bootflag '%c' not recognised\n", *cp);
427 else
428 boothowto |= howto;
429 }
430 }
431
432
433 void
434 init_riscv(register_t hartid, paddr_t dtb)
435 {
436
437 /* set temporally to work printf()/panic() even before consinit() */
438 cn_tab = &earlycons;
439
440 /* Load FDT */
441 const vaddr_t dtbva = VM_KERNEL_DTB_BASE + (dtb & (NBSEG - 1));
442 void *fdt_data = (void *)dtbva;
443 int error = fdt_check_header(fdt_data);
444 if (error != 0)
445 panic("fdt_check_header failed: %s", fdt_strerror(error));
446
447 fdtbus_init(fdt_data);
448
449 #if 0
450 /* Lookup platform specific backend */
451 plat = riscv_fdt_platform();
452 if (plat == NULL)
453 panic("Kernel does not support this device");
454
455 #endif
456 /* Early console may be available, announce ourselves. */
457 VPRINTF("FDT<%p>\n", fdt_data);
458
459 const int chosen = OF_finddevice("/chosen");
460 if (chosen >= 0)
461 OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs));
462 boot_args = bootargs;
463
464 #if 0
465 /*
466 * If stdout-path is specified on the command line, override the
467 * value in /chosen/stdout-path before initializing console.
468 */
469 VPRINTF("stdout\n");
470 fdt_update_stdout_path();
471 #endif
472
473 /*
474 * Done making changes to the FDT.
475 */
476 fdt_pack(fdt_data);
477
478 VPRINTF("consinit ");
479 consinit();
480 VPRINTF("ok\n");
481
482 /* Talk to the user */
483 printf("NetBSD/riscv (fdt) booting ...\n");
484
485 #ifdef BOOT_ARGS
486 char mi_bootargs[] = BOOT_ARGS;
487 parse_bi_bootargs(mi_bootargs);
488 #endif
489
490 /* SPAM me while testing */
491 boothowto |= AB_DEBUG;
492
493 uint64_t memory_start, memory_end;
494 fdt_memory_get(&memory_start, &memory_end);
495
496 fdt_memory_foreach(riscv_print_memory, NULL);
497
498 /* Cannot map memory above largest page number */
499 const uint64_t maxppn = __SHIFTOUT_MASK(PTE_PPN) - 1;
500 const uint64_t memory_limit = ptoa(maxppn);
501
502 if (memory_end > memory_limit) {
503 fdt_memory_remove_range(memory_limit, memory_end);
504 memory_end = memory_limit;
505 }
506
507 uint64_t memory_size __unused = memory_end - memory_start;
508
509 VPRINTF("%s: memory start %" PRIx64 " end %" PRIx64 " (len %"
510 PRIx64 ")\n", __func__, memory_start, memory_end, memory_size);
511
512 /* Perform PT build and VM init */
513 //cpu_kernel_vm_init();
514
515 VPRINTF("bootargs: %s\n", bootargs);
516
517 parse_bi_bootargs(boot_args);
518
519 extern char __kernel_text[];
520 extern char _end[];
521
522 vaddr_t kernstart = trunc_page((vaddr_t)__kernel_text);
523 vaddr_t kernend = round_page((vaddr_t)_end);
524 paddr_t kernstart_phys __unused = KERN_VTOPHYS(kernstart);
525 paddr_t kernend_phys __unused = KERN_VTOPHYS(kernend);
526
527 vaddr_t kernelvmstart;
528
529 vaddr_t kernstart_mega __unused = MEGAPAGE_TRUNC(kernstart);
530 vaddr_t kernend_mega = MEGAPAGE_ROUND(kernend);
531
532 kernelvmstart = kernend_mega;
533
534 #define DPRINTF(v) VPRINTF("%24s = 0x%16lx\n", #v, (unsigned long)v);
535
536 VPRINTF("------------------------------------------\n");
537 DPRINTF(kern_vtopdiff);
538 DPRINTF(memory_start);
539 DPRINTF(memory_end);
540 DPRINTF(memory_size);
541 DPRINTF(kernstart_phys);
542 DPRINTF(kernend_phys)
543 DPRINTF(VM_MIN_KERNEL_ADDRESS);
544 DPRINTF(kernstart_mega);
545 DPRINTF(kernstart);
546 DPRINTF(kernend);
547 DPRINTF(kernend_mega);
548 DPRINTF(VM_MAX_KERNEL_ADDRESS);
549 VPRINTF("------------------------------------------\n");
550
551 #undef DPRINTF
552
553 KASSERT(kernelvmstart < VM_KERNEL_VM_BASE);
554
555 kernelvmstart = VM_KERNEL_VM_BASE;
556
557 /*
558 * msgbuf is allocated from the bottom of any one of memory blocks
559 * to avoid corruption due to bootloader or changing kernel layout.
560 */
561 paddr_t msgbufaddr = 0;
562
563 KASSERT(msgbufaddr != 0); /* no space for msgbuf */
564 #ifdef _LP64
565 initmsgbuf((void *)RISCV_PA_TO_KVA(msgbufaddr), MSGBUFSIZE);
566 #endif
567
568 uvm_md_init();
569
570 pmap_bootstrap(kernelvmstart, VM_MAX_KERNEL_ADDRESS);
571
572 /* Finish setting up lwp0 on our end before we call main() */
573 riscv_init_lwp0_uarea();
574 }
575