1 /* $OpenBSD: machdep.c,v 1.21 2021/06/18 21:52:47 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se> 5 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/sched.h> 23 #include <sys/proc.h> 24 #include <sys/sysctl.h> 25 #include <sys/reboot.h> 26 #include <sys/mount.h> 27 #include <sys/exec.h> 28 #include <sys/user.h> 29 #include <sys/conf.h> 30 #include <sys/kcore.h> 31 #include <sys/msgbuf.h> 32 #include <sys/buf.h> 33 #include <sys/sensors.h> 34 #include <sys/malloc.h> 35 #include <sys/syscallargs.h> 36 37 #include <net/if.h> 38 #include <uvm/uvm.h> 39 #include <dev/cons.h> 40 #include <dev/ofw/fdt.h> 41 #include <dev/ofw/openfirm.h> 42 #include <machine/param.h> 43 #include <machine/bootconfig.h> 44 #include <machine/bus.h> 45 #include <machine/riscv64var.h> 46 #include <machine/sbi.h> 47 48 #include <machine/db_machdep.h> 49 #include <ddb/db_extern.h> 50 51 #include <dev/acpi/efi.h> 52 53 #include "softraid.h" 54 #if NSOFTRAID > 0 55 #include <dev/softraidvar.h> 56 #endif 57 58 extern vaddr_t virtual_avail; 59 extern uint64_t esym; 60 61 extern char _start[]; 62 63 char *boot_args = NULL; 64 uint8_t *bootmac = NULL; 65 66 int stdout_node; 67 int stdout_speed; 68 69 void (*cpuresetfn)(void); 70 void (*powerdownfn)(void); 71 72 int cold = 1; 73 74 struct vm_map *exec_map = NULL; 75 struct vm_map *phys_map = NULL; 76 77 int physmem; 78 79 caddr_t msgbufaddr; 80 paddr_t msgbufphys; 81 82 struct user *proc0paddr; 83 84 struct uvm_constraint_range dma_constraint = { 0x0, (paddr_t)-1 }; 85 struct uvm_constraint_range *uvm_md_constraints[] = { 86 &dma_constraint, 87 NULL, 88 }; 89 90 /* the following is used externally (sysctl_hw) */ 91 char machine[] = MACHINE; /* from <machine/param.h> */ 92 93 int safepri = 0; 94 95 uint32_t boot_hart; /* The hart we booted on. */ 96 struct cpu_info cpu_info_primary; 97 struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary }; 98 99 uint32_t tb_freq = 1000000; 100 101 struct fdt_reg memreg[VM_PHYSSEG_MAX]; 102 int nmemreg; 103 104 void memreg_add(const struct fdt_reg *); 105 void memreg_remove(const struct fdt_reg *); 106 107 static int 108 atoi(const char *s) 109 { 110 int n, neg; 111 112 n = 0; 113 neg = 0; 114 115 while (*s == '-') { 116 s++; 117 neg = !neg; 118 } 119 120 while (*s != '\0') { 121 if (*s < '0' || *s > '9') 122 break; 123 124 n = (10 * n) + (*s - '0'); 125 s++; 126 } 127 128 return (neg ? -n : n); 129 } 130 131 void * 132 fdt_find_cons(const char *name) 133 { 134 char *alias = "serial0"; 135 char buf[128]; 136 char *stdout = NULL; 137 char *p; 138 void *node; 139 140 /* First check if "stdout-path" is set. */ 141 node = fdt_find_node("/chosen"); 142 if (node) { 143 if (fdt_node_property(node, "stdout-path", &stdout) > 0) { 144 if (strchr(stdout, ':') != NULL) { 145 strlcpy(buf, stdout, sizeof(buf)); 146 if ((p = strchr(buf, ':')) != NULL) { 147 *p++ = '\0'; 148 stdout_speed = atoi(p); 149 } 150 stdout = buf; 151 } 152 if (stdout[0] != '/') { 153 /* It's an alias. */ 154 alias = stdout; 155 stdout = NULL; 156 } 157 } 158 } 159 160 /* Perform alias lookup if necessary. */ 161 if (stdout == NULL) { 162 node = fdt_find_node("/aliases"); 163 if (node) 164 fdt_node_property(node, alias, &stdout); 165 } 166 167 /* Lookup the physical address of the interface. */ 168 if (stdout) { 169 node = fdt_find_node(stdout); 170 if (node && fdt_is_compatible(node, name)) { 171 stdout_node = OF_finddevice(stdout); 172 return (node); 173 } 174 } 175 176 return (NULL); 177 } 178 179 void com_fdt_init_cons(void); 180 void sfuart_init_cons(void); 181 182 void 183 consinit(void) 184 { 185 static int consinit_called = 0; 186 187 if (consinit_called != 0) 188 return; 189 190 consinit_called = 1; 191 192 com_fdt_init_cons(); 193 sfuart_init_cons(); 194 } 195 196 void 197 cpu_idle_enter(void) 198 { 199 } 200 201 void 202 cpu_idle_cycle(void) 203 { 204 // Enable interrupts 205 intr_enable(); 206 // XXX Data Sync Barrier? (Maybe SFENCE???) 207 __asm volatile("wfi"); 208 } 209 210 void 211 cpu_idle_leave(void) 212 { 213 } 214 215 /* Dummy trapframe for proc0. */ 216 struct trapframe proc0tf; 217 218 void 219 cpu_startup(void) 220 { 221 u_int loop; 222 paddr_t minaddr; 223 paddr_t maxaddr; 224 225 proc0.p_addr = proc0paddr; 226 227 /* 228 * Give pmap a chance to set up a few more things now the vm 229 * is initialised 230 */ 231 pmap_postinit(); 232 233 /* 234 * Initialize error message buffer (at end of core). 235 */ 236 237 /* msgbufphys was setup during the secondary boot strap */ 238 for (loop = 0; loop < atop(MSGBUFSIZE); ++loop) 239 pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE, 240 msgbufphys + loop * PAGE_SIZE, PROT_READ | PROT_WRITE); 241 pmap_update(pmap_kernel()); 242 initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); 243 244 /* 245 * Identify ourselves for the msgbuf (everything printed earlier will 246 * not be buffered). 247 */ 248 printf("%s", version); 249 250 printf("real mem = %lu (%luMB)\n", ptoa(physmem), 251 ptoa(physmem) / 1024 / 1024); 252 253 /* 254 * Allocate a submap for exec arguments. This map effectively 255 * limits the number of processes exec'ing at any time. 256 */ 257 minaddr = vm_map_min(kernel_map); 258 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 259 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 260 261 /* 262 * Allocate a submap for physio 263 */ 264 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 265 VM_PHYS_SIZE, 0, FALSE, NULL); 266 267 /* 268 * Set up buffers, so they can be used to read disk labels. 269 */ 270 bufinit(); 271 272 printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free), 273 ptoa(uvmexp.free) / 1024 / 1024); 274 275 curpcb = &proc0.p_addr->u_pcb; 276 curpcb->pcb_flags = 0; 277 curpcb->pcb_tf = &proc0tf; 278 279 if (boothowto & RB_CONFIG) { 280 #ifdef BOOT_CONFIG 281 user_config(); 282 #else 283 printf("kernel does not support -c; continuing..\n"); 284 #endif 285 } 286 } 287 288 /* 289 * Move parts of cpu_switchto into C, too difficult in asm 290 */ 291 292 void cpu_switchto_asm(struct proc *, struct proc *); 293 294 void 295 cpu_switchto(struct proc *old, struct proc *new) 296 { 297 struct cpu_info *ci = curcpu(); 298 struct trapframe *tf; 299 struct pcb *pcb; 300 301 /* old may be NULL, do not save context */ 302 if (old != NULL) { 303 tf = old->p_addr->u_pcb.pcb_tf; 304 if ((tf->tf_sstatus & SSTATUS_FS_MASK) == SSTATUS_FS_DIRTY) { 305 fpu_save(old, tf); 306 } 307 tf->tf_sstatus &= ~SSTATUS_FS_MASK; 308 } 309 310 cpu_switchto_asm(old, new); 311 312 pcb = ci->ci_curpcb; 313 tf = new->p_addr->u_pcb.pcb_tf; 314 #if 0 315 /* XXX this optimization is subtly broken */ 316 if (pcb->pcb_fpcpu == ci && ci->ci_fpuproc == new) { 317 /* If fpu state is already loaded, allow it to be used */ 318 tf->tf_sstatus |= SSTATUS_FS_CLEAN; 319 } 320 #endif 321 } 322 323 /* 324 * machine dependent system variables. 325 */ 326 327 int 328 cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 329 size_t newlen, struct proc *p) 330 { 331 char *compatible; 332 int node, len, error; 333 334 /* all sysctl names at this level are terminal */ 335 if (namelen != 1) 336 return (ENOTDIR); /* overloaded */ 337 338 switch (name[0]) { 339 case CPU_COMPATIBLE: 340 node = OF_finddevice("/"); 341 len = OF_getproplen(node, "compatible"); 342 if (len <= 0) 343 return (EOPNOTSUPP); 344 compatible = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 345 OF_getprop(node, "compatible", compatible, len); 346 compatible[len - 1] = 0; 347 error = sysctl_rdstring(oldp, oldlenp, newp, compatible); 348 free(compatible, M_TEMP, len); 349 return error; 350 default: 351 return (EOPNOTSUPP); 352 } 353 /* NOTREACHED */ 354 } 355 356 int waittime = -1; 357 358 __dead void 359 boot(int howto) 360 { 361 if ((howto & RB_RESET) != 0) 362 goto doreset; 363 364 if (cold) { 365 if ((howto & RB_USERREQ) == 0) 366 howto |= RB_HALT; 367 goto haltsys; 368 } 369 370 boothowto = howto; 371 if ((howto & RB_NOSYNC) == 0 && waittime < 0) { 372 waittime = 0; 373 vfs_shutdown(curproc); 374 375 if ((howto & RB_TIMEBAD) == 0) { 376 resettodr(); 377 } else { 378 printf("WARNING: not updating battery clock\n"); 379 } 380 } 381 if_downall(); 382 383 uvm_shutdown(); 384 splhigh(); 385 cold = 1; 386 387 if ((howto & RB_DUMP) != 0) 388 printf("no dump so far\n"); 389 390 haltsys: 391 config_suspend_all(DVACT_POWERDOWN); 392 393 if ((howto & RB_HALT) != 0) { 394 if ((howto & RB_POWERDOWN) != 0) { 395 printf("\nAttempting to power down...\n"); 396 delay(500000); 397 if (powerdownfn) 398 (*powerdownfn)(); 399 } 400 401 printf("\n"); 402 printf("The operating system has halted.\n"); 403 printf("Please press any key to reboot.\n\n"); 404 cngetc(); 405 } 406 407 doreset: 408 printf("rebooting...\n"); 409 delay(500000); 410 if (cpuresetfn) 411 (*cpuresetfn)(); 412 printf("reboot failed; spinning\n"); 413 for (;;) 414 continue; 415 /* NOTREACHED */ 416 } 417 418 //Copied from ARM64, removed some registers. XXX 419 void 420 setregs(struct proc *p, struct exec_package *pack, u_long stack, 421 register_t *retval) 422 { 423 struct trapframe *tf; 424 425 /* If we were using the FPU, forget about it. */ 426 if (p->p_addr->u_pcb.pcb_fpcpu != NULL) 427 fpu_discard(p); 428 p->p_addr->u_pcb.pcb_flags &= ~PCB_FPU; 429 430 tf = p->p_addr->u_pcb.pcb_tf; 431 432 memset (tf,0, sizeof(*tf)); 433 tf->tf_a[0] = stack; // XXX Inherited from FreeBSD. Why? 434 tf->tf_sp = STACKALIGN(stack); 435 tf->tf_ra = pack->ep_entry; 436 tf->tf_sepc = pack->ep_entry; 437 438 retval[1] = 0; 439 } 440 441 void 442 need_resched(struct cpu_info *ci) 443 { 444 ci->ci_want_resched = 1; 445 446 /* There's a risk we'll be called before the idle threads start */ 447 if (ci->ci_curproc) { 448 aston(ci->ci_curproc); 449 cpu_kick(ci); 450 } 451 } 452 453 454 /* 455 * Size of memory segments, before any memory is stolen. 456 */ 457 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 458 int mem_cluster_cnt; 459 460 /* 461 * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers. 462 */ 463 int 464 cpu_dumpsize(void) 465 { 466 int size; 467 468 size = ALIGN(sizeof(kcore_seg_t)) + 469 ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t)); 470 if (roundup(size, dbtob(1)) != dbtob(1)) 471 return (-1); 472 473 return (1); 474 } 475 476 u_long 477 cpu_dump_mempagecnt(void) 478 { 479 return 0; 480 } 481 482 //Copied from ARM64 483 /* 484 * These variables are needed by /sbin/savecore 485 */ 486 u_long dumpmag = 0x8fca0101; /* magic number */ 487 int dumpsize = 0; /* pages */ 488 long dumplo = 0; /* blocks */ 489 490 /* 491 * This is called by main to set dumplo and dumpsize. 492 * Dumps always skip the first PAGE_SIZE of disk space 493 * in case there might be a disk label stored there. 494 * If there is extra space, put dump at the end to 495 * reduce the chance that swapping trashes it. 496 */ 497 void 498 dumpconf(void) 499 { 500 int nblks, dumpblks; /* size of dump area */ 501 502 if (dumpdev == NODEV || 503 (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0) 504 return; 505 if (nblks <= ctod(1)) 506 return; 507 508 dumpblks = cpu_dumpsize(); 509 if (dumpblks < 0) 510 return; 511 dumpblks += ctod(cpu_dump_mempagecnt()); 512 513 /* If dump won't fit (incl. room for possible label), punt. */ 514 if (dumpblks > (nblks - ctod(1))) 515 return; 516 517 /* Put dump at end of partition */ 518 dumplo = nblks - dumpblks; 519 520 /* dumpsize is in page units, and doesn't include headers. */ 521 dumpsize = cpu_dump_mempagecnt(); 522 } 523 524 //copied from arm64/sys_machdep.h 525 int 526 sys_sysarch(struct proc *p, void *v, register_t *retval) 527 { 528 struct sys_sysarch_args /* { 529 syscallarg(int) op; 530 syscallarg(void *) parms; 531 } */ *uap = v; 532 int error = 0; 533 534 switch (SCARG(uap, op)) { 535 default: 536 error = EINVAL; 537 break; 538 } 539 540 return (error); 541 } 542 543 uint64_t mmap_start; 544 uint32_t mmap_size; 545 uint32_t mmap_desc_size; 546 uint32_t mmap_desc_ver; 547 548 EFI_MEMORY_DESCRIPTOR *mmap; 549 550 void collect_kernel_args(const char *); 551 void process_kernel_args(void); 552 553 int pmap_bootstrap_bs_map(bus_space_tag_t, bus_addr_t, 554 bus_size_t, int, bus_space_handle_t *); 555 556 void 557 initriscv(struct riscv_bootparams *rbp) 558 { 559 long kernbase = (long)_start & ~PAGE_MASK; 560 long kvo = rbp->kern_delta; 561 paddr_t memstart, memend; 562 vaddr_t vstart; 563 void *config = (void *)rbp->dtbp_virt; 564 void *fdt = NULL; 565 paddr_t fdt_start = (paddr_t)rbp->dtbp_phys; 566 size_t fdt_size; 567 EFI_PHYSICAL_ADDRESS system_table = 0; 568 int (*map_func_save)(bus_space_tag_t, bus_addr_t, bus_size_t, int, 569 bus_space_handle_t *); 570 paddr_t ramstart, ramend; 571 paddr_t start, end; 572 int i; 573 574 /* Set the per-CPU pointer. */ 575 __asm volatile("mv tp, %0" :: "r"(&cpu_info_primary)); 576 577 // NOTE that 1GB of ram is mapped in by default in 578 // the bootstrap memory config, so nothing is necessary 579 // until pmap_bootstrap_finalize is called?? 580 581 //NOTE: FDT is already mapped (rbp->dtbp_virt => rbp->dtbp_phys) 582 // Initialize the Flattened Device Tree 583 if (!fdt_init(config) || fdt_get_size(config) == 0) 584 panic("initriscv: no FDT"); 585 fdt_size = fdt_get_size(config); 586 587 struct fdt_reg reg; 588 void *node; 589 590 node = fdt_find_node("/cpus"); 591 if (node != NULL) { 592 char *prop; 593 int len; 594 595 len = fdt_node_property(node, "timebase-frequency", &prop); 596 if (len == sizeof(tb_freq)) 597 tb_freq = bemtoh32((uint32_t *)prop); 598 } 599 600 node = fdt_find_node("/chosen"); 601 if (node != NULL) { 602 char *prop; 603 int len; 604 static uint8_t lladdr[6]; 605 606 len = fdt_node_property(node, "boot-hartid", &prop); 607 if (len == sizeof(boot_hart)) 608 boot_hart = bemtoh32((uint32_t *)prop); 609 610 len = fdt_node_property(node, "bootargs", &prop); 611 if (len > 0) 612 collect_kernel_args(prop); 613 614 len = fdt_node_property(node, "openbsd,boothowto", &prop); 615 if (len == sizeof(boothowto)) 616 boothowto = bemtoh32((uint32_t *)prop); 617 618 len = fdt_node_property(node, "openbsd,bootduid", &prop); 619 if (len == sizeof(bootduid)) 620 memcpy(bootduid, prop, sizeof(bootduid)); 621 622 len = fdt_node_property(node, "openbsd,bootmac", &prop); 623 if (len == sizeof(lladdr)) { 624 memcpy(lladdr, prop, sizeof(lladdr)); 625 bootmac = lladdr; 626 } 627 628 len = fdt_node_property(node, "openbsd,sr-bootuuid", &prop); 629 #if NSOFTRAID > 0 630 if (len == sizeof(sr_bootuuid)) 631 memcpy(&sr_bootuuid, prop, sizeof(sr_bootuuid)); 632 #endif 633 if (len > 0) 634 explicit_bzero(prop, len); 635 636 len = fdt_node_property(node, "openbsd,sr-bootkey", &prop); 637 #if NSOFTRAID > 0 638 if (len == sizeof(sr_bootkey)) 639 memcpy(&sr_bootkey, prop, sizeof(sr_bootkey)); 640 #endif 641 if (len > 0) 642 explicit_bzero(prop, len); 643 644 len = fdt_node_property(node, "openbsd,uefi-mmap-start", &prop); 645 if (len == sizeof(mmap_start)) 646 mmap_start = bemtoh64((uint64_t *)prop); 647 len = fdt_node_property(node, "openbsd,uefi-mmap-size", &prop); 648 if (len == sizeof(mmap_size)) 649 mmap_size = bemtoh32((uint32_t *)prop); 650 len = fdt_node_property(node, "openbsd,uefi-mmap-desc-size", &prop); 651 if (len == sizeof(mmap_desc_size)) 652 mmap_desc_size = bemtoh32((uint32_t *)prop); 653 len = fdt_node_property(node, "openbsd,uefi-mmap-desc-ver", &prop); 654 if (len == sizeof(mmap_desc_ver)) 655 mmap_desc_ver = bemtoh32((uint32_t *)prop); 656 657 len = fdt_node_property(node, "openbsd,uefi-system-table", &prop); 658 if (len == sizeof(system_table)) 659 system_table = bemtoh64((uint64_t *)prop); 660 661 len = fdt_node_property(node, "openbsd,dma-constraint", &prop); 662 if (len == sizeof(dma_constraint)) { 663 dma_constraint.ucr_low = bemtoh64((uint64_t *)prop); 664 dma_constraint.ucr_high = bemtoh64((uint64_t *)prop + 1); 665 } 666 } 667 668 sbi_init(); 669 670 process_kernel_args(); 671 672 /* 673 * Determine physical RAM address range from FDT. 674 */ 675 node = fdt_find_node("/memory"); 676 if (node == NULL) 677 panic("%s: no memory specified", __func__); 678 ramstart = (paddr_t)-1, ramend = 0; 679 for (i = 0; i < VM_PHYSSEG_MAX; i++) { 680 if (fdt_get_reg(node, i, ®)) 681 break; 682 if (reg.size == 0) 683 continue; 684 685 start = reg.addr; 686 end = reg.addr + reg.size; 687 688 if (start < ramstart) 689 ramstart = start; 690 if (end > ramend) 691 ramend = end; 692 693 physmem += atop(ramend - ramstart); 694 } 695 696 /* The bootloader has loaded us into a 64MB block. */ 697 memstart = KERNBASE + kvo; 698 memend = memstart + 64 * 1024 * 1024; 699 700 /* XXX */ 701 kernbase = KERNBASE; 702 703 /* Bootstrap enough of pmap to enter the kernel proper. */ 704 vstart = pmap_bootstrap(kvo, rbp->kern_l1pt, 705 kernbase, esym, memstart, memend, ramstart, ramend); 706 707 proc0paddr = (struct user *)rbp->kern_stack; 708 709 msgbufaddr = (caddr_t)vstart; 710 msgbufphys = pmap_steal_avail(round_page(MSGBUFSIZE), PAGE_SIZE, NULL); 711 vstart += round_page(MSGBUFSIZE); 712 713 zero_page = vstart; 714 vstart += MAXCPUS * PAGE_SIZE; 715 copy_src_page = vstart; 716 vstart += MAXCPUS * PAGE_SIZE; 717 copy_dst_page = vstart; 718 vstart += MAXCPUS * PAGE_SIZE; 719 720 /* Relocate the FDT to safe memory. */ 721 if (fdt_size != 0) { 722 uint32_t csize, size = round_page(fdt_size); 723 paddr_t pa; 724 vaddr_t va; 725 726 pa = pmap_steal_avail(size, PAGE_SIZE, NULL); 727 memcpy((void *)PHYS_TO_DMAP(pa), 728 (void *)PHYS_TO_DMAP(fdt_start), size); 729 for (va = vstart, csize = size; csize > 0; 730 csize -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE) 731 pmap_kenter_pa(va, pa, PROT_READ); 732 733 fdt = (void *)vstart; 734 vstart += size; 735 } 736 737 /* Relocate the EFI memory map too. */ 738 if (mmap_start != 0) { 739 uint32_t csize, size = round_page(mmap_size); 740 paddr_t pa; 741 vaddr_t va; 742 743 pa = pmap_steal_avail(size, PAGE_SIZE, NULL); 744 memcpy((void *)PHYS_TO_DMAP(pa), 745 (void *)PHYS_TO_DMAP(mmap_start), size); 746 for (va = vstart, csize = size; csize > 0; 747 csize -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE) 748 pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE); 749 750 mmap = (void *)vstart; 751 vstart += size; 752 } 753 754 /* No more KVA stealing after this point. */ 755 virtual_avail = vstart; 756 757 /* Now we can reinit the FDT, using the virtual address. */ 758 if (fdt) 759 fdt_init(fdt); 760 761 map_func_save = riscv64_bs_tag._space_map; 762 riscv64_bs_tag._space_map = pmap_bootstrap_bs_map; 763 764 consinit(); 765 766 riscv64_bs_tag._space_map = map_func_save; 767 768 pmap_avail_fixup(); 769 770 uvmexp.pagesize = PAGE_SIZE; 771 uvm_setpagesize(); 772 773 /* Make what's left of the initial 64MB block available to UVM. */ 774 pmap_physload_avail(); 775 776 /* Make all other physical memory available to UVM. */ 777 if (mmap && mmap_desc_ver == EFI_MEMORY_DESCRIPTOR_VERSION) { 778 EFI_MEMORY_DESCRIPTOR *desc = mmap; 779 780 /* 781 * Load all memory marked as EfiConventionalMemory, 782 * EfiBootServicesCode or EfiBootServicesData. 783 * Don't bother with blocks smaller than 64KB. The 784 * initial 64MB memory block should be marked as 785 * EfiLoaderData so it won't be added here. 786 */ 787 for (i = 0; i < mmap_size / mmap_desc_size; i++) { 788 printf("type 0x%x pa 0x%llx va 0x%llx pages 0x%llx attr 0x%llx\n", 789 desc->Type, desc->PhysicalStart, 790 desc->VirtualStart, desc->NumberOfPages, 791 desc->Attribute); 792 if ((desc->Type == EfiConventionalMemory || 793 desc->Type == EfiBootServicesCode || 794 desc->Type == EfiBootServicesData) && 795 desc->NumberOfPages >= 16) { 796 reg.addr = desc->PhysicalStart; 797 reg.size = ptoa(desc->NumberOfPages); 798 memreg_add(®); 799 } 800 desc = NextMemoryDescriptor(desc, mmap_desc_size); 801 } 802 } else { 803 node = fdt_find_node("/memory"); 804 if (node == NULL) 805 panic("%s: no memory specified", __func__); 806 807 for (i = 0; nmemreg < nitems(memreg); i++) { 808 if (fdt_get_reg(node, i, ®)) 809 break; 810 if (reg.size == 0) 811 continue; 812 memreg_add(®); 813 } 814 } 815 816 /* Remove reserved memory. */ 817 node = fdt_find_node("/reserved-memory"); 818 if (node) { 819 for (node = fdt_child_node(node); node; 820 node = fdt_next_node(node)) { 821 if (fdt_get_reg(node, 0, ®)) 822 continue; 823 if (reg.size == 0) 824 continue; 825 memreg_remove(®); 826 } 827 } 828 829 /* Remove the initial 64MB block. */ 830 reg.addr = memstart; 831 reg.size = memend - memstart; 832 memreg_remove(®); 833 834 for (i = 0; i < nmemreg; i++) { 835 paddr_t start = memreg[i].addr; 836 paddr_t end = start + memreg[i].size; 837 838 uvm_page_physload(atop(start), atop(end), 839 atop(start), atop(end), 0); 840 } 841 842 /* 843 * Make sure that we have enough KVA to initialize UVM. In 844 * particular, we need enough KVA to be able to allocate the 845 * vm_page structures. 846 */ 847 pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 1024 * 1024 * 1024 + 848 physmem * sizeof(struct vm_page)); 849 850 #ifdef DDB 851 db_machine_init(); 852 853 /* Firmware doesn't load symbols. */ 854 ddb_init(); 855 856 if (boothowto & RB_KDB) 857 db_enter(); 858 #endif 859 860 softintr_init(); 861 splraise(IPL_IPI); 862 } 863 864 char bootargs[256]; 865 866 void 867 collect_kernel_args(const char *args) 868 { 869 /* Make a local copy of the bootargs */ 870 strlcpy(bootargs, args, sizeof(bootargs)); 871 } 872 873 void 874 process_kernel_args(void) 875 { 876 char *cp = bootargs; 877 878 if (*cp == 0) 879 return; 880 881 /* Skip the kernel image filename */ 882 while (*cp != ' ' && *cp != 0) 883 cp++; 884 885 if (*cp != 0) 886 *cp++ = 0; 887 888 while (*cp == ' ') 889 cp++; 890 891 boot_args = cp; 892 893 printf("bootargs: %s\n", boot_args); 894 895 /* Setup pointer to boot flags */ 896 while (*cp != '-') 897 if (*cp++ == '\0') 898 return; 899 900 while (*cp != 0) { 901 switch (*cp) { 902 case 'a': 903 boothowto |= RB_ASKNAME; 904 break; 905 case 'c': 906 boothowto |= RB_CONFIG; 907 break; 908 case 'd': 909 boothowto |= RB_KDB; 910 break; 911 case 's': 912 boothowto |= RB_SINGLE; 913 break; 914 default: 915 printf("unknown option `%c'\n", *cp); 916 break; 917 } 918 cp++; 919 } 920 } 921 922 /* 923 * Allow bootstrap to steal KVA after machdep has given it back to pmap. 924 */ 925 int 926 pmap_bootstrap_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, 927 int flags, bus_space_handle_t *bshp) 928 { 929 u_long startpa, pa, endpa; 930 vaddr_t va; 931 932 va = virtual_avail; /* steal memory from virtual avail. */ 933 934 startpa = trunc_page(bpa); 935 endpa = round_page((bpa + size)); 936 937 *bshp = (bus_space_handle_t)(va + (bpa - startpa)); 938 939 for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) 940 pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE); 941 942 virtual_avail = va; 943 944 return 0; 945 } 946 947 void 948 memreg_add(const struct fdt_reg *reg) 949 { 950 int i; 951 952 for (i = 0; i < nmemreg; i++) { 953 if (reg->addr == memreg[i].addr + memreg[i].size) { 954 memreg[i].size += reg->size; 955 return; 956 } 957 if (reg->addr + reg->size == memreg[i].addr) { 958 memreg[i].addr = reg->addr; 959 memreg[i].size += reg->size; 960 return; 961 } 962 } 963 964 if (nmemreg >= nitems(memreg)) 965 return; 966 967 memreg[nmemreg++] = *reg; 968 } 969 970 void 971 memreg_remove(const struct fdt_reg *reg) 972 { 973 uint64_t start = reg->addr; 974 uint64_t end = reg->addr + reg->size; 975 int i, j; 976 977 for (i = 0; i < nmemreg; i++) { 978 uint64_t memstart = memreg[i].addr; 979 uint64_t memend = memreg[i].addr + memreg[i].size; 980 981 if (end <= memstart) 982 continue; 983 if (start >= memend) 984 continue; 985 986 if (start <= memstart) 987 memstart = MIN(end, memend); 988 if (end >= memend) 989 memend = MAX(start, memstart); 990 991 if (start > memstart && end < memend) { 992 if (nmemreg < nitems(memreg)) { 993 memreg[nmemreg].addr = end; 994 memreg[nmemreg].size = memend - end; 995 nmemreg++; 996 } 997 memend = start; 998 } 999 memreg[i].addr = memstart; 1000 memreg[i].size = memend - memstart; 1001 } 1002 1003 /* Remove empty slots. */ 1004 for (i = nmemreg - 1; i >= 0; i--) { 1005 if (memreg[i].size == 0) { 1006 for (j = i; (j + 1) < nmemreg; j++) 1007 memreg[j] = memreg[j + 1]; 1008 nmemreg--; 1009 } 1010 } 1011 } 1012