1 1.45 thorpej /* $NetBSD: riscv_machdep.c,v 1.45 2025/09/06 22:53:48 thorpej Exp $ */ 2 1.12 skrll 3 1.1 matt /*- 4 1.18 skrll * Copyright (c) 2014, 2019, 2022 The NetBSD Foundation, Inc. 5 1.1 matt * All rights reserved. 6 1.1 matt * 7 1.1 matt * This code is derived from software contributed to The NetBSD Foundation 8 1.18 skrll * by Matt Thomas of 3am Software Foundry, and by Nick Hudson. 9 1.1 matt * 10 1.1 matt * Redistribution and use in source and binary forms, with or without 11 1.1 matt * modification, are permitted provided that the following conditions 12 1.1 matt * are met: 13 1.1 matt * 1. Redistributions of source code must retain the above copyright 14 1.1 matt * notice, this list of conditions and the following disclaimer. 15 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 matt * notice, this list of conditions and the following disclaimer in the 17 1.1 matt * documentation and/or other materials provided with the distribution. 18 1.1 matt * 19 1.1 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 matt * POSSIBILITY OF SUCH DAMAGE. 30 1.1 matt */ 31 1.1 matt 32 1.26 skrll #include "opt_ddb.h" 33 1.18 skrll #include "opt_modular.h" 34 1.29 skrll #include "opt_multiprocessor.h" 35 1.18 skrll #include "opt_riscv_debug.h" 36 1.18 skrll 37 1.1 matt #include <sys/cdefs.h> 38 1.45 thorpej __RCSID("$NetBSD: riscv_machdep.c,v 1.45 2025/09/06 22:53:48 thorpej Exp $"); 39 1.1 matt 40 1.16 skrll #include <sys/param.h> 41 1.1 matt 42 1.26 skrll #include <sys/asan.h> 43 1.18 skrll #include <sys/boot_flag.h> 44 1.1 matt #include <sys/cpu.h> 45 1.1 matt #include <sys/exec.h> 46 1.1 matt #include <sys/kmem.h> 47 1.1 matt #include <sys/ktrace.h> 48 1.16 skrll #include <sys/lwp.h> 49 1.1 matt #include <sys/module.h> 50 1.26 skrll #include <sys/mount.h> 51 1.18 skrll #include <sys/msgbuf.h> 52 1.26 skrll #include <sys/optstr.h> 53 1.1 matt #include <sys/proc.h> 54 1.1 matt #include <sys/reboot.h> 55 1.1 matt #include <sys/syscall.h> 56 1.26 skrll #include <sys/sysctl.h> 57 1.16 skrll #include <sys/systm.h> 58 1.1 matt 59 1.18 skrll #include <dev/cons.h> 60 1.40 skrll #ifdef __HAVE_MM_MD_KERNACC 61 1.40 skrll #include <dev/mm.h> 62 1.40 skrll #endif 63 1.40 skrll 64 1.1 matt #include <uvm/uvm_extern.h> 65 1.1 matt 66 1.26 skrll #include <riscv/frame.h> 67 1.1 matt #include <riscv/locore.h> 68 1.18 skrll #include <riscv/machdep.h> 69 1.18 skrll #include <riscv/pte.h> 70 1.26 skrll #include <riscv/sbi.h> 71 1.39 skrll #include <riscv/userret.h> 72 1.1 matt 73 1.22 skrll #include <libfdt.h> 74 1.22 skrll #include <dev/fdt/fdtvar.h> 75 1.26 skrll #include <dev/fdt/fdt_boot.h> 76 1.45 thorpej #include <dev/fdt/fdt_console.h> 77 1.22 skrll #include <dev/fdt/fdt_memory.h> 78 1.26 skrll #include <dev/fdt/fdt_private.h> 79 1.44 thorpej #include <dev/fdt/fdt_platform.h> 80 1.22 skrll 81 1.26 skrll int cpu_printfataltraps = 1; 82 1.1 matt char machine[] = MACHINE; 83 1.1 matt char machine_arch[] = MACHINE_ARCH; 84 1.1 matt 85 1.18 skrll #ifdef VERBOSE_INIT_RISCV 86 1.20 simonb #define VPRINTF(...) printf(__VA_ARGS__) 87 1.18 skrll #else 88 1.20 simonb #define VPRINTF(...) __nothing 89 1.18 skrll #endif 90 1.18 skrll 91 1.26 skrll /* 64 should be enough, even for a ZFS UUID */ 92 1.26 skrll #define MAX_BOOT_DEV_STR 64 93 1.18 skrll 94 1.26 skrll char bootdevstr[MAX_BOOT_DEV_STR] = ""; 95 1.18 skrll char *boot_args = NULL; 96 1.18 skrll 97 1.26 skrll paddr_t physical_start; 98 1.26 skrll paddr_t physical_end; 99 1.26 skrll 100 1.18 skrll static void 101 1.18 skrll earlyconsputc(dev_t dev, int c) 102 1.18 skrll { 103 1.18 skrll uartputc(c); 104 1.18 skrll } 105 1.18 skrll 106 1.18 skrll static int 107 1.18 skrll earlyconsgetc(dev_t dev) 108 1.18 skrll { 109 1.19 skrll return uartgetc(); 110 1.18 skrll } 111 1.18 skrll 112 1.18 skrll static struct consdev earlycons = { 113 1.18 skrll .cn_putc = earlyconsputc, 114 1.18 skrll .cn_getc = earlyconsgetc, 115 1.18 skrll .cn_pollc = nullcnpollc, 116 1.18 skrll }; 117 1.18 skrll 118 1.1 matt struct vm_map *phys_map; 119 1.1 matt 120 1.1 matt struct trapframe cpu_ddb_regs; 121 1.1 matt const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = { 122 1.14 skrll #ifdef FPE 123 1.1 matt [PCU_FPU] = &pcu_fpu_ops, 124 1.14 skrll #endif 125 1.1 matt }; 126 1.1 matt 127 1.18 skrll /* 128 1.18 skrll * Used by PHYSTOV and VTOPHYS -- Will be set be BSS is zeroed so 129 1.18 skrll * keep it in data 130 1.18 skrll */ 131 1.18 skrll unsigned long kern_vtopdiff __attribute__((__section__(".data"))); 132 1.18 skrll 133 1.26 skrll 134 1.26 skrll /* 135 1.26 skrll * machine dependent system variables. 136 1.26 skrll */ 137 1.26 skrll SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 138 1.26 skrll { 139 1.26 skrll sysctl_createv(clog, 0, NULL, NULL, 140 1.26 skrll CTLFLAG_PERMANENT, 141 1.26 skrll CTLTYPE_NODE, "machdep", NULL, 142 1.26 skrll NULL, 0, NULL, 0, 143 1.26 skrll CTL_MACHDEP, CTL_EOL); 144 1.26 skrll } 145 1.26 skrll 146 1.1 matt #ifdef MODULAR 147 1.1 matt /* 148 1.10 skrll * Push any modules loaded by the boot loader. 149 1.1 matt */ 150 1.1 matt void 151 1.1 matt module_init_md(void) 152 1.1 matt { 153 1.1 matt } 154 1.1 matt #endif /* MODULAR */ 155 1.1 matt 156 1.1 matt /* 157 1.1 matt * Set registers on exec. 158 1.26 skrll * Clear all registers except sp, pc. 159 1.26 skrll * sp is set to the stack pointer passed in. pc is set to the entry 160 1.26 skrll * point given by the exec_package passed in. 161 1.1 matt */ 162 1.1 matt void 163 1.1 matt setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack) 164 1.1 matt { 165 1.1 matt struct trapframe * const tf = l->l_md.md_utf; 166 1.1 matt struct proc * const p = l->l_proc; 167 1.1 matt 168 1.26 skrll memset(tf, 0, sizeof(*tf)); 169 1.1 matt tf->tf_sp = (intptr_t)stack_align(stack); 170 1.1 matt tf->tf_pc = (intptr_t)pack->ep_entry & ~1; 171 1.1 matt #ifdef _LP64 172 1.25 simonb tf->tf_sr = (p->p_flag & PK_32) ? SR_USER32 : SR_USER64; 173 1.1 matt #else 174 1.1 matt tf->tf_sr = SR_USER; 175 1.1 matt #endif 176 1.26 skrll 177 1.26 skrll // Set up arguments for ___start(cleanup, ps_strings) 178 1.26 skrll tf->tf_a0 = 0; // cleanup 179 1.26 skrll tf->tf_a1 = p->p_psstrp; // ps_strings 180 1.26 skrll 181 1.26 skrll /* 182 1.26 skrll * Must have interrupts disabled for exception return. 183 1.26 skrll * Must be switching to user mode. 184 1.26 skrll * Must enable interrupts after sret. 185 1.26 skrll */ 186 1.26 skrll KASSERT(__SHIFTOUT(tf->tf_sr, SR_SIE) == 0); 187 1.26 skrll KASSERT(__SHIFTOUT(tf->tf_sr, SR_SPP) == 0); 188 1.26 skrll KASSERT(__SHIFTOUT(tf->tf_sr, SR_SPIE) != 0); 189 1.1 matt } 190 1.1 matt 191 1.1 matt void 192 1.4 kamil md_child_return(struct lwp *l) 193 1.1 matt { 194 1.26 skrll struct trapframe * const tf = lwp_trapframe(l); 195 1.1 matt 196 1.1 matt tf->tf_a0 = 0; 197 1.1 matt tf->tf_a1 = 1; 198 1.13 skrll #ifdef FPE 199 1.26 skrll /* Disable FP as we can't be using it (yet). */ 200 1.26 skrll tf->tf_sr &= ~SR_FS; 201 1.13 skrll #endif 202 1.26 skrll 203 1.26 skrll /* 204 1.26 skrll * Must have interrupts disabled for exception return. 205 1.26 skrll * Must be switching to user mode. 206 1.26 skrll * Must enable interrupts after sret. 207 1.26 skrll */ 208 1.26 skrll 209 1.26 skrll KASSERT(__SHIFTOUT(tf->tf_sr, SR_SIE) == 0); 210 1.26 skrll KASSERT(__SHIFTOUT(tf->tf_sr, SR_SPP) == 0); 211 1.26 skrll KASSERT(__SHIFTOUT(tf->tf_sr, SR_SPIE) != 0); 212 1.26 skrll 213 1.26 skrll userret(l); 214 1.1 matt } 215 1.1 matt 216 1.38 skrll /* 217 1.38 skrll * Process the tail end of a posix_spawn() for the child. 218 1.38 skrll */ 219 1.1 matt void 220 1.1 matt cpu_spawn_return(struct lwp *l) 221 1.1 matt { 222 1.1 matt userret(l); 223 1.1 matt } 224 1.1 matt 225 1.10 skrll /* 226 1.1 matt * Start a new LWP 227 1.1 matt */ 228 1.1 matt void 229 1.1 matt startlwp(void *arg) 230 1.1 matt { 231 1.1 matt ucontext_t * const uc = arg; 232 1.1 matt lwp_t * const l = curlwp; 233 1.1 matt int error __diagused; 234 1.1 matt 235 1.1 matt error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 236 1.1 matt KASSERT(error == 0); 237 1.1 matt 238 1.26 skrll kmem_free(uc, sizeof(*uc)); 239 1.1 matt userret(l); 240 1.1 matt } 241 1.1 matt 242 1.1 matt // We've worked hard to make sure struct reg and __gregset_t are the same. 243 1.1 matt // Ditto for struct fpreg and fregset_t. 244 1.1 matt 245 1.15 skrll #ifdef _LP64 246 1.1 matt CTASSERT(sizeof(struct reg) == sizeof(__gregset_t)); 247 1.15 skrll #endif 248 1.1 matt CTASSERT(sizeof(struct fpreg) == sizeof(__fregset_t)); 249 1.1 matt 250 1.1 matt void 251 1.1 matt cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags) 252 1.1 matt { 253 1.1 matt const struct trapframe * const tf = l->l_md.md_utf; 254 1.1 matt 255 1.1 matt /* Save register context. */ 256 1.1 matt *(struct reg *)mcp->__gregs = tf->tf_regs; 257 1.1 matt 258 1.1 matt *flags |= _UC_CPU | _UC_TLSBASE; 259 1.1 matt 260 1.1 matt /* Save floating point register context, if any. */ 261 1.1 matt KASSERT(l == curlwp); 262 1.2 chs if (fpu_valid_p(l)) { 263 1.1 matt /* 264 1.1 matt * If this process is the current FP owner, dump its 265 1.1 matt * context to the PCB first. 266 1.1 matt */ 267 1.2 chs fpu_save(l); 268 1.1 matt 269 1.1 matt struct pcb * const pcb = lwp_getpcb(l); 270 1.1 matt *(struct fpreg *)mcp->__fregs = pcb->pcb_fpregs; 271 1.1 matt *flags |= _UC_FPU; 272 1.1 matt } 273 1.1 matt } 274 1.1 matt 275 1.1 matt int 276 1.1 matt cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) 277 1.1 matt { 278 1.1 matt /* 279 1.1 matt * Verify that at least the PC and SP are user addresses. 280 1.1 matt */ 281 1.1 matt if ((intptr_t) mcp->__gregs[_REG_PC] < 0 282 1.1 matt || (intptr_t) mcp->__gregs[_REG_SP] < 0 283 1.1 matt || (mcp->__gregs[_REG_PC] & 1)) 284 1.1 matt return EINVAL; 285 1.1 matt 286 1.1 matt return 0; 287 1.1 matt } 288 1.1 matt 289 1.1 matt int 290 1.1 matt cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) 291 1.1 matt { 292 1.1 matt struct trapframe * const tf = l->l_md.md_utf; 293 1.1 matt struct proc * const p = l->l_proc; 294 1.1 matt const __greg_t * const gr = mcp->__gregs; 295 1.1 matt int error; 296 1.1 matt 297 1.1 matt /* Restore register context, if any. */ 298 1.1 matt if (flags & _UC_CPU) { 299 1.1 matt error = cpu_mcontext_validate(l, mcp); 300 1.1 matt if (error) 301 1.1 matt return error; 302 1.1 matt 303 1.33 rin /* 304 1.33 rin * Avoid updating TLS register here. 305 1.33 rin */ 306 1.33 rin const __greg_t saved_tp = tf->tf_reg[_REG_TP]; 307 1.1 matt tf->tf_regs = *(const struct reg *)gr; 308 1.33 rin tf->tf_reg[_REG_TP] = saved_tp; 309 1.1 matt } 310 1.1 matt 311 1.1 matt /* Restore the private thread context */ 312 1.1 matt if (flags & _UC_TLSBASE) { 313 1.26 skrll lwp_setprivate(l, (void *)(intptr_t)mcp->__gregs[_X_TP]); 314 1.1 matt } 315 1.1 matt 316 1.1 matt /* Restore floating point register context, if any. */ 317 1.1 matt if (flags & _UC_FPU) { 318 1.1 matt KASSERT(l == curlwp); 319 1.1 matt /* Tell PCU we are replacing the FPU contents. */ 320 1.2 chs fpu_replace(l); 321 1.1 matt 322 1.1 matt /* 323 1.1 matt * The PCB FP regs struct includes the FP CSR, so use the 324 1.1 matt * proper size of fpreg when copying. 325 1.1 matt */ 326 1.1 matt struct pcb * const pcb = lwp_getpcb(l); 327 1.1 matt pcb->pcb_fpregs = *(const struct fpreg *)mcp->__fregs; 328 1.1 matt } 329 1.1 matt 330 1.1 matt mutex_enter(p->p_lock); 331 1.1 matt if (flags & _UC_SETSTACK) 332 1.1 matt l->l_sigstk.ss_flags |= SS_ONSTACK; 333 1.1 matt if (flags & _UC_CLRSTACK) 334 1.1 matt l->l_sigstk.ss_flags &= ~SS_ONSTACK; 335 1.1 matt mutex_exit(p->p_lock); 336 1.1 matt 337 1.26 skrll return 0; 338 1.1 matt } 339 1.1 matt 340 1.1 matt void 341 1.6 ad cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags) 342 1.1 matt { 343 1.1 matt KASSERT(kpreempt_disabled()); 344 1.1 matt 345 1.6 ad if ((flags & RESCHED_KPREEMPT) != 0) { 346 1.1 matt #ifdef __HAVE_PREEMPTION 347 1.6 ad if ((flags & RESCHED_REMOTE) != 0) { 348 1.17 skrll cpu_send_ipi(ci, IPI_KPREEMPT); 349 1.6 ad } else { 350 1.1 matt softint_trigger(SOFTINT_KPREEMPT); 351 1.17 skrll } 352 1.1 matt #endif 353 1.1 matt return; 354 1.1 matt } 355 1.6 ad if ((flags & RESCHED_REMOTE) != 0) { 356 1.1 matt #ifdef MULTIPROCESSOR 357 1.1 matt cpu_send_ipi(ci, IPI_AST); 358 1.1 matt #endif 359 1.6 ad } else { 360 1.26 skrll l->l_md.md_astpending = 1; /* force call to ast() */ 361 1.6 ad } 362 1.1 matt } 363 1.1 matt 364 1.1 matt void 365 1.1 matt cpu_signotify(struct lwp *l) 366 1.1 matt { 367 1.1 matt KASSERT(kpreempt_disabled()); 368 1.1 matt #ifdef __HAVE_FAST_SOFTINTS 369 1.1 matt KASSERT(lwp_locked(l, NULL)); 370 1.1 matt #endif 371 1.1 matt 372 1.6 ad if (l->l_cpu != curcpu()) { 373 1.6 ad #ifdef MULTIPROCESSOR 374 1.29 skrll cpu_send_ipi(l->l_cpu, IPI_AST); 375 1.6 ad #endif 376 1.6 ad } else { 377 1.6 ad l->l_md.md_astpending = 1; /* force call to ast() */ 378 1.6 ad } 379 1.1 matt } 380 1.1 matt 381 1.1 matt void 382 1.1 matt cpu_need_proftick(struct lwp *l) 383 1.1 matt { 384 1.1 matt KASSERT(kpreempt_disabled()); 385 1.1 matt KASSERT(l->l_cpu == curcpu()); 386 1.1 matt 387 1.1 matt l->l_pflag |= LP_OWEUPC; 388 1.1 matt l->l_md.md_astpending = 1; /* force call to ast() */ 389 1.1 matt } 390 1.1 matt 391 1.26 skrll 392 1.26 skrll /* Sync the discs, unmount the filesystems, and adjust the todr */ 393 1.26 skrll static void 394 1.26 skrll bootsync(void) 395 1.26 skrll { 396 1.26 skrll static bool bootsyncdone = false; 397 1.26 skrll 398 1.26 skrll if (bootsyncdone) 399 1.26 skrll return; 400 1.26 skrll 401 1.26 skrll bootsyncdone = true; 402 1.26 skrll 403 1.26 skrll /* Make sure we can still manage to do things */ 404 1.26 skrll if ((csr_sstatus_read() & SR_SIE) == 0) { 405 1.26 skrll /* 406 1.26 skrll * If we get here then boot has been called without RB_NOSYNC 407 1.26 skrll * and interrupts were disabled. This means the boot() call 408 1.26 skrll * did not come from a user process e.g. shutdown, but must 409 1.26 skrll * have come from somewhere in the kernel. 410 1.26 skrll */ 411 1.26 skrll ENABLE_INTERRUPTS(); 412 1.26 skrll printf("Warning interrupts disabled during boot()\n"); 413 1.26 skrll } 414 1.26 skrll 415 1.26 skrll vfs_shutdown(); 416 1.26 skrll } 417 1.26 skrll 418 1.26 skrll 419 1.1 matt void 420 1.26 skrll cpu_reboot(int howto, char *bootstr) 421 1.1 matt { 422 1.26 skrll 423 1.26 skrll /* 424 1.26 skrll * If RB_NOSYNC was not specified sync the discs. 425 1.26 skrll * Note: Unless cold is set to 1 here, syslogd will die during the 426 1.26 skrll * unmount. It looks like syslogd is getting woken up only to find 427 1.26 skrll * that it cannot page part of the binary in as the filesystem has 428 1.26 skrll * been unmounted. 429 1.26 skrll */ 430 1.26 skrll if ((howto & RB_NOSYNC) == 0) 431 1.26 skrll bootsync(); 432 1.26 skrll 433 1.26 skrll #if 0 434 1.26 skrll /* Disable interrupts. */ 435 1.26 skrll const int s = splhigh(); 436 1.26 skrll 437 1.26 skrll /* Do a dump if requested. */ 438 1.26 skrll if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 439 1.26 skrll dumpsys(); 440 1.26 skrll 441 1.26 skrll splx(s); 442 1.26 skrll #endif 443 1.26 skrll 444 1.26 skrll pmf_system_shutdown(boothowto); 445 1.26 skrll 446 1.26 skrll /* Say NO to interrupts for good */ 447 1.26 skrll splhigh(); 448 1.26 skrll 449 1.26 skrll /* Run any shutdown hooks */ 450 1.26 skrll doshutdownhooks(); 451 1.26 skrll 452 1.26 skrll /* Make sure IRQ's are disabled */ 453 1.26 skrll DISABLE_INTERRUPTS(); 454 1.26 skrll 455 1.27 skrll if (howto & RB_HALT) { 456 1.27 skrll printf("\n"); 457 1.27 skrll printf("The operating system has halted.\n"); 458 1.27 skrll printf("Please press any key to reboot.\n\n"); 459 1.35 skrll cnpollc(true); /* for proper keyboard command handling */ 460 1.27 skrll if (cngetc() == 0) { 461 1.27 skrll /* no console attached, so just hlt */ 462 1.27 skrll printf("No keyboard - cannot reboot after all.\n"); 463 1.27 skrll goto spin; 464 1.27 skrll } 465 1.35 skrll cnpollc(false); 466 1.27 skrll } 467 1.27 skrll 468 1.27 skrll printf("rebooting...\n"); 469 1.27 skrll 470 1.26 skrll sbi_system_reset(SBI_RESET_TYPE_COLDREBOOT, SBI_RESET_REASON_NONE); 471 1.27 skrll spin: 472 1.1 matt for (;;) { 473 1.26 skrll asm volatile("wfi" ::: "memory"); 474 1.1 matt } 475 1.26 skrll /* NOTREACHED */ 476 1.1 matt } 477 1.1 matt 478 1.1 matt void 479 1.1 matt cpu_dumpconf(void) 480 1.1 matt { 481 1.1 matt // TBD!! 482 1.1 matt } 483 1.1 matt 484 1.26 skrll 485 1.26 skrll int 486 1.26 skrll cpu_lwp_setprivate(lwp_t *l, void *addr) 487 1.26 skrll { 488 1.26 skrll struct trapframe * const tf = lwp_trapframe(l); 489 1.26 skrll 490 1.26 skrll tf->tf_reg[_REG_TP] = (register_t)addr; 491 1.26 skrll 492 1.26 skrll return 0; 493 1.26 skrll } 494 1.26 skrll 495 1.26 skrll 496 1.1 matt void 497 1.1 matt cpu_startup(void) 498 1.1 matt { 499 1.1 matt vaddr_t minaddr, maxaddr; 500 1.26 skrll char pbuf[10]; /* "999999 MB" -- But Sv39 is max 512GB */ 501 1.1 matt 502 1.1 matt /* 503 1.1 matt * Good {morning,afternoon,evening,night}. 504 1.1 matt */ 505 1.1 matt printf("%s%s", copyright, version); 506 1.1 matt format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 507 1.1 matt printf("total memory = %s\n", pbuf); 508 1.1 matt 509 1.1 matt minaddr = 0; 510 1.1 matt /* 511 1.1 matt * Allocate a submap for physio. 512 1.1 matt */ 513 1.1 matt phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 514 1.1 matt VM_PHYS_SIZE, 0, FALSE, NULL); 515 1.1 matt 516 1.11 ad format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false))); 517 1.1 matt printf("avail memory = %s\n", pbuf); 518 1.26 skrll 519 1.29 skrll #ifdef MULTIPROCESSOR 520 1.29 skrll kcpuset_create(&cpus_halted, true); 521 1.29 skrll KASSERT(cpus_halted != NULL); 522 1.29 skrll 523 1.29 skrll kcpuset_create(&cpus_hatched, true); 524 1.29 skrll KASSERT(cpus_hatched != NULL); 525 1.29 skrll 526 1.29 skrll kcpuset_create(&cpus_paused, true); 527 1.29 skrll KASSERT(cpus_paused != NULL); 528 1.29 skrll 529 1.29 skrll kcpuset_create(&cpus_resumed, true); 530 1.29 skrll KASSERT(cpus_resumed != NULL); 531 1.29 skrll 532 1.29 skrll kcpuset_create(&cpus_running, true); 533 1.29 skrll KASSERT(cpus_running != NULL); 534 1.29 skrll 535 1.34 skrll kcpuset_set(cpus_hatched, cpu_index(curcpu())); 536 1.34 skrll kcpuset_set(cpus_running, cpu_index(curcpu())); 537 1.29 skrll #endif 538 1.29 skrll 539 1.26 skrll fdtbus_intr_init(); 540 1.31 rin 541 1.31 rin fdt_setup_rndseed(); 542 1.31 rin fdt_setup_efirng(); 543 1.26 skrll } 544 1.26 skrll 545 1.26 skrll static void 546 1.26 skrll riscv_add_memory(const struct fdt_memory *m, void *arg) 547 1.26 skrll { 548 1.26 skrll paddr_t first = atop(m->start); 549 1.26 skrll paddr_t last = atop(m->end); 550 1.26 skrll int freelist = VM_FREELIST_DEFAULT; 551 1.26 skrll 552 1.26 skrll VPRINTF("adding %#16" PRIxPADDR " - %#16" PRIxPADDR" to freelist %d\n", 553 1.26 skrll m->start, m->end, freelist); 554 1.26 skrll 555 1.26 skrll uvm_page_physload(first, last, first, last, freelist); 556 1.26 skrll physmem += last - first; 557 1.26 skrll } 558 1.26 skrll 559 1.26 skrll 560 1.26 skrll static void 561 1.26 skrll cpu_kernel_vm_init(paddr_t memory_start, paddr_t memory_end) 562 1.26 skrll { 563 1.26 skrll extern char __kernel_text[]; 564 1.26 skrll extern char _end[]; 565 1.26 skrll 566 1.26 skrll vaddr_t kernstart = trunc_page((vaddr_t)__kernel_text); 567 1.26 skrll vaddr_t kernend = round_page((vaddr_t)_end); 568 1.26 skrll paddr_t kernstart_phys = KERN_VTOPHYS(kernstart); 569 1.26 skrll paddr_t kernend_phys = KERN_VTOPHYS(kernend); 570 1.26 skrll 571 1.26 skrll VPRINTF("%s: kernel phys start %#" PRIxPADDR " end %#" PRIxPADDR "\n", 572 1.26 skrll __func__, kernstart_phys, kernend_phys); 573 1.26 skrll fdt_memory_remove_range(kernstart_phys, 574 1.26 skrll kernend_phys - kernstart_phys); 575 1.26 skrll 576 1.43 skrll #if 0 577 1.26 skrll /* 578 1.26 skrll * Don't give these pages to UVM. 579 1.26 skrll * 580 1.26 skrll * cpu_kernel_vm_init need to create proper tables then the following 581 1.26 skrll * will be true. 582 1.26 skrll * 583 1.26 skrll * Now we have APs started the pages used for stacks and L1PT can 584 1.26 skrll * be given to uvm 585 1.26 skrll */ 586 1.26 skrll extern char const __start__init_memory[]; 587 1.26 skrll extern char const __stop__init_memory[] __weak; 588 1.32 mrg if (&__start__init_memory[0] != &__stop__init_memory[0]) { 589 1.26 skrll const paddr_t spa = KERN_VTOPHYS((vaddr_t)__start__init_memory); 590 1.26 skrll const paddr_t epa = KERN_VTOPHYS((vaddr_t)__stop__init_memory); 591 1.26 skrll 592 1.26 skrll VPRINTF("%s: init phys start %#" PRIxPADDR 593 1.26 skrll " end %#" PRIxPADDR "\n", __func__, spa, epa); 594 1.26 skrll fdt_memory_remove_range(spa, epa - spa); 595 1.26 skrll } 596 1.43 skrll #endif 597 1.26 skrll 598 1.26 skrll #ifdef _LP64 599 1.26 skrll paddr_t pa = memory_start & ~XSEGOFSET; 600 1.26 skrll pmap_direct_base = RISCV_DIRECTMAP_START; 601 1.26 skrll extern pd_entry_t l2_pte[PAGE_SIZE / sizeof(pd_entry_t)]; 602 1.26 skrll 603 1.26 skrll 604 1.26 skrll const vsize_t vshift = XSEGSHIFT; 605 1.26 skrll const vaddr_t pdetab_mask = PMAP_PDETABSIZE - 1; 606 1.26 skrll const vsize_t inc = 1UL << vshift; 607 1.26 skrll 608 1.26 skrll const vaddr_t sva = RISCV_DIRECTMAP_START + pa; 609 1.26 skrll const vaddr_t eva = RISCV_DIRECTMAP_END; 610 1.26 skrll const size_t sidx = (sva >> vshift) & pdetab_mask; 611 1.26 skrll const size_t eidx = (eva >> vshift) & pdetab_mask; 612 1.26 skrll 613 1.26 skrll /* Allocate gigapages covering all physical memory in the direct map. */ 614 1.26 skrll for (size_t i = sidx; i < eidx && pa < memory_end; i++, pa += inc) { 615 1.26 skrll l2_pte[i] = PA_TO_PTE(pa) | PTE_KERN | PTE_HARDWIRED | PTE_RW; 616 1.26 skrll VPRINTF("dm: %p : %#" PRIxPADDR "\n", &l2_pte[i], l2_pte[i]); 617 1.26 skrll } 618 1.26 skrll #endif 619 1.26 skrll // pt_dump(printf); 620 1.1 matt } 621 1.1 matt 622 1.18 skrll static void 623 1.18 skrll riscv_init_lwp0_uarea(void) 624 1.18 skrll { 625 1.18 skrll extern char lwp0uspace[]; 626 1.18 skrll 627 1.18 skrll uvm_lwp_setuarea(&lwp0, (vaddr_t)lwp0uspace); 628 1.18 skrll memset(&lwp0.l_md, 0, sizeof(lwp0.l_md)); 629 1.18 skrll memset(lwp_getpcb(&lwp0), 0, sizeof(struct pcb)); 630 1.18 skrll 631 1.18 skrll struct trapframe *tf = (struct trapframe *)(lwp0uspace + USPACE) - 1; 632 1.26 skrll memset(tf, 0, sizeof(*tf)); 633 1.18 skrll 634 1.18 skrll lwp0.l_md.md_utf = lwp0.l_md.md_ktf = tf; 635 1.18 skrll } 636 1.18 skrll 637 1.18 skrll 638 1.18 skrll static void 639 1.18 skrll riscv_print_memory(const struct fdt_memory *m, void *arg) 640 1.18 skrll { 641 1.18 skrll 642 1.18 skrll VPRINTF("FDT /memory @ 0x%" PRIx64 " size 0x%" PRIx64 "\n", 643 1.18 skrll m->start, m->end - m->start); 644 1.18 skrll } 645 1.18 skrll 646 1.18 skrll 647 1.18 skrll static void 648 1.26 skrll parse_mi_bootargs(char *args) 649 1.18 skrll { 650 1.18 skrll int howto; 651 1.26 skrll bool found, start, skipping; 652 1.26 skrll 653 1.26 skrll if (args == NULL) 654 1.26 skrll return; 655 1.18 skrll 656 1.26 skrll start = true; 657 1.26 skrll skipping = false; 658 1.18 skrll for (char *cp = args; *cp; cp++) { 659 1.26 skrll /* check for "words" starting with a "-" only */ 660 1.26 skrll if (start) { 661 1.26 skrll if (*cp == '-') { 662 1.26 skrll skipping = false; 663 1.26 skrll } else { 664 1.26 skrll skipping = true; 665 1.26 skrll } 666 1.26 skrll start = false; 667 1.26 skrll continue; 668 1.26 skrll } 669 1.26 skrll 670 1.26 skrll if (*cp == ' ') { 671 1.26 skrll start = true; 672 1.26 skrll skipping = false; 673 1.26 skrll continue; 674 1.26 skrll } 675 1.26 skrll 676 1.26 skrll if (skipping) { 677 1.18 skrll continue; 678 1.26 skrll } 679 1.18 skrll 680 1.26 skrll /* Check valid boot flags */ 681 1.18 skrll howto = 0; 682 1.18 skrll BOOT_FLAG(*cp, howto); 683 1.18 skrll if (!howto) 684 1.18 skrll printf("bootflag '%c' not recognised\n", *cp); 685 1.18 skrll else 686 1.18 skrll boothowto |= howto; 687 1.18 skrll } 688 1.26 skrll 689 1.26 skrll found = optstr_get(args, "root", bootdevstr, sizeof(bootdevstr)); 690 1.26 skrll if (found) { 691 1.26 skrll bootspec = bootdevstr; 692 1.26 skrll } 693 1.18 skrll } 694 1.18 skrll 695 1.18 skrll 696 1.1 matt void 697 1.21 skrll init_riscv(register_t hartid, paddr_t dtb) 698 1.1 matt { 699 1.9 thorpej 700 1.18 skrll /* set temporally to work printf()/panic() even before consinit() */ 701 1.18 skrll cn_tab = &earlycons; 702 1.18 skrll 703 1.18 skrll /* Load FDT */ 704 1.21 skrll const vaddr_t dtbva = VM_KERNEL_DTB_BASE + (dtb & (NBSEG - 1)); 705 1.21 skrll void *fdt_data = (void *)dtbva; 706 1.18 skrll int error = fdt_check_header(fdt_data); 707 1.18 skrll if (error != 0) 708 1.18 skrll panic("fdt_check_header failed: %s", fdt_strerror(error)); 709 1.18 skrll 710 1.18 skrll fdtbus_init(fdt_data); 711 1.18 skrll 712 1.18 skrll /* Lookup platform specific backend */ 713 1.29 skrll const struct fdt_platform * const plat = fdt_platform_find(); 714 1.18 skrll if (plat == NULL) 715 1.18 skrll panic("Kernel does not support this device"); 716 1.18 skrll 717 1.18 skrll /* Early console may be available, announce ourselves. */ 718 1.18 skrll VPRINTF("FDT<%p>\n", fdt_data); 719 1.18 skrll 720 1.30 rin boot_args = fdt_get_bootargs(); 721 1.18 skrll 722 1.26 skrll VPRINTF("devmap %p\n", plat->fp_devmap()); 723 1.26 skrll pmap_devmap_bootstrap(0, plat->fp_devmap()); 724 1.26 skrll 725 1.26 skrll VPRINTF("bootstrap\n"); 726 1.26 skrll plat->fp_bootstrap(); 727 1.26 skrll 728 1.18 skrll /* 729 1.18 skrll * If stdout-path is specified on the command line, override the 730 1.18 skrll * value in /chosen/stdout-path before initializing console. 731 1.18 skrll */ 732 1.18 skrll VPRINTF("stdout\n"); 733 1.26 skrll fdt_update_stdout_path(fdt_data, boot_args); 734 1.18 skrll 735 1.18 skrll /* 736 1.18 skrll * Done making changes to the FDT. 737 1.18 skrll */ 738 1.18 skrll fdt_pack(fdt_data); 739 1.18 skrll 740 1.26 skrll const uint32_t dtbsize = round_page(fdt_totalsize(fdt_data)); 741 1.26 skrll 742 1.26 skrll VPRINTF("fdt size %x/%x\n", dtbsize, fdt_totalsize(fdt_data)); 743 1.26 skrll 744 1.18 skrll VPRINTF("consinit "); 745 1.18 skrll consinit(); 746 1.18 skrll VPRINTF("ok\n"); 747 1.18 skrll 748 1.18 skrll /* Talk to the user */ 749 1.18 skrll printf("NetBSD/riscv (fdt) booting ...\n"); 750 1.18 skrll 751 1.18 skrll #ifdef BOOT_ARGS 752 1.18 skrll char mi_bootargs[] = BOOT_ARGS; 753 1.26 skrll parse_mi_bootargs(mi_bootargs); 754 1.18 skrll #endif 755 1.18 skrll 756 1.18 skrll uint64_t memory_start, memory_end; 757 1.18 skrll fdt_memory_get(&memory_start, &memory_end); 758 1.26 skrll physical_start = memory_start; 759 1.26 skrll physical_end = memory_end; 760 1.18 skrll 761 1.18 skrll fdt_memory_foreach(riscv_print_memory, NULL); 762 1.18 skrll 763 1.18 skrll /* Cannot map memory above largest page number */ 764 1.18 skrll const uint64_t maxppn = __SHIFTOUT_MASK(PTE_PPN) - 1; 765 1.18 skrll const uint64_t memory_limit = ptoa(maxppn); 766 1.18 skrll 767 1.18 skrll if (memory_end > memory_limit) { 768 1.18 skrll fdt_memory_remove_range(memory_limit, memory_end); 769 1.18 skrll memory_end = memory_limit; 770 1.18 skrll } 771 1.18 skrll 772 1.18 skrll uint64_t memory_size __unused = memory_end - memory_start; 773 1.18 skrll 774 1.18 skrll VPRINTF("%s: memory start %" PRIx64 " end %" PRIx64 " (len %" 775 1.18 skrll PRIx64 ")\n", __func__, memory_start, memory_end, memory_size); 776 1.18 skrll 777 1.31 rin /* Parse ramdisk, rndseed, and firmware's RNG from EFI */ 778 1.31 rin fdt_probe_initrd(); 779 1.31 rin fdt_probe_rndseed(); 780 1.31 rin fdt_probe_efirng(); 781 1.31 rin 782 1.26 skrll fdt_memory_remove_reserved(memory_start, memory_end); 783 1.26 skrll 784 1.28 skrll fdt_memory_remove_range(dtb, dtbsize); 785 1.31 rin fdt_reserve_initrd(); 786 1.31 rin fdt_reserve_rndseed(); 787 1.31 rin fdt_reserve_efirng(); 788 1.26 skrll 789 1.18 skrll /* Perform PT build and VM init */ 790 1.26 skrll cpu_kernel_vm_init(memory_start, memory_end); 791 1.18 skrll 792 1.30 rin VPRINTF("bootargs: %s\n", boot_args); 793 1.18 skrll 794 1.26 skrll parse_mi_bootargs(boot_args); 795 1.26 skrll 796 1.26 skrll #ifdef DDB 797 1.26 skrll if (boothowto & RB_KDB) { 798 1.26 skrll printf("Entering DDB...\n"); 799 1.26 skrll cpu_Debugger(); 800 1.26 skrll } 801 1.26 skrll #endif 802 1.18 skrll 803 1.18 skrll extern char __kernel_text[]; 804 1.18 skrll extern char _end[]; 805 1.26 skrll // extern char __data_start[]; 806 1.26 skrll // extern char __rodata_start[]; 807 1.18 skrll 808 1.18 skrll vaddr_t kernstart = trunc_page((vaddr_t)__kernel_text); 809 1.18 skrll vaddr_t kernend = round_page((vaddr_t)_end); 810 1.18 skrll paddr_t kernstart_phys __unused = KERN_VTOPHYS(kernstart); 811 1.18 skrll paddr_t kernend_phys __unused = KERN_VTOPHYS(kernend); 812 1.18 skrll 813 1.18 skrll vaddr_t kernelvmstart; 814 1.18 skrll 815 1.18 skrll vaddr_t kernstart_mega __unused = MEGAPAGE_TRUNC(kernstart); 816 1.18 skrll vaddr_t kernend_mega = MEGAPAGE_ROUND(kernend); 817 1.18 skrll 818 1.18 skrll kernelvmstart = kernend_mega; 819 1.18 skrll 820 1.26 skrll #if 0 821 1.26 skrll #ifdef MODULAR 822 1.26 skrll #define MODULE_RESERVED_MAX (1024 * 1024 * 128) 823 1.26 skrll #define MODULE_RESERVED_SIZE (1024 * 1024 * 32) /* good enough? */ 824 1.26 skrll module_start = kernelvmstart; 825 1.26 skrll module_end = kernend_mega + MODULE_RESERVED_SIZE; 826 1.26 skrll if (module_end >= kernstart_mega + MODULE_RESERVED_MAX) 827 1.26 skrll module_end = kernstart_mega + MODULE_RESERVED_MAX; 828 1.26 skrll KASSERT(module_end > kernend_mega); 829 1.26 skrll kernelvmstart = module_end; 830 1.26 skrll #endif /* MODULAR */ 831 1.26 skrll #endif 832 1.26 skrll KASSERT(kernelvmstart < VM_KERNEL_VM_BASE); 833 1.26 skrll 834 1.26 skrll kernelvmstart = VM_KERNEL_VM_BASE; 835 1.26 skrll 836 1.26 skrll /* 837 1.26 skrll * msgbuf is allocated from the top of the last biggest memory block. 838 1.26 skrll */ 839 1.26 skrll paddr_t msgbufaddr = 0; 840 1.26 skrll 841 1.26 skrll #ifdef _LP64 842 1.26 skrll /* XXX check all ranges for last one with a big enough hole */ 843 1.26 skrll msgbufaddr = memory_end - MSGBUFSIZE; 844 1.26 skrll KASSERT(msgbufaddr != 0); /* no space for msgbuf */ 845 1.26 skrll fdt_memory_remove_range(msgbufaddr, msgbufaddr + MSGBUFSIZE); 846 1.26 skrll msgbufaddr = RISCV_PA_TO_KVA(msgbufaddr); 847 1.26 skrll VPRINTF("msgbufaddr = %#lx\n", msgbufaddr); 848 1.26 skrll initmsgbuf((void *)msgbufaddr, MSGBUFSIZE); 849 1.26 skrll #endif 850 1.26 skrll 851 1.26 skrll KASSERT(msgbufaddr != 0); /* no space for msgbuf */ 852 1.26 skrll #ifdef _LP64 853 1.26 skrll initmsgbuf((void *)RISCV_PA_TO_KVA(msgbufaddr), MSGBUFSIZE); 854 1.26 skrll #endif 855 1.26 skrll 856 1.20 simonb #define DPRINTF(v) VPRINTF("%24s = 0x%16lx\n", #v, (unsigned long)v); 857 1.18 skrll 858 1.18 skrll VPRINTF("------------------------------------------\n"); 859 1.18 skrll DPRINTF(kern_vtopdiff); 860 1.18 skrll DPRINTF(memory_start); 861 1.18 skrll DPRINTF(memory_end); 862 1.18 skrll DPRINTF(memory_size); 863 1.18 skrll DPRINTF(kernstart_phys); 864 1.18 skrll DPRINTF(kernend_phys) 865 1.26 skrll DPRINTF(msgbufaddr); 866 1.26 skrll // DPRINTF(physical_end); 867 1.18 skrll DPRINTF(VM_MIN_KERNEL_ADDRESS); 868 1.18 skrll DPRINTF(kernstart_mega); 869 1.18 skrll DPRINTF(kernstart); 870 1.18 skrll DPRINTF(kernend); 871 1.18 skrll DPRINTF(kernend_mega); 872 1.26 skrll #if 0 873 1.26 skrll #ifdef MODULAR 874 1.26 skrll DPRINTF(module_start); 875 1.26 skrll DPRINTF(module_end); 876 1.26 skrll #endif 877 1.26 skrll #endif 878 1.18 skrll DPRINTF(VM_MAX_KERNEL_ADDRESS); 879 1.26 skrll #ifdef _LP64 880 1.26 skrll DPRINTF(pmap_direct_base); 881 1.26 skrll #endif 882 1.18 skrll VPRINTF("------------------------------------------\n"); 883 1.18 skrll 884 1.18 skrll #undef DPRINTF 885 1.18 skrll 886 1.26 skrll uvm_md_init(); 887 1.18 skrll 888 1.18 skrll /* 889 1.26 skrll * pass memory pages to uvm 890 1.18 skrll */ 891 1.26 skrll physmem = 0; 892 1.26 skrll fdt_memory_foreach(riscv_add_memory, NULL); 893 1.26 skrll 894 1.26 skrll pmap_bootstrap(kernelvmstart, VM_MAX_KERNEL_ADDRESS); 895 1.26 skrll 896 1.26 skrll kasan_init(); 897 1.26 skrll 898 1.26 skrll /* Finish setting up lwp0 on our end before we call main() */ 899 1.26 skrll riscv_init_lwp0_uarea(); 900 1.29 skrll 901 1.29 skrll 902 1.29 skrll error = 0; 903 1.29 skrll if ((boothowto & RB_MD1) == 0) { 904 1.29 skrll VPRINTF("mpstart\n"); 905 1.29 skrll if (plat->fp_mpstart) 906 1.29 skrll error = plat->fp_mpstart(); 907 1.29 skrll } 908 1.29 skrll if (error) 909 1.29 skrll printf("AP startup problems\n"); 910 1.26 skrll } 911 1.26 skrll 912 1.26 skrll 913 1.40 skrll #ifdef __HAVE_MM_MD_KERNACC 914 1.42 skrll 915 1.42 skrll #define IN_RANGE_P(addr, start, end) (start) <= (addr) && (addr) < (end) 916 1.42 skrll #ifdef _LP64 917 1.42 skrll #define IN_DIRECTMAP_P(va) \ 918 1.42 skrll IN_RANGE_P(va, RISCV_DIRECTMAP_START, RISCV_DIRECTMAP_END) 919 1.42 skrll #else 920 1.42 skrll #define IN_DIRECTMAP_P(va) false 921 1.42 skrll #endif 922 1.42 skrll 923 1.40 skrll int 924 1.40 skrll mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled) 925 1.40 skrll { 926 1.40 skrll extern char __kernel_text[]; 927 1.40 skrll extern char _end[]; 928 1.40 skrll extern char __data_start[]; 929 1.40 skrll 930 1.40 skrll const vaddr_t kernstart = trunc_page((vaddr_t)__kernel_text); 931 1.40 skrll const vaddr_t kernend = round_page((vaddr_t)_end); 932 1.40 skrll const vaddr_t data_start = (vaddr_t)__data_start; 933 1.40 skrll 934 1.40 skrll const vaddr_t va = (vaddr_t)ptr; 935 1.40 skrll 936 1.40 skrll *handled = false; 937 1.40 skrll if (IN_RANGE_P(va, kernstart, kernend)) { 938 1.40 skrll *handled = true; 939 1.40 skrll if (va < data_start && (prot & VM_PROT_WRITE) != 0) { 940 1.40 skrll return EFAULT; 941 1.40 skrll } 942 1.42 skrll } else if (IN_DIRECTMAP_P(va)) { 943 1.40 skrll *handled = true; 944 1.40 skrll } 945 1.40 skrll 946 1.40 skrll return 0; 947 1.40 skrll } 948 1.40 skrll #endif 949 1.40 skrll 950 1.40 skrll 951 1.26 skrll #ifdef _LP64 952 1.26 skrll static void 953 1.26 skrll pte_bits(void (*pr)(const char *, ...), pt_entry_t pte) 954 1.26 skrll { 955 1.26 skrll (*pr)("%c%c%c%c%c%c%c%c", 956 1.26 skrll (pte & PTE_D) ? 'D' : '.', 957 1.26 skrll (pte & PTE_A) ? 'A' : '.', 958 1.26 skrll (pte & PTE_G) ? 'G' : '.', 959 1.26 skrll (pte & PTE_U) ? 'U' : '.', 960 1.26 skrll (pte & PTE_X) ? 'X' : '.', 961 1.26 skrll (pte & PTE_W) ? 'W' : '.', 962 1.26 skrll (pte & PTE_R) ? 'R' : '.', 963 1.26 skrll (pte & PTE_V) ? 'V' : '.'); 964 1.26 skrll } 965 1.26 skrll 966 1.26 skrll static void 967 1.26 skrll dump_ln_table(paddr_t pdp_pa, int topbit, int level, vaddr_t va, 968 1.26 skrll void (*pr)(const char *, ...) __printflike(1, 2)) 969 1.26 skrll { 970 1.26 skrll pd_entry_t *pdp = (void *)PMAP_DIRECT_MAP(pdp_pa); 971 1.26 skrll 972 1.26 skrll (*pr)("l%u @ pa %#16" PRIxREGISTER "\n", level, pdp_pa); 973 1.26 skrll for (size_t i = 0; i < PAGE_SIZE / sizeof(pd_entry_t); i++) { 974 1.26 skrll pd_entry_t entry = pdp[i]; 975 1.26 skrll 976 1.26 skrll if (topbit) { 977 1.26 skrll va = i << (PGSHIFT + level * SEGLENGTH); 978 1.26 skrll if (va & __BIT(topbit)) { 979 1.26 skrll va |= __BITS(63, topbit); 980 1.26 skrll } 981 1.26 skrll } 982 1.26 skrll if (entry != 0) { 983 1.26 skrll paddr_t pa = __SHIFTOUT(entry, PTE_PPN) << PGSHIFT; 984 1.26 skrll // check level PPN bits. 985 1.26 skrll if (PTE_ISLEAF_P(entry)) { 986 1.26 skrll (*pr)("l%u %3zu va 0x%016lx pa 0x%012lx - ", 987 1.26 skrll level, i, va, pa); 988 1.26 skrll pte_bits(pr, entry); 989 1.26 skrll (*pr)("\n"); 990 1.26 skrll } else { 991 1.26 skrll (*pr)("l%u %3zu va 0x%016lx -> 0x%012lx - ", 992 1.26 skrll level, i, va, pa); 993 1.26 skrll pte_bits(pr, entry); 994 1.26 skrll (*pr)("\n"); 995 1.26 skrll if (level == 0) { 996 1.26 skrll (*pr)("wtf\n"); 997 1.26 skrll continue; 998 1.26 skrll } 999 1.26 skrll if (pte_pde_valid_p(entry)) 1000 1.26 skrll dump_ln_table(pa, 0, level - 1, va, pr); 1001 1.26 skrll } 1002 1.26 skrll } 1003 1.26 skrll va += 1UL << (PGSHIFT + level * SEGLENGTH); 1004 1.26 skrll } 1005 1.26 skrll } 1006 1.26 skrll 1007 1.26 skrll void 1008 1.26 skrll pt_dump(void (*pr)(const char *, ...) __printflike(1, 2)) 1009 1.26 skrll { 1010 1.26 skrll const register_t satp = csr_satp_read(); 1011 1.26 skrll size_t topbit = sizeof(long) * NBBY - 1; 1012 1.26 skrll 1013 1.26 skrll #ifdef _LP64 1014 1.26 skrll const paddr_t satp_pa = __SHIFTOUT(satp, SATP_PPN) << PGSHIFT; 1015 1.26 skrll const uint8_t mode = __SHIFTOUT(satp, SATP_MODE); 1016 1.26 skrll u_int level = 1; 1017 1.26 skrll 1018 1.26 skrll switch (mode) { 1019 1.26 skrll case SATP_MODE_SV39: 1020 1.26 skrll case SATP_MODE_SV48: 1021 1.26 skrll topbit = (39 - 1) + (mode - 8) * SEGLENGTH; 1022 1.26 skrll level = mode - 6; 1023 1.26 skrll break; 1024 1.26 skrll } 1025 1.26 skrll #endif 1026 1.26 skrll (*pr)("topbit = %zu\n", topbit); 1027 1.18 skrll 1028 1.26 skrll (*pr)("satp = 0x%" PRIxREGISTER "\n", satp); 1029 1.18 skrll #ifdef _LP64 1030 1.26 skrll dump_ln_table(satp_pa, topbit, level, 0, pr); 1031 1.18 skrll #endif 1032 1.26 skrll } 1033 1.29 skrll #endif 1034 1.26 skrll 1035 1.26 skrll void 1036 1.26 skrll consinit(void) 1037 1.26 skrll { 1038 1.26 skrll static bool initialized = false; 1039 1.26 skrll const struct fdt_console *cons = fdtbus_get_console(); 1040 1.26 skrll const struct fdt_platform *plat = fdt_platform_find(); 1041 1.18 skrll 1042 1.26 skrll if (initialized || cons == NULL) 1043 1.26 skrll return; 1044 1.26 skrll 1045 1.26 skrll u_int uart_freq = 0; 1046 1.26 skrll extern struct bus_space riscv_generic_bs_tag; 1047 1.26 skrll struct fdt_attach_args faa = { 1048 1.26 skrll .faa_bst = &riscv_generic_bs_tag, 1049 1.26 skrll }; 1050 1.26 skrll 1051 1.26 skrll faa.faa_phandle = fdtbus_get_stdout_phandle(); 1052 1.26 skrll if (plat->fp_uart_freq != NULL) 1053 1.26 skrll uart_freq = plat->fp_uart_freq(); 1054 1.18 skrll 1055 1.26 skrll cons->consinit(&faa, uart_freq); 1056 1.18 skrll 1057 1.26 skrll initialized = true; 1058 1.1 matt } 1059