xref: /openbsd-src/sys/arch/riscv64/riscv64/machdep.c (revision b0d2811898b6af5f105845a12bf9d62865077da0)
1 /*	$OpenBSD: machdep.c,v 1.40 2024/11/18 05:32:39 jsg 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_extern.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/sbi.h>
46 #include <machine/sysarch.h>
47 
48 #include <machine/db_machdep.h>
49 #include <ddb/db_extern.h>
50 
51 #include <dev/efi/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 uint64_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_cycle(void)
198 {
199 	// Enable interrupts
200 	intr_enable();
201 	// XXX Data Sync Barrier? (Maybe SFENCE???)
202 	__asm volatile("wfi");
203 }
204 
205 /* Dummy trapframe for proc0. */
206 struct trapframe proc0tf;
207 
208 void
209 cpu_startup(void)
210 {
211 	u_int loop;
212 	paddr_t minaddr;
213 	paddr_t maxaddr;
214 
215 	proc0.p_addr = proc0paddr;
216 
217 	/*
218 	 * Give pmap a chance to set up a few more things now the vm
219 	 * is initialised
220 	 */
221 	pmap_postinit();
222 
223 	/*
224 	 * Initialize error message buffer (at end of core).
225 	 */
226 
227 	/* msgbufphys was setup during the secondary boot strap */
228 	for (loop = 0; loop < atop(MSGBUFSIZE); ++loop)
229 		pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE,
230 		    msgbufphys + loop * PAGE_SIZE, PROT_READ | PROT_WRITE);
231 	pmap_update(pmap_kernel());
232 	initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE));
233 
234 	/*
235 	 * Identify ourselves for the msgbuf (everything printed earlier will
236 	 * not be buffered).
237 	 */
238 	printf("%s", version);
239 
240 	printf("real mem  = %lu (%luMB)\n", ptoa(physmem),
241 	    ptoa(physmem) / 1024 / 1024);
242 
243 	/*
244 	 * Allocate a submap for exec arguments.  This map effectively
245 	 * limits the number of processes exec'ing at any time.
246 	 */
247 	minaddr = vm_map_min(kernel_map);
248 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
249 	    16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
250 
251 	/*
252 	 * Allocate a submap for physio
253 	 */
254 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
255 	    VM_PHYS_SIZE, 0, FALSE, NULL);
256 
257 	/*
258 	 * Set up buffers, so they can be used to read disk labels.
259 	 */
260 	bufinit();
261 
262 	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
263 	    ptoa(uvmexp.free) / 1024 / 1024);
264 
265 	sbi_print_version();
266 
267 	curpcb = &proc0.p_addr->u_pcb;
268 	curpcb->pcb_flags = 0;
269 	curpcb->pcb_tf = &proc0tf;
270 
271 	if (boothowto & RB_CONFIG) {
272 #ifdef BOOT_CONFIG
273 		user_config();
274 #else
275 		printf("kernel does not support -c; continuing..\n");
276 #endif
277 	}
278 }
279 
280 /*
281  * Move parts of cpu_switchto into C, too difficult in asm
282  */
283 
284 void    cpu_switchto_asm(struct proc *, struct proc *);
285 
286 void
287 cpu_switchto(struct proc *old, struct proc *new)
288 {
289 	if (old) {
290 		struct pcb *pcb = &old->p_addr->u_pcb;
291 		struct trapframe *tf = pcb->pcb_tf;
292 
293 		if (pcb->pcb_flags & PCB_FPU)
294 			fpu_save(old, tf);
295 
296 		/* drop FPU state */
297 		tf->tf_sstatus &= ~SSTATUS_FS_MASK;
298 		tf->tf_sstatus |= SSTATUS_FS_OFF;
299 	}
300 
301 	cpu_switchto_asm(old, new);
302 }
303 
304 /*
305  * machine dependent system variables.
306  */
307 
308 int
309 cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
310     size_t newlen, struct proc *p)
311 {
312 	char *compatible;
313 	int node, len, error;
314 
315 	/* all sysctl names at this level are terminal */
316 	if (namelen != 1)
317 		return (ENOTDIR);		/* overloaded */
318 
319 	switch (name[0]) {
320 	case CPU_COMPATIBLE:
321 		node = OF_finddevice("/");
322 		len = OF_getproplen(node, "compatible");
323 		if (len <= 0)
324 			return (EOPNOTSUPP);
325 		compatible = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
326 		OF_getprop(node, "compatible", compatible, len);
327 		compatible[len - 1] = 0;
328 		error = sysctl_rdstring(oldp, oldlenp, newp, compatible);
329 		free(compatible, M_TEMP, len);
330 		return error;
331 	default:
332 		return (EOPNOTSUPP);
333 	}
334 	/* NOTREACHED */
335 }
336 
337 int	waittime = -1;
338 
339 __dead void
340 boot(int howto)
341 {
342 	if ((howto & RB_RESET) != 0)
343 		goto doreset;
344 
345 	if (cold) {
346 		if ((howto & RB_USERREQ) == 0)
347 			howto |= RB_HALT;
348 		goto haltsys;
349 	}
350 
351 	boothowto = howto;
352 	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
353 		waittime = 0;
354 		vfs_shutdown(curproc);
355 
356 		if ((howto & RB_TIMEBAD) == 0) {
357 			resettodr();
358 		} else {
359 			printf("WARNING: not updating battery clock\n");
360 		}
361 	}
362 	if_downall();
363 
364 	uvm_shutdown();
365 	splhigh();
366 	cold = 1;
367 
368 	if ((howto & RB_DUMP) != 0)
369 		printf("no dump so far\n");
370 
371 haltsys:
372 	config_suspend_all(DVACT_POWERDOWN);
373 
374 	if ((howto & RB_HALT) != 0) {
375 		if ((howto & RB_POWERDOWN) != 0) {
376 			printf("\nAttempting to power down...\n");
377 			delay(500000);
378 			if (powerdownfn)
379 				(*powerdownfn)();
380 		}
381 
382 		printf("\n");
383 		printf("The operating system has halted.\n");
384 		printf("Please press any key to reboot.\n\n");
385 		cngetc();
386 	}
387 
388 doreset:
389 	printf("rebooting...\n");
390 	delay(500000);
391 	if (cpuresetfn)
392 		(*cpuresetfn)();
393 	printf("reboot failed; spinning\n");
394 	for (;;)
395 		continue;
396 	/* NOTREACHED */
397 }
398 
399 void
400 setregs(struct proc *p, struct exec_package *pack, u_long stack,
401     struct ps_strings *arginfo)
402 {
403 	struct trapframe *tf = p->p_addr->u_pcb.pcb_tf;
404 	struct pcb *pcb = &p->p_addr->u_pcb;
405 
406 	/* If we were using the FPU, forget about it. */
407 	pcb->pcb_flags &= ~PCB_FPU;
408 	tf->tf_sstatus &= ~SSTATUS_FS_MASK;
409 	tf->tf_sstatus |= SSTATUS_FS_OFF;
410 
411 	memset(tf, 0, sizeof *tf);
412 	tf->tf_sp = STACKALIGN(stack);
413 	tf->tf_ra = pack->ep_entry;
414 	tf->tf_sepc = pack->ep_entry;
415 }
416 
417 void
418 need_resched(struct cpu_info *ci)
419 {
420 	ci->ci_want_resched = 1;
421 
422 	/* There's a risk we'll be called before the idle threads start */
423 	if (ci->ci_curproc) {
424 		aston(ci->ci_curproc);
425 		cpu_kick(ci);
426 	}
427 }
428 
429 
430 /*
431  * Size of memory segments, before any memory is stolen.
432  */
433 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
434 int	mem_cluster_cnt;
435 
436 /*
437  * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers.
438  */
439 int
440 cpu_dumpsize(void)
441 {
442 	int size;
443 
444 	size = ALIGN(sizeof(kcore_seg_t)) +
445 	    ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t));
446 	if (roundup(size, dbtob(1)) != dbtob(1))
447 		return (-1);
448 
449 	return (1);
450 }
451 
452 u_long
453 cpu_dump_mempagecnt(void)
454 {
455 	return 0;
456 }
457 
458 /*
459  * These variables are needed by /sbin/savecore
460  */
461 u_long	dumpmag = 0x8fca0101;	/* magic number */
462 int	dumpsize = 0;		/* pages */
463 long	dumplo = 0;		/* blocks */
464 
465 /*
466  * This is called by main to set dumplo and dumpsize.
467  * Dumps always skip the first PAGE_SIZE of disk space
468  * in case there might be a disk label stored there.
469  * If there is extra space, put dump at the end to
470  * reduce the chance that swapping trashes it.
471  */
472 void
473 dumpconf(void)
474 {
475 	int nblks, dumpblks;	/* size of dump area */
476 
477 	if (dumpdev == NODEV ||
478 	    (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
479 		return;
480 	if (nblks <= ctod(1))
481 		return;
482 
483 	dumpblks = cpu_dumpsize();
484 	if (dumpblks < 0)
485 		return;
486 	dumpblks += ctod(cpu_dump_mempagecnt());
487 
488 	/* If dump won't fit (incl. room for possible label), punt. */
489 	if (dumpblks > (nblks - ctod(1)))
490 		return;
491 
492 	/* Put dump at end of partition */
493 	dumplo = nblks - dumpblks;
494 
495 	/* dumpsize is in page units, and doesn't include headers. */
496 	dumpsize = cpu_dump_mempagecnt();
497 }
498 
499 int
500 sys_sysarch(struct proc *p, void *v, register_t *retval)
501 {
502 	struct sys_sysarch_args /* {
503 		syscallarg(int) op;
504 		syscallarg(void *) parms;
505 	} */ *uap = v;
506 	struct riscv_sync_icache_args args;
507 	int error = 0;
508 
509 	switch (SCARG(uap, op)) {
510 	case RISCV_SYNC_ICACHE:
511 		if (SCARG(uap, parms) != NULL)
512 			error = copyin(SCARG(uap, parms), &args, sizeof(args));
513 		if (error)
514 			break;
515 		/*
516 		 * XXX Validate args.addr and args.len before using them.
517 		 */
518 		pmap_proc_iflush(p->p_p, (vaddr_t)args.addr, args.len);
519 		break;
520 	default:
521 		error = EINVAL;
522 		break;
523 	}
524 
525 	return (error);
526 }
527 
528 uint64_t mmap_start;
529 uint32_t mmap_size;
530 uint32_t mmap_desc_size;
531 uint32_t mmap_desc_ver;
532 
533 EFI_MEMORY_DESCRIPTOR *mmap;
534 
535 void	collect_kernel_args(const char *);
536 void	process_kernel_args(void);
537 
538 int	pmap_bootstrap_bs_map(bus_space_tag_t, bus_addr_t,
539 	    bus_size_t, int, bus_space_handle_t *);
540 
541 void
542 initriscv(struct riscv_bootparams *rbp)
543 {
544 	paddr_t memstart, memend;
545 	paddr_t startpa, endpa, pa;
546 	vaddr_t vstart, va;
547 	struct fdt_head *fh;
548 	void *config = (void *)rbp->dtbp_phys;
549 	void *fdt = NULL;
550 	struct fdt_reg reg;
551 	void *node;
552 	EFI_PHYSICAL_ADDRESS system_table = 0;
553 	int (*map_func_save)(bus_space_tag_t, bus_addr_t, bus_size_t, int,
554 	    bus_space_handle_t *);
555 	int i;
556 
557 	/* Set the per-CPU pointer. */
558 	__asm volatile("mv tp, %0" :: "r"(&cpu_info_primary));
559 
560 	sbi_init();
561 
562 	/* The bootloader has loaded us into a 64MB block. */
563 	memstart = rbp->kern_phys;
564 	memend = memstart + 64 * 1024 * 1024;
565 
566 	/* Bootstrap enough of pmap to enter the kernel proper. */
567 	vstart = pmap_bootstrap(rbp->kern_phys - KERNBASE, rbp->kern_l1pt,
568 	    KERNBASE, esym, memstart, memend);
569 
570 	/* Map the FDT header to determine its size. */
571 	va = vstart;
572 	startpa = trunc_page((paddr_t)config);
573 	endpa = round_page((paddr_t)config + sizeof(struct fdt_head));
574 	for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
575 		pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, PMAP_CACHE_WB);
576 	fh = (void *)(vstart + ((paddr_t)config - startpa));
577 	if (betoh32(fh->fh_magic) != FDT_MAGIC || betoh32(fh->fh_size) == 0)
578 		panic("%s: no FDT", __func__);
579 
580 	/* Map the remainder of the FDT. */
581 	endpa = round_page((paddr_t)config + betoh32(fh->fh_size));
582 	for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
583 		pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, PMAP_CACHE_WB);
584 	config = (void *)(vstart + ((paddr_t)config - startpa));
585 	vstart = va;
586 
587 	if (!fdt_init(config))
588 		panic("%s: corrupt FDT", __func__);
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(uint32_t))
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 	process_kernel_args();
669 
670 	proc0paddr = (struct user *)rbp->kern_stack;
671 
672 	msgbufaddr = (caddr_t)vstart;
673 	msgbufphys = pmap_steal_avail(round_page(MSGBUFSIZE), PAGE_SIZE, NULL);
674 	vstart += round_page(MSGBUFSIZE);
675 
676 	zero_page = vstart;
677 	vstart += MAXCPUS * PAGE_SIZE;
678 	copy_src_page = vstart;
679 	vstart += MAXCPUS * PAGE_SIZE;
680 	copy_dst_page = vstart;
681 	vstart += MAXCPUS * PAGE_SIZE;
682 
683 	/* Relocate the FDT to safe memory. */
684 	if (fdt_get_size(config) != 0) {
685 		uint32_t csize, size = round_page(fdt_get_size(config));
686 		paddr_t pa;
687 		vaddr_t va;
688 
689 		pa = pmap_steal_avail(size, PAGE_SIZE, NULL);
690 		memcpy((void *)PHYS_TO_DMAP(pa), config, size);
691 		for (va = vstart, csize = size; csize > 0;
692 		    csize -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE)
693 			pmap_kenter_cache(va, pa, PROT_READ, PMAP_CACHE_WB);
694 
695 		fdt = (void *)vstart;
696 		vstart += size;
697 	}
698 
699 	/* Relocate the EFI memory map too. */
700 	if (mmap_start != 0) {
701 		uint32_t csize, size = round_page(mmap_size);
702 		paddr_t pa, startpa, endpa;
703 		vaddr_t va;
704 
705 		startpa = trunc_page(mmap_start);
706 		endpa = round_page(mmap_start + mmap_size);
707 		for (pa = startpa, va = vstart; pa < endpa;
708 		    pa += PAGE_SIZE, va += PAGE_SIZE)
709 			pmap_kenter_cache(va, pa, PROT_READ, PMAP_CACHE_WB);
710 		pa = pmap_steal_avail(size, PAGE_SIZE, NULL);
711 		memcpy((void *)PHYS_TO_DMAP(pa),
712 		    (caddr_t)vstart + (mmap_start - startpa), mmap_size);
713 		pmap_kremove(vstart, endpa - startpa);
714 
715 		for (va = vstart, csize = size; csize > 0;
716 		    csize -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE)
717 			pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, PMAP_CACHE_WB);
718 
719 		mmap = (void *)vstart;
720 		vstart += size;
721 	}
722 
723 	/* No more KVA stealing after this point. */
724 	virtual_avail = vstart;
725 
726 	/* Now we can reinit the FDT, using the virtual address. */
727 	if (fdt)
728 		fdt_init(fdt);
729 
730 	map_func_save = riscv64_bs_tag._space_map;
731 	riscv64_bs_tag._space_map = pmap_bootstrap_bs_map;
732 
733 	consinit();
734 
735 	riscv64_bs_tag._space_map = map_func_save;
736 
737 	pmap_avail_fixup();
738 
739 	uvmexp.pagesize = PAGE_SIZE;
740 	uvm_setpagesize();
741 
742 	/* Make what's left of the initial 64MB block available to UVM. */
743 	pmap_physload_avail();
744 
745 	/* Make all other physical memory available to UVM. */
746 	if (mmap && mmap_desc_ver == EFI_MEMORY_DESCRIPTOR_VERSION) {
747 		EFI_MEMORY_DESCRIPTOR *desc = mmap;
748 
749 		/*
750 		 * Load all memory marked as EfiConventionalMemory,
751 		 * EfiBootServicesCode or EfiBootServicesData.
752 		 * Don't bother with blocks smaller than 64KB.  The
753 		 * initial 64MB memory block should be marked as
754 		 * EfiLoaderData so it won't be added here.
755 		 */
756 		for (i = 0; i < mmap_size / mmap_desc_size; i++) {
757 			printf("type 0x%x pa 0x%llx va 0x%llx pages 0x%llx attr 0x%llx\n",
758 			    desc->Type, desc->PhysicalStart,
759 			    desc->VirtualStart, desc->NumberOfPages,
760 			    desc->Attribute);
761 			if ((desc->Type == EfiConventionalMemory ||
762 			     desc->Type == EfiBootServicesCode ||
763 			     desc->Type == EfiBootServicesData) &&
764 			    desc->NumberOfPages >= 16) {
765 				reg.addr = desc->PhysicalStart;
766 				reg.size = ptoa(desc->NumberOfPages);
767 				memreg_add(&reg);
768 			}
769 			desc = NextMemoryDescriptor(desc, mmap_desc_size);
770 		}
771 	} else {
772 		node = fdt_find_node("/memory");
773 		if (node == NULL)
774 			panic("%s: no memory specified", __func__);
775 
776 		for (i = 0; nmemreg < nitems(memreg); i++) {
777 			if (fdt_get_reg(node, i, &reg))
778 				break;
779 			if (reg.size == 0)
780 				continue;
781 			memreg_add(&reg);
782 		}
783 	}
784 
785 	/* Remove reserved memory. */
786 	node = fdt_find_node("/reserved-memory");
787 	if (node) {
788 		for (node = fdt_child_node(node); node;
789 		    node = fdt_next_node(node)) {
790 			if (fdt_get_reg(node, 0, &reg))
791 				continue;
792 			if (reg.size == 0)
793 				continue;
794 			memreg_remove(&reg);
795 		}
796 	}
797 
798 	/* Remove the initial 64MB block. */
799 	reg.addr = memstart;
800 	reg.size = memend - memstart;
801 	memreg_remove(&reg);
802 
803 	for (i = 0; i < nmemreg; i++) {
804 		paddr_t start = memreg[i].addr;
805 		paddr_t end = start + memreg[i].size;
806 
807 		uvm_page_physload(atop(start), atop(end),
808 		    atop(start), atop(end), 0);
809 	}
810 
811 	/*
812 	 * Determine physical RAM size from the /memory nodes in the
813 	 * FDT.  There can be multiple nodes and each node can contain
814 	 * multiple ranges.
815 	 */
816 	node = fdt_find_node("/memory");
817 	if (node == NULL)
818 		panic("%s: no memory specified", __func__);
819 	while (node) {
820 		const char *s = fdt_node_name(node);
821 		if (strncmp(s, "memory", 6) == 0 &&
822 		    (s[6] == '\0' || s[6] == '@')) {
823 			for (i = 0; i < VM_PHYSSEG_MAX; i++) {
824 				if (fdt_get_reg(node, i, &reg))
825 					break;
826 				if (reg.size == 0)
827 					continue;
828 				physmem += atop(reg.size);
829 			}
830 		}
831 
832 		node = fdt_next_node(node);
833 	}
834 
835 	kmeminit_nkmempages();
836 
837 	/*
838 	 * Make sure that we have enough KVA to initialize UVM.  In
839 	 * particular, we need enough KVA to be able to allocate the
840 	 * vm_page structures and nkmempages for malloc(9).
841 	 */
842 	pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 1024 * 1024 * 1024 +
843 	    physmem * sizeof(struct vm_page) + ptoa(nkmempages));
844 
845 #ifdef DDB
846 	db_machine_init();
847 
848 	/* Firmware doesn't load symbols. */
849 	ddb_init();
850 
851 	if (boothowto & RB_KDB)
852 		db_enter();
853 #endif
854 
855 	softintr_init();
856 	splraise(IPL_IPI);
857 }
858 
859 char bootargs[256];
860 
861 void
862 collect_kernel_args(const char *args)
863 {
864 	/* Make a local copy of the bootargs */
865 	strlcpy(bootargs, args, sizeof(bootargs));
866 }
867 
868 void
869 process_kernel_args(void)
870 {
871 	char *cp = bootargs;
872 
873 	if (*cp == 0)
874 		return;
875 
876 	/* Skip the kernel image filename */
877 	while (*cp != ' ' && *cp != 0)
878 		cp++;
879 
880 	if (*cp != 0)
881 		*cp++ = 0;
882 
883 	while (*cp == ' ')
884 		cp++;
885 
886 	boot_args = cp;
887 
888 	printf("bootargs: %s\n", boot_args);
889 
890 	/* Setup pointer to boot flags */
891 	while (*cp != '-')
892 		if (*cp++ == '\0')
893 			return;
894 
895 	while (*++cp != 0) {
896 		switch (*cp) {
897 		case 'a':
898 			boothowto |= RB_ASKNAME;
899 			break;
900 		case 'c':
901 			boothowto |= RB_CONFIG;
902 			break;
903 		case 'd':
904 			boothowto |= RB_KDB;
905 			break;
906 		case 's':
907 			boothowto |= RB_SINGLE;
908 			break;
909 		default:
910 			printf("unknown option `%c'\n", *cp);
911 			break;
912 		}
913 	}
914 }
915 
916 /*
917  * Allow bootstrap to steal KVA after machdep has given it back to pmap.
918  */
919 int
920 pmap_bootstrap_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
921     int flags, bus_space_handle_t *bshp)
922 {
923 	u_long startpa, pa, endpa;
924 	vaddr_t va;
925 
926 	va = virtual_avail;	/* steal memory from virtual avail. */
927 
928 	startpa = trunc_page(bpa);
929 	endpa = round_page((bpa + size));
930 
931 	*bshp = (bus_space_handle_t)(va + (bpa - startpa));
932 
933 	for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
934 		pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE,
935 		    PMAP_CACHE_DEV);
936 
937 	virtual_avail = va;
938 
939 	return 0;
940 }
941 
942 void
943 memreg_add(const struct fdt_reg *reg)
944 {
945 	int i;
946 
947 	for (i = 0; i < nmemreg; i++) {
948 		if (reg->addr == memreg[i].addr + memreg[i].size) {
949 			memreg[i].size += reg->size;
950 			return;
951 		}
952 		if (reg->addr + reg->size == memreg[i].addr) {
953 			memreg[i].addr = reg->addr;
954 			memreg[i].size += reg->size;
955 			return;
956 		}
957 	}
958 
959 	if (nmemreg >= nitems(memreg))
960 		return;
961 
962 	memreg[nmemreg++] = *reg;
963 }
964 
965 void
966 memreg_remove(const struct fdt_reg *reg)
967 {
968 	uint64_t start = reg->addr;
969 	uint64_t end = reg->addr + reg->size;
970 	int i, j;
971 
972 	for (i = 0; i < nmemreg; i++) {
973 		uint64_t memstart = memreg[i].addr;
974 		uint64_t memend = memreg[i].addr + memreg[i].size;
975 
976 		if (end <= memstart)
977 			continue;
978 		if (start >= memend)
979 			continue;
980 
981 		if (start <= memstart)
982 			memstart = MIN(end, memend);
983 		if (end >= memend)
984 			memend = MAX(start, memstart);
985 
986 		if (start > memstart && end < memend) {
987 			if (nmemreg < nitems(memreg)) {
988 				memreg[nmemreg].addr = end;
989 				memreg[nmemreg].size = memend - end;
990 				nmemreg++;
991 			}
992 			memend = start;
993 		}
994 		memreg[i].addr = memstart;
995 		memreg[i].size = memend - memstart;
996 	}
997 
998 	/* Remove empty slots. */
999 	for (i = nmemreg - 1; i >= 0; i--) {
1000 		if (memreg[i].size == 0) {
1001 			for (j = i; (j + 1) < nmemreg; j++)
1002 				memreg[j] = memreg[j + 1];
1003 			nmemreg--;
1004 		}
1005 	}
1006 }
1007