xref: /openbsd/sys/arch/riscv64/riscv64/machdep.c (revision 36fde14f)
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, &reg))
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(&reg);
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, &reg))
809 				break;
810 			if (reg.size == 0)
811 				continue;
812 			memreg_add(&reg);
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, &reg))
822 				continue;
823 			if (reg.size == 0)
824 				continue;
825 			memreg_remove(&reg);
826 		}
827 	}
828 
829 	/* Remove the initial 64MB block. */
830 	reg.addr = memstart;
831 	reg.size = memend - memstart;
832 	memreg_remove(&reg);
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