1/*	$OpenBSD: machdep.c,v 1.74 2023/01/07 17:29:37 miod Exp $	*/
2
3/*
4 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/param.h>
20#include <sys/buf.h>
21#include <sys/exec.h>
22#include <sys/exec_elf.h>
23#include <sys/mount.h>
24#include <sys/msgbuf.h>
25#include <sys/proc.h>
26#include <sys/reboot.h>
27#include <sys/signalvar.h>
28#include <sys/syscallargs.h>
29#include <sys/sysctl.h>
30#include <sys/systm.h>
31#include <sys/user.h>
32
33#include <machine/cpufunc.h>
34#include <machine/fpu.h>
35#include <machine/opal.h>
36#include <machine/pcb.h>
37#include <machine/psl.h>
38#include <machine/trap.h>
39
40#include <net/if.h>
41#include <uvm/uvm_extern.h>
42
43#include <dev/ofw/fdt.h>
44#include <dev/ofw/openfirm.h>
45#include <dev/cons.h>
46
47#ifdef DDB
48#include <machine/db_machdep.h>
49#include <ddb/db_extern.h>
50#include <ddb/db_interface.h>
51#endif
52
53int cacheline_size = 128;
54
55struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
56struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
57
58int cold = 1;
59int safepri = 0;
60int physmem;
61paddr_t physmax;
62
63struct vm_map *exec_map;
64struct vm_map *phys_map;
65
66char machine[] = MACHINE;
67
68struct user *proc0paddr;
69
70caddr_t ssym, esym;
71
72extern char _start[], _end[];
73extern char __bss_start[];
74
75extern uint64_t opal_base;
76extern uint64_t opal_entry;
77int opal_have_console_flush;
78
79extern char trapcode[], trapcodeend[];
80extern char hvtrapcode[], hvtrapcodeend[];
81extern char rsttrapcode[], rsttrapcodeend[];
82extern char slbtrapcode[], slbtrapcodeend[];
83extern char generictrap[];
84extern char generichvtrap[];
85extern char kern_slbtrap[];
86extern char cpu_idle_restore_context[];
87
88extern char initstack[];
89
90struct fdt_reg memreg[VM_PHYSSEG_MAX];
91int nmemreg;
92
93#ifdef DDB
94struct fdt_reg initrd_reg;
95#endif
96
97void memreg_add(const struct fdt_reg *);
98void memreg_remove(const struct fdt_reg *);
99
100uint8_t *bootmac = NULL;
101
102void parse_bootargs(const char *);
103const char *parse_bootduid(const char *);
104const char *parse_bootmac(const char *);
105
106paddr_t fdt_pa;
107size_t fdt_size;
108
109int stdout_node;
110int stdout_speed;
111
112static int
113atoi(const char *s)
114{
115	int n, neg;
116
117	n = 0;
118	neg = 0;
119
120	while (*s == '-') {
121		s++;
122		neg = !neg;
123	}
124
125	while (*s != '\0') {
126		if (*s < '0' || *s > '9')
127			break;
128
129		n = (10 * n) + (*s - '0');
130		s++;
131	}
132
133	return (neg ? -n : n);
134}
135
136void *
137fdt_find_cons(void)
138{
139	char *alias = "serial0";
140	char buf[128];
141	char *stdout = NULL;
142	char *p;
143	void *node;
144
145	/* First check if "stdout-path" is set. */
146	node = fdt_find_node("/chosen");
147	if (node) {
148		if (fdt_node_property(node, "stdout-path", &stdout) > 0) {
149			if (strchr(stdout, ':') != NULL) {
150				strlcpy(buf, stdout, sizeof(buf));
151				if ((p = strchr(buf, ':')) != NULL) {
152					*p++ = '\0';
153					stdout_speed = atoi(p);
154				}
155				stdout = buf;
156			}
157			if (stdout[0] != '/') {
158				/* It's an alias. */
159				alias = stdout;
160				stdout = NULL;
161			}
162		}
163	}
164
165	/* Perform alias lookup if necessary. */
166	if (stdout == NULL) {
167		node = fdt_find_node("/aliases");
168		if (node)
169			fdt_node_property(node, alias, &stdout);
170	}
171
172	/* Lookup the physical address of the interface. */
173	if (stdout) {
174		node = fdt_find_node(stdout);
175		if (node) {
176			stdout_node = OF_finddevice(stdout);
177			return (node);
178		}
179	}
180
181	return (NULL);
182}
183
184void
185init_powernv(void *fdt, void *tocbase)
186{
187	struct fdt_reg reg;
188	register_t uspace;
189	paddr_t trap;
190	uint64_t msr;
191	void *node;
192	char *prop;
193	int len;
194	int i;
195
196	/* Store pointer to our struct cpu_info. */
197	__asm volatile ("mtsprg0 %0" :: "r"(cpu_info_primary));
198
199	/* Clear BSS. */
200	memset(__bss_start, 0, _end - __bss_start);
201
202	if (!fdt_init(fdt) || fdt_get_size(fdt) == 0)
203		panic("no FDT");
204
205	/* Get OPAL base and entry addresses from FDT. */
206	node = fdt_find_node("/ibm,opal");
207	if (node) {
208		fdt_node_property(node, "opal-base-address", &prop);
209		opal_base = bemtoh64((uint64_t *)prop);
210		fdt_node_property(node, "opal-entry-address", &prop);
211		opal_entry = bemtoh64((uint64_t *)prop);
212		fdt_node_property(node, "compatible", &prop);
213
214		opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_BE);
215
216		/*
217		 * The following call will fail on Power ISA 2.0x CPUs,
218		 * but that is fine since they don't support Radix Tree
219		 * translation.  On Power ISA 3.0 CPUs this will make
220		 * the full TLB available.
221		 */
222		opal_reinit_cpus(OPAL_REINIT_CPUS_MMU_HASH);
223
224		/* Older firmware doesn't implement OPAL_CONSOLE_FLUSH. */
225		if (opal_check_token(OPAL_CONSOLE_FLUSH) == OPAL_TOKEN_PRESENT)
226			opal_have_console_flush = 1;
227	}
228
229	/* At this point we can call OPAL runtime services and use printf(9). */
230	printf("Hello, World!\n");
231
232	/* Stash these such that we can remap the FDT later. */
233	fdt_pa = (paddr_t)fdt;
234	fdt_size = fdt_get_size(fdt);
235
236	fdt_find_cons();
237
238	/*
239	 * Initialize all traps with the stub that calls the generic
240	 * trap handler.
241	 */
242	for (trap = EXC_RST; trap < EXC_END; trap += 32)
243		memcpy((void *)trap, trapcode, trapcodeend - trapcode);
244
245	/* Hypervisor interrupts needs special handling. */
246	memcpy((void *)EXC_HDSI, hvtrapcode, hvtrapcodeend - hvtrapcode);
247	memcpy((void *)EXC_HISI, hvtrapcode, hvtrapcodeend - hvtrapcode);
248	memcpy((void *)EXC_HEA, hvtrapcode, hvtrapcodeend - hvtrapcode);
249	memcpy((void *)EXC_HMI, hvtrapcode, hvtrapcodeend - hvtrapcode);
250	memcpy((void *)EXC_HFAC, hvtrapcode, hvtrapcodeend - hvtrapcode);
251	memcpy((void *)EXC_HVI, hvtrapcode, hvtrapcodeend - hvtrapcode);
252
253	/* System reset trap needs special handling. */
254	memcpy((void *)EXC_RST, rsttrapcode, rsttrapcodeend - rsttrapcode);
255
256	/* SLB trap needs special handling as well. */
257	memcpy((void *)EXC_DSE, slbtrapcode, slbtrapcodeend - slbtrapcode);
258
259	*((void **)TRAP_ENTRY) = generictrap;
260	*((void **)TRAP_HVENTRY) = generichvtrap;
261	*((void **)TRAP_SLBENTRY) = kern_slbtrap;
262	*((void **)TRAP_RSTENTRY) = cpu_idle_restore_context;
263
264	/* Make the stubs visible to the CPU. */
265	__syncicache(EXC_RSVD, EXC_END - EXC_RSVD);
266
267	/* We're now ready to take traps. */
268	msr = mfmsr();
269	mtmsr(msr | (PSL_ME|PSL_RI));
270
271	cpu_init_features();
272	cpu_init();
273
274	/* Add all memory. */
275	node = fdt_find_node("/");
276	for (node = fdt_child_node(node); node; node = fdt_next_node(node)) {
277		len = fdt_node_property(node, "device_type", &prop);
278		if (len <= 0)
279			continue;
280		if (strcmp(prop, "memory") != 0)
281			continue;
282		for (i = 0; nmemreg < nitems(memreg); i++) {
283			if (fdt_get_reg(node, i, &reg))
284				break;
285			if (reg.size == 0)
286				continue;
287			memreg_add(&reg);
288			physmem += atop(reg.size);
289			physmax = MAX(physmax, reg.addr + reg.size);
290		}
291	}
292
293	/* Remove reserved memory. */
294	node = fdt_find_node("/reserved-memory");
295	if (node) {
296		for (node = fdt_child_node(node); node;
297		     node = fdt_next_node(node)) {
298			if (fdt_get_reg(node, 0, &reg))
299				continue;
300			if (reg.size == 0)
301				continue;
302			memreg_remove(&reg);
303		}
304	}
305
306	/* Remove interrupt vectors. */
307	reg.addr = trunc_page(EXC_RSVD);
308	reg.size = round_page(EXC_END);
309	memreg_remove(&reg);
310
311	/* Remove kernel. */
312	reg.addr = trunc_page((paddr_t)_start);
313	reg.size = round_page((paddr_t)_end) - reg.addr;
314	memreg_remove(&reg);
315
316	/* Remove FDT. */
317	reg.addr = trunc_page((paddr_t)fdt);
318	reg.size = round_page((paddr_t)fdt + fdt_get_size(fdt)) - reg.addr;
319	memreg_remove(&reg);
320
321#ifdef DDB
322	/* Load symbols from initrd. */
323	db_machine_init();
324	if (initrd_reg.size != 0)
325		memreg_remove(&initrd_reg);
326	ssym = (caddr_t)initrd_reg.addr;
327	esym = ssym + initrd_reg.size;
328#endif
329
330	pmap_bootstrap();
331	uvm_setpagesize();
332
333	for (i = 0; i < nmemreg; i++) {
334		paddr_t start = memreg[i].addr;
335		paddr_t end = start + memreg[i].size;
336
337		uvm_page_physload(atop(start), atop(end),
338		    atop(start), atop(end), 0);
339	}
340
341	/* Enable translation. */
342	msr = mfmsr();
343	mtmsr(msr | (PSL_DR|PSL_IR));
344	isync();
345
346	initmsgbuf((caddr_t)uvm_pageboot_alloc(MSGBUFSIZE), MSGBUFSIZE);
347
348	proc0paddr = (struct user *)initstack;
349	proc0.p_addr = proc0paddr;
350	curpcb = &proc0.p_addr->u_pcb;
351	uspace = (register_t)proc0paddr + USPACE - FRAMELEN;
352	proc0.p_md.md_regs = (struct trapframe *)uspace;
353}
354
355void
356memreg_add(const struct fdt_reg *reg)
357{
358	int i;
359
360	for (i = 0; i < nmemreg; i++) {
361		if (reg->addr == memreg[i].addr + memreg[i].size) {
362			memreg[i].size += reg->size;
363			return;
364		}
365		if (reg->addr + reg->size == memreg[i].addr) {
366			memreg[i].addr = reg->addr;
367			memreg[i].size += reg->size;
368			return;
369		}
370	}
371
372	if (nmemreg >= nitems(memreg))
373		return;
374
375	memreg[nmemreg++] = *reg;
376}
377
378void
379memreg_remove(const struct fdt_reg *reg)
380{
381	uint64_t start = reg->addr;
382	uint64_t end = reg->addr + reg->size;
383	int i, j;
384
385	for (i = 0; i < nmemreg; i++) {
386		uint64_t memstart = memreg[i].addr;
387		uint64_t memend = memreg[i].addr + memreg[i].size;
388
389		if (end <= memstart)
390			continue;
391		if (start >= memend)
392			continue;
393
394		if (start <= memstart)
395			memstart = MIN(end, memend);
396		if (end >= memend)
397			memend = MAX(start, memstart);
398
399		if (start > memstart && end < memend) {
400			if (nmemreg < nitems(memreg)) {
401				memreg[nmemreg].addr = end;
402				memreg[nmemreg].size = memend - end;
403				nmemreg++;
404			}
405			memend = start;
406		}
407		memreg[i].addr = memstart;
408		memreg[i].size = memend - memstart;
409	}
410
411	/* Remove empty slots. */
412	for (i = nmemreg - 1; i >= 0; i--) {
413		if (memreg[i].size == 0) {
414			for (j = i; (j + 1) < nmemreg; j++)
415				memreg[j] = memreg[j + 1];
416			nmemreg--;
417		}
418	}
419}
420
421#define R_PPC64_RELATIVE	22
422#define ELF_R_TYPE_RELATIVE	R_PPC64_RELATIVE
423
424/*
425 * Disable optimization for this function to prevent clang from
426 * generating jump tables that need relocation.
427 */
428__attribute__((optnone)) void
429self_reloc(Elf_Dyn *dynamic, Elf_Addr base)
430{
431	Elf_Word relasz = 0, relaent = sizeof(Elf_RelA);
432	Elf_RelA *rela = NULL;
433	Elf_Addr *addr;
434	Elf_Dyn *dynp;
435
436	for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) {
437		switch (dynp->d_tag) {
438		case DT_RELA:
439			rela = (Elf_RelA *)(dynp->d_un.d_ptr + base);
440			break;
441		case DT_RELASZ:
442			relasz = dynp->d_un.d_val;
443			break;
444		case DT_RELAENT:
445			relaent = dynp->d_un.d_val;
446			break;
447		}
448	}
449
450	while (relasz > 0) {
451		switch (ELF_R_TYPE(rela->r_info)) {
452		case ELF_R_TYPE_RELATIVE:
453			addr = (Elf_Addr *)(base + rela->r_offset);
454			*addr = base + rela->r_addend;
455			break;
456		}
457		rela = (Elf_RelA *)((caddr_t)rela + relaent);
458		relasz -= relaent;
459	}
460}
461
462void *
463opal_phys(void *va)
464{
465	paddr_t pa;
466
467	pmap_extract(pmap_kernel(), (vaddr_t)va, &pa);
468	return (void *)pa;
469}
470
471void
472opal_printf(const char *fmt, ...)
473{
474	static char buf[256];
475	uint64_t len;
476	va_list ap;
477
478	va_start(ap, fmt);
479	len = vsnprintf(buf, sizeof(buf), fmt, ap);
480	if (len == (uint64_t)-1)
481		len = 0;
482	else if (len >= sizeof(buf))
483		 len = sizeof(buf) - 1;
484	va_end(ap);
485
486	opal_console_write(0, opal_phys(&len), opal_phys(buf));
487}
488
489int64_t
490opal_do_console_flush(int64_t term_number)
491{
492	uint64_t events;
493	int64_t error;
494
495	if (opal_have_console_flush) {
496		error = opal_console_flush(term_number);
497		if (error == OPAL_BUSY_EVENT) {
498			opal_poll_events(NULL);
499			error = OPAL_BUSY;
500		}
501		return error;
502	} else {
503		opal_poll_events(opal_phys(&events));
504		if (events & OPAL_EVENT_CONSOLE_OUTPUT)
505			return OPAL_BUSY;
506		return OPAL_SUCCESS;
507	}
508}
509
510void
511opal_cnprobe(struct consdev *cd)
512{
513}
514
515void
516opal_cninit(struct consdev *cd)
517{
518}
519
520int
521opal_cngetc(dev_t dev)
522{
523	uint64_t len;
524	char ch;
525
526	for (;;) {
527		len = 1;
528		opal_console_read(0, opal_phys(&len), opal_phys(&ch));
529		if (len)
530			return ch;
531		opal_poll_events(NULL);
532	}
533}
534
535void
536opal_cnputc(dev_t dev, int c)
537{
538	uint64_t len = 1;
539	char ch = c;
540	int64_t error;
541
542	opal_console_write(0, opal_phys(&len), opal_phys(&ch));
543	while (1) {
544		error = opal_do_console_flush(0);
545		if (error != OPAL_BUSY && error != OPAL_PARTIAL)
546			break;
547		delay(1);
548	}
549}
550
551void
552opal_cnpollc(dev_t dev, int on)
553{
554}
555
556struct consdev opal_consdev = {
557	.cn_probe = opal_cnprobe,
558	.cn_init = opal_cninit,
559	.cn_getc = opal_cngetc,
560	.cn_putc = opal_cnputc,
561	.cn_pollc = opal_cnpollc,
562};
563
564struct consdev *cn_tab = &opal_consdev;
565
566int
567copyin(const void *uaddr, void *kaddr, size_t len)
568{
569	pmap_t pm = curproc->p_vmspace->vm_map.pmap;
570	vaddr_t kva;
571	vsize_t klen;
572	int error;
573
574	while (len > 0) {
575		error = pmap_set_user_slb(pm, (vaddr_t)uaddr, &kva, &klen);
576		if (error)
577			return error;
578		if (klen > len)
579			klen = len;
580		error = kcopy((const void *)kva, kaddr, klen);
581		pmap_unset_user_slb();
582		if (error)
583			return error;
584
585		uaddr = (const char *)uaddr + klen;
586		kaddr = (char *)kaddr + klen;
587		len -= klen;
588	}
589
590	return 0;
591}
592
593int
594copyin32(const uint32_t *uaddr, uint32_t *kaddr)
595{
596	return copyin(uaddr, kaddr, sizeof(uint32_t));
597}
598
599int
600copyout(const void *kaddr, void *uaddr, size_t len)
601{
602	pmap_t pm = curproc->p_vmspace->vm_map.pmap;
603	vaddr_t kva;
604	vsize_t klen;
605	int error;
606
607	while (len > 0) {
608		error = pmap_set_user_slb(pm, (vaddr_t)uaddr, &kva, &klen);
609		if (error)
610			return error;
611		if (klen > len)
612			klen = len;
613		error = kcopy(kaddr, (void *)kva, klen);
614		pmap_unset_user_slb();
615		if (error)
616			return error;
617
618		kaddr = (const char *)kaddr + klen;
619		uaddr = (char *)uaddr + klen;
620		len -= klen;
621	}
622
623	return 0;
624}
625
626/* in locore.S */
627extern int copystr(const void *, void *, size_t, size_t *)
628		__attribute__ ((__bounded__(__string__,2,3)));
629
630int
631copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
632{
633	pmap_t pm = curproc->p_vmspace->vm_map.pmap;
634	vaddr_t kva;
635	vsize_t klen;
636	size_t count, total;
637	int error = 0;
638
639	if (len == 0)
640		return ENAMETOOLONG;
641
642	total = 0;
643	while (len > 0) {
644		error = pmap_set_user_slb(pm, (vaddr_t)uaddr, &kva, &klen);
645		if (error)
646			goto out;
647		if (klen > len)
648			klen = len;
649		error = copystr((const void *)kva, kaddr, klen, &count);
650		total += count;
651		pmap_unset_user_slb();
652		if (error == 0 || error == EFAULT)
653			goto out;
654
655		uaddr = (const char *)uaddr + klen;
656		kaddr = (char *)kaddr + klen;
657		len -= klen;
658	}
659
660out:
661	if (done)
662		*done = total;
663	return error;
664}
665
666int
667copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
668{
669	pmap_t pm = curproc->p_vmspace->vm_map.pmap;
670	vaddr_t kva;
671	vsize_t klen;
672	size_t count, total;
673	int error = 0;
674
675	if (len == 0)
676		return ENAMETOOLONG;
677
678	total = 0;
679	while (len > 0) {
680		error = pmap_set_user_slb(pm, (vaddr_t)uaddr, &kva, &klen);
681		if (error)
682			goto out;
683		if (klen > len)
684			klen = len;
685		error = copystr(kaddr, (void *)kva, klen, &count);
686		total += count;
687		pmap_unset_user_slb();
688		if (error == 0 || error == EFAULT)
689			goto out;
690
691		kaddr = (const char *)kaddr + klen;
692		uaddr = (char *)uaddr + klen;
693		len -= klen;
694	}
695
696out:
697	if (done)
698		*done = total;
699	return error;
700}
701
702void
703need_resched(struct cpu_info *ci)
704{
705	ci->ci_want_resched = 1;
706
707	/* There's a risk we'll be called before the idle threads start */
708	if (ci->ci_curproc) {
709		aston(ci->ci_curproc);
710		cpu_kick(ci);
711	}
712}
713
714void
715cpu_startup(void)
716{
717	vaddr_t minaddr, maxaddr, va;
718	paddr_t pa, epa;
719	void *fdt;
720	void *node;
721	char *prop;
722	int len;
723
724	printf("%s", version);
725
726	printf("real mem  = %lu (%luMB)\n", ptoa(physmem),
727	    ptoa(physmem)/1024/1024);
728
729	/*
730	 * Allocate a submap for exec arguments.  This map effectively
731	 * limits the number of processes exec'ing at any time.
732	 */
733	minaddr = vm_map_min(kernel_map);
734	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
735	    16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
736
737	/*
738	 * Allocate a submap for physio.
739	 */
740	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
741	    VM_PHYS_SIZE, 0, FALSE, NULL);
742
743	/*
744	 * Set up buffers, so they can be used to read disk labels.
745	 */
746	bufinit();
747
748	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
749	    ptoa(uvmexp.free)/1024/1024);
750
751	/* Remap the FDT. */
752	pa = trunc_page(fdt_pa);
753	epa = round_page(fdt_pa + fdt_size);
754	va = (vaddr_t)km_alloc(epa - pa, &kv_any, &kp_none, &kd_waitok);
755	fdt = (void *)(va + (fdt_pa & PAGE_MASK));
756	while (pa < epa) {
757		pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE);
758		va += PAGE_SIZE;
759		pa += PAGE_SIZE;
760	}
761
762	if (!fdt_init(fdt) || fdt_get_size(fdt) == 0)
763		panic("can't remap FDT");
764
765	intr_init();
766
767	node = fdt_find_node("/chosen");
768	if (node) {
769		len = fdt_node_property(node, "bootargs", &prop);
770		if (len > 0)
771			parse_bootargs(prop);
772
773		len = fdt_node_property(node, "openbsd,boothowto", &prop);
774		if (len == sizeof(boothowto))
775			boothowto = bemtoh32((uint32_t *)prop);
776
777		len = fdt_node_property(node, "openbsd,bootduid", &prop);
778		if (len == sizeof(bootduid))
779			memcpy(bootduid, prop, sizeof(bootduid));
780	}
781
782	if (boothowto & RB_CONFIG) {
783#ifdef BOOT_CONFIG
784		user_config();
785#else
786		printf("kernel does not support -c; continuing..\n");
787#endif
788	}
789}
790
791void
792parse_bootargs(const char *bootargs)
793{
794	const char *cp = bootargs;
795
796	if (strncmp(cp, "bootduid=", strlen("bootduid=")) == 0)
797		cp = parse_bootduid(cp + strlen("bootduid="));
798
799	if (strncmp(cp, "bootmac=", strlen("bootmac=")) == 0)
800		cp = parse_bootmac(cp + strlen("bootmac="));
801
802	while (*cp != '-')
803		if (*cp++ == '\0')
804			return;
805	cp++;
806
807	while (*cp != 0) {
808		switch(*cp) {
809		case 'a':
810			boothowto |= RB_ASKNAME;
811			break;
812		case 'c':
813			boothowto |= RB_CONFIG;
814			break;
815		case 'd':
816			boothowto |= RB_KDB;
817			break;
818		case 's':
819			boothowto |= RB_SINGLE;
820			break;
821		default:
822			printf("unknown option `%c'\n", *cp);
823			break;
824		}
825		cp++;
826	}
827}
828
829const char *
830parse_bootduid(const char *bootarg)
831{
832	const char *cp = bootarg;
833	uint64_t duid = 0;
834	int digit, count = 0;
835
836	while (count < 16) {
837		if (*cp >= '0' && *cp <= '9')
838			digit = *cp - '0';
839		else if (*cp >= 'a' && *cp <= 'f')
840			digit = *cp - 'a' + 10;
841		else
842			break;
843		duid *= 16;
844		duid += digit;
845		count++;
846		cp++;
847	}
848
849	if (count > 0) {
850		memcpy(&bootduid, &duid, sizeof(bootduid));
851		return cp;
852	}
853
854	return bootarg;
855}
856
857const char *
858parse_bootmac(const char *bootarg)
859{
860	static uint8_t lladdr[6];
861	const char *cp = bootarg;
862	int digit, count = 0;
863
864	memset(lladdr, 0, sizeof(lladdr));
865
866	while (count < 12) {
867		if (*cp >= '0' && *cp <= '9')
868			digit = *cp - '0';
869		else if (*cp >= 'a' && *cp <= 'f')
870			digit = *cp - 'a' + 10;
871		else if (*cp == ':') {
872			cp++;
873			continue;
874		} else
875			break;
876		lladdr[count / 2] |= digit << (4 * !(count % 2));
877		count++;
878		cp++;
879	}
880
881	if (count > 0) {
882		bootmac = lladdr;
883		return cp;
884	}
885
886	return bootarg;
887}
888
889#define PSL_USER \
890    (PSL_SF | PSL_HV | PSL_EE | PSL_PR | PSL_ME | PSL_IR | PSL_DR | PSL_RI)
891
892void
893setregs(struct proc *p, struct exec_package *pack, u_long stack,
894    struct ps_strings *arginfo)
895{
896	struct trapframe *frame = p->p_md.md_regs;
897	struct pcb *pcb = &p->p_addr->u_pcb;
898
899	memset(frame, 0, sizeof(*frame));
900	frame->fixreg[1] = stack;
901	frame->fixreg[3] = arginfo->ps_nargvstr;
902	frame->fixreg[4] = (register_t)arginfo->ps_argvstr;
903	frame->fixreg[5] = (register_t)arginfo->ps_envstr;
904	frame->fixreg[6] = (register_t)pack->ep_auxinfo;
905	frame->fixreg[12] = pack->ep_entry;
906	frame->srr0 = pack->ep_entry;
907	frame->srr1 = PSL_USER;
908
909	memset(&pcb->pcb_slb, 0, sizeof(pcb->pcb_slb));
910	memset(&pcb->pcb_fpstate, 0, sizeof(pcb->pcb_fpstate));
911	pcb->pcb_flags = 0;
912}
913
914int
915sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip,
916    int info, int onstack)
917{
918	struct proc *p = curproc;
919	struct pcb *pcb = &p->p_addr->u_pcb;
920	struct trapframe *tf = p->p_md.md_regs;
921	struct sigframe *fp, frame;
922	siginfo_t *sip = NULL;
923	int i;
924
925	/* Allocate space for the signal handler context. */
926	if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
927	    !sigonstack(tf->fixreg[1]) && onstack)
928		fp = (struct sigframe *)
929		    trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size);
930	else
931		fp = (struct sigframe *)tf->fixreg[1];
932
933	fp = (struct sigframe *)(STACKALIGN(fp - 1) - 288);
934
935	/* Save FPU state to PCB if necessary. */
936	if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX) &&
937	    tf->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX)) {
938		tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
939		save_vsx(p);
940	}
941
942	/* Build stack frame for signal trampoline. */
943	memset(&frame, 0, sizeof(frame));
944	frame.sf_signum = sig;
945
946	/* Save register context. */
947	for (i = 0; i < 32; i++)
948		frame.sf_sc.sc_reg[i] = tf->fixreg[i];
949	frame.sf_sc.sc_lr = tf->lr;
950	frame.sf_sc.sc_cr = tf->cr;
951	frame.sf_sc.sc_xer = tf->xer;
952	frame.sf_sc.sc_ctr = tf->ctr;
953	frame.sf_sc.sc_pc = tf->srr0;
954	frame.sf_sc.sc_ps = PSL_USER;
955	frame.sf_sc.sc_vrsave = tf->vrsave;
956
957	/* Copy the saved FPU state into the frame if necessary. */
958	if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX)) {
959		memcpy(frame.sf_sc.sc_vsx, pcb->pcb_fpstate.fp_vsx,
960		    sizeof(pcb->pcb_fpstate.fp_vsx));
961		frame.sf_sc.sc_fpscr = pcb->pcb_fpstate.fp_fpscr;
962		frame.sf_sc.sc_vscr = pcb->pcb_fpstate.fp_vscr;
963	}
964
965	/* Save signal mask. */
966	frame.sf_sc.sc_mask = mask;
967
968	if (info) {
969		sip = &fp->sf_si;
970		frame.sf_si = *ksip;
971	}
972
973	frame.sf_sc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie;
974	if (copyout(&frame, fp, sizeof(frame)))
975		return 1;
976
977	/*
978	 * Build context to run handler in.
979	 */
980	tf->fixreg[1] = (register_t)fp;
981	tf->fixreg[3] = sig;
982	tf->fixreg[4] = (register_t)sip;
983	tf->fixreg[5] = (register_t)&fp->sf_sc;
984	tf->fixreg[12] = (register_t)catcher;
985
986	tf->srr0 = p->p_p->ps_sigcode;
987
988	return 0;
989}
990
991int
992sys_sigreturn(struct proc *p, void *v, register_t *retval)
993{
994	struct sys_sigreturn_args /* {
995		syscallarg(struct sigcontext *) sigcntxp;
996	} */ *uap = v;
997	struct sigcontext ksc, *scp = SCARG(uap, sigcntxp);
998	struct trapframe *tf = p->p_md.md_regs;
999	struct pcb *pcb = &p->p_addr->u_pcb;
1000	int error;
1001	int i;
1002
1003	if (PROC_PC(p) != p->p_p->ps_sigcoderet) {
1004		sigexit(p, SIGILL);
1005		return EPERM;
1006	}
1007
1008	if ((error = copyin(scp, &ksc, sizeof ksc)))
1009		return error;
1010
1011	if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) {
1012		sigexit(p, SIGILL);
1013		return EFAULT;
1014	}
1015
1016	/* Prevent reuse of the sigcontext cookie */
1017	ksc.sc_cookie = 0;
1018	(void)copyout(&ksc.sc_cookie, (caddr_t)scp +
1019	    offsetof(struct sigcontext, sc_cookie), sizeof (ksc.sc_cookie));
1020
1021	/* Make sure the processor mode has not been tampered with. */
1022	if (ksc.sc_ps != PSL_USER)
1023		return EINVAL;
1024
1025	/* Restore register context. */
1026	for (i = 0; i < 32; i++)
1027		tf->fixreg[i] = ksc.sc_reg[i];
1028	tf->lr = ksc.sc_lr;
1029	tf->cr = ksc.sc_cr;
1030	tf->xer = ksc.sc_xer;
1031	tf->ctr = ksc.sc_ctr;
1032	tf->srr0 = ksc.sc_pc;
1033	tf->srr1 = ksc.sc_ps;
1034	tf->vrsave = ksc.sc_vrsave;
1035
1036	/* Write saved FPU state back to PCB if necessary. */
1037	if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX)) {
1038		memcpy(pcb->pcb_fpstate.fp_vsx, ksc.sc_vsx,
1039		    sizeof(pcb->pcb_fpstate.fp_vsx));
1040		pcb->pcb_fpstate.fp_fpscr = ksc.sc_fpscr;
1041		pcb->pcb_fpstate.fp_vscr = ksc.sc_vscr;
1042	}
1043
1044	/* Restore signal mask. */
1045	p->p_sigmask = ksc.sc_mask & ~sigcantmask;
1046
1047	return EJUSTRETURN;
1048}
1049
1050/*
1051 * Notify the current process (p) that it has a signal pending,
1052 * process as soon as possible.
1053 */
1054void
1055signotify(struct proc *p)
1056{
1057	aston(p);
1058	cpu_kick(p->p_cpu);
1059}
1060
1061void	cpu_switchto_asm(struct proc *, struct proc *);
1062
1063void
1064cpu_switchto(struct proc *old, struct proc *new)
1065{
1066	if (old) {
1067		struct pcb *pcb = &old->p_addr->u_pcb;
1068		struct trapframe *tf = old->p_md.md_regs;
1069
1070		if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX) &&
1071		    tf->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX)) {
1072			tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
1073			save_vsx(old);
1074		}
1075
1076		pmap_clear_user_slb();
1077	}
1078
1079	cpu_switchto_asm(old, new);
1080}
1081
1082/*
1083 * machine dependent system variables.
1084 */
1085
1086int
1087cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
1088    size_t newlen, struct proc *p)
1089{
1090	int altivec = 1;	/* Altivec is always supported */
1091
1092	/* All sysctl names at this level are terminal. */
1093	if (namelen != 1)
1094		return ENOTDIR;		/* overloaded */
1095
1096	switch (name[0]) {
1097	case CPU_ALTIVEC:
1098		return (sysctl_rdint(oldp, oldlenp, newp, altivec));
1099	default:
1100		return EOPNOTSUPP;
1101	}
1102	/* NOTREACHED */
1103}
1104
1105void
1106consinit(void)
1107{
1108}
1109
1110void
1111opal_powerdown(void)
1112{
1113	int64_t error;
1114
1115	do {
1116		error = opal_cec_power_down(0);
1117		if (error == OPAL_BUSY_EVENT)
1118			opal_poll_events(NULL);
1119	} while (error == OPAL_BUSY || error == OPAL_BUSY_EVENT);
1120
1121	if (error != OPAL_SUCCESS)
1122		return;
1123
1124	/* Wait for the actual powerdown to happen. */
1125	for (;;)
1126		opal_poll_events(NULL);
1127}
1128
1129int	waittime = -1;
1130
1131__dead void
1132boot(int howto)
1133{
1134	if ((howto & RB_RESET) != 0)
1135		goto doreset;
1136
1137	if (cold) {
1138		if ((howto & RB_USERREQ) == 0)
1139			howto |= RB_HALT;
1140		goto haltsys;
1141	}
1142
1143	boothowto = howto;
1144	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
1145		waittime = 0;
1146		vfs_shutdown(curproc);
1147
1148		if ((howto & RB_TIMEBAD) == 0) {
1149			resettodr();
1150		} else {
1151			printf("WARNING: not updating battery clock\n");
1152		}
1153	}
1154	if_downall();
1155
1156	uvm_shutdown();
1157	splhigh();
1158	cold = 1;
1159
1160haltsys:
1161	config_suspend_all(DVACT_POWERDOWN);
1162
1163	if ((howto & RB_HALT) != 0) {
1164		if ((howto & RB_POWERDOWN) != 0)
1165			opal_powerdown();
1166
1167		printf("\n");
1168		printf("The operating system has halted.\n");
1169		printf("Please press any key to reboot.\n\n");
1170		cngetc();
1171	}
1172
1173doreset:
1174	printf("rebooting...\n");
1175	opal_cec_reboot();
1176
1177	for (;;)
1178		continue;
1179	/* NOTREACHED */
1180}
1181