1/*	$OpenBSD: Locore.c,v 1.18 2023/06/01 17:24:56 krw Exp $	*/
2/*	$NetBSD: Locore.c,v 1.1 2000/08/20 14:58:36 mrg Exp $	*/
3
4/*
5 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6 * Copyright (C) 1995, 1996 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <lib/libsa/stand.h>
36
37#include "openfirm.h"
38
39#include <machine/cpu.h>
40
41#ifdef SOFTRAID
42#include <dev/softraidvar.h>
43#include <lib/libsa/softraid.h>
44#endif
45
46static vaddr_t OF_claim_virt(vaddr_t vaddr, int len);
47static vaddr_t OF_alloc_virt(int len, int align);
48static int OF_free_virt(vaddr_t vaddr, int len);
49static int OF_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode);
50static paddr_t OF_alloc_phys(int len, int align);
51static int OF_free_phys(paddr_t paddr, int len);
52
53extern int openfirmware(void *);
54
55void setup(void);
56
57__dead void
58_rtt(void)
59{
60	struct {
61		cell_t name;
62		cell_t nargs;
63		cell_t nreturns;
64	} args;
65
66#ifdef SOFTRAID
67	sr_clear_keys();
68#endif
69
70	args.name = ADR2CELL("exit");
71	args.nargs = 0;
72	args.nreturns = 0;
73	openfirmware(&args);
74	while (1);			/* just in case */
75}
76
77void
78OF_enter(void)
79{
80	struct {
81		cell_t name;
82		cell_t nargs;
83		cell_t nreturns;
84	} args;
85
86	args.name = ADR2CELL("enter");
87	args.nargs = 0;
88	args.nreturns = 0;
89	openfirmware(&args);
90}
91
92int
93OF_finddevice(char *name)
94{
95	struct {
96		cell_t name;
97		cell_t nargs;
98		cell_t nreturns;
99		cell_t device;
100		cell_t phandle;
101	} args;
102
103	args.name = ADR2CELL("finddevice");
104	args.nargs = 1;
105	args.nreturns = 1;
106	args.device = ADR2CELL(name);
107	if (openfirmware(&args) == -1)
108		return -1;
109	return args.phandle;
110}
111
112int
113OF_instance_to_package(int ihandle)
114{
115	struct {
116		cell_t name;
117		cell_t nargs;
118		cell_t nreturns;
119		cell_t ihandle;
120		cell_t phandle;
121	} args;
122
123	args.name = ADR2CELL("instance-to-package");
124	args.nargs = 1;
125	args.nreturns = 1;
126	args.ihandle = HDL2CELL(ihandle);
127	if (openfirmware(&args) == -1)
128		return -1;
129	return args.phandle;
130}
131
132int
133OF_getprop(int handle, char *prop, void *buf, int buflen)
134{
135	struct {
136		cell_t name;
137		cell_t nargs;
138		cell_t nreturns;
139		cell_t phandle;
140		cell_t prop;
141		cell_t buf;
142		cell_t buflen;
143		cell_t size;
144	} args;
145
146	args.name = ADR2CELL("getprop");
147	args.nargs = 4;
148	args.nreturns = 1;
149	args.phandle = HDL2CELL(handle);
150	args.prop = ADR2CELL(prop);
151	args.buf = ADR2CELL(buf);
152	args.buflen = buflen;
153	if (openfirmware(&args) == -1)
154		return -1;
155	return args.size;
156}
157
158int
159OF_open(char *dname)
160{
161	struct {
162		cell_t name;
163		cell_t nargs;
164		cell_t nreturns;
165		cell_t dname;
166		cell_t handle;
167	} args;
168
169	args.name = ADR2CELL("open");
170	args.nargs = 1;
171	args.nreturns = 1;
172	args.dname = ADR2CELL(dname);
173	if (openfirmware(&args) == -1 ||
174	    args.handle == 0)
175		return -1;
176	return args.handle;
177}
178
179void
180OF_close(int handle)
181{
182	struct {
183		cell_t name;
184		cell_t nargs;
185		cell_t nreturns;
186		cell_t handle;
187	} args;
188
189	args.name = ADR2CELL("close");
190	args.nargs = 1;
191	args.nreturns = 0;
192	args.handle = HDL2CELL(handle);
193	openfirmware(&args);
194}
195
196int
197OF_write(int handle, void *addr, int len)
198{
199	struct {
200		cell_t name;
201		cell_t nargs;
202		cell_t nreturns;
203		cell_t ihandle;
204		cell_t addr;
205		cell_t len;
206		cell_t actual;
207	} args;
208
209	args.name = ADR2CELL("write");
210	args.nargs = 3;
211	args.nreturns = 1;
212	args.ihandle = HDL2CELL(handle);
213	args.addr = ADR2CELL(addr);
214	args.len = len;
215	if (openfirmware(&args) == -1)
216		return -1;
217	return args.actual;
218}
219
220int
221OF_read(int handle, void *addr, int len)
222{
223	struct {
224		cell_t name;
225		cell_t nargs;
226		cell_t nreturns;
227		cell_t ihandle;
228		cell_t addr;
229		cell_t len;
230		cell_t actual;
231	} args;
232
233	args.name = ADR2CELL("read");
234	args.nargs = 3;
235	args.nreturns = 1;
236	args.ihandle = HDL2CELL(handle);
237	args.addr = ADR2CELL(addr);
238	args.len = len;
239	if (openfirmware(&args) == -1) {
240		return -1;
241	}
242	return args.actual;
243}
244
245int
246OF_seek(int handle, u_quad_t pos)
247{
248	struct {
249		cell_t name;
250		cell_t nargs;
251		cell_t nreturns;
252		cell_t handle;
253		cell_t poshi;
254		cell_t poslo;
255		cell_t status;
256	} args;
257
258	args.name = ADR2CELL("seek");
259	args.nargs = 3;
260	args.nreturns = 1;
261	args.handle = HDL2CELL(handle);
262	args.poshi = HDQ2CELL_HI(pos);
263	args.poslo = HDQ2CELL_LO(pos);
264	if (openfirmware(&args) == -1) {
265		return -1;
266	}
267	return args.status;
268}
269
270void
271OF_release(void *virt, u_int size)
272{
273	struct {
274		cell_t name;
275		cell_t nargs;
276		cell_t nreturns;
277		cell_t virt;
278		cell_t size;
279	} args;
280
281	args.name = ADR2CELL("release");
282	args.nargs = 2;
283	args.nreturns = 0;
284	args.virt = ADR2CELL(virt);
285	args.size = size;
286	openfirmware(&args);
287}
288
289int
290OF_milliseconds(void)
291{
292	struct {
293		cell_t name;
294		cell_t nargs;
295		cell_t nreturns;
296		cell_t ms;
297	} args;
298
299	args.name = ADR2CELL("milliseconds");
300	args.nargs = 0;
301	args.nreturns = 1;
302	openfirmware(&args);
303	return args.ms;
304}
305
306void
307OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
308{
309	extern int64_t romp;
310
311	entry(0, arg, len, (unsigned long)romp, (unsigned long)romp);
312	panic("OF_chain: kernel returned!");
313	__asm("ta 2" : :);
314}
315
316static u_int stdin;
317static u_int stdout;
318static u_int mmuh = -1;
319static u_int memh = -1;
320
321void
322setup(void)
323{
324	u_int chosen;
325
326	if ((chosen = OF_finddevice("/chosen")) == -1)
327		_rtt();
328	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) != sizeof(stdin)
329	    || OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) != sizeof(stdout)
330	    || OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) != sizeof(mmuh)
331	    || OF_getprop(chosen, "memory", &memh, sizeof(memh)) != sizeof(memh))
332		_rtt();
333}
334
335/*
336 * The following need either the handle to memory or the handle to the MMU.
337 */
338
339/*
340 * Grab some address space from the prom
341 *
342 * Only works while the prom is actively mapping us.
343 */
344static vaddr_t
345OF_claim_virt(vaddr_t vaddr, int len)
346{
347	struct {
348		cell_t name;
349		cell_t nargs;
350		cell_t nreturns;
351		cell_t method;
352		cell_t ihandle;
353		cell_t align;
354		cell_t len;
355		cell_t vaddr;
356		cell_t status;
357		cell_t retaddr;
358	} args;
359
360	args.name = ADR2CELL("call-method");
361	args.nargs = 5;
362	args.nreturns = 2;
363	args.method = ADR2CELL("claim");
364	args.ihandle = HDL2CELL(mmuh);
365	args.align = 0;
366	args.len = len;
367	args.vaddr = ADR2CELL(vaddr);
368	if (openfirmware(&args) != 0)
369		return -1LL;
370	return (vaddr_t)args.retaddr;
371}
372
373/*
374 * Request some address space from the prom
375 *
376 * Only works while the prom is actively mapping us.
377 */
378static vaddr_t
379OF_alloc_virt(int len, int align)
380{
381	int retaddr=-1;
382	struct {
383		cell_t name;
384		cell_t nargs;
385		cell_t nreturns;
386		cell_t method;
387		cell_t ihandle;
388		cell_t align;
389		cell_t len;
390		cell_t status;
391		cell_t retaddr;
392	} args;
393
394	args.name = ADR2CELL("call-method");
395	args.nargs = 4;
396	args.nreturns = 2;
397	args.method = ADR2CELL("claim");
398	args.ihandle = HDL2CELL(mmuh);
399	args.align = align;
400	args.len = len;
401	args.retaddr = ADR2CELL(&retaddr);
402	if (openfirmware(&args) != 0)
403		return -1LL;
404	return (vaddr_t)args.retaddr;
405}
406
407/*
408 * Release some address space to the prom
409 *
410 * Only works while the prom is actively mapping us.
411 */
412static int
413OF_free_virt(vaddr_t vaddr, int len)
414{
415	struct {
416		cell_t name;
417		cell_t nargs;
418		cell_t nreturns;
419		cell_t method;
420		cell_t ihandle;
421		cell_t len;
422		cell_t vaddr;
423	} args;
424
425	args.name = ADR2CELL("call-method");
426	args.nargs = 4;
427	args.nreturns = 0;
428	args.method = ADR2CELL("release");
429	args.ihandle = HDL2CELL(mmuh);
430	args.vaddr = ADR2CELL(vaddr);
431	args.len = len;
432	return openfirmware(&args);
433}
434
435
436/*
437 * Have prom map in some memory
438 *
439 * Only works while the prom is actively mapping us.
440 */
441static int
442OF_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode)
443{
444	struct {
445		cell_t name;
446		cell_t nargs;
447		cell_t nreturns;
448		cell_t method;
449		cell_t ihandle;
450		cell_t mode;
451		cell_t size;
452		cell_t vaddr;
453		cell_t paddr_hi;
454		cell_t paddr_lo;
455	} args;
456
457	args.name = ADR2CELL("call-method");
458	args.nargs = 7;
459	args.nreturns = 0;
460	args.method = ADR2CELL("map");
461	args.ihandle = HDL2CELL(mmuh);
462	args.mode = mode;
463	args.size = size;
464	args.vaddr = ADR2CELL(vaddr);
465	args.paddr_hi = HDQ2CELL_HI(paddr);
466	args.paddr_lo = HDQ2CELL_LO(paddr);
467	return openfirmware(&args);
468}
469
470
471/*
472 * Request some RAM from the prom
473 *
474 * Only works while the prom is actively mapping us.
475 */
476static paddr_t
477OF_alloc_phys(int len, int align)
478{
479	struct {
480		cell_t name;
481		cell_t nargs;
482		cell_t nreturns;
483		cell_t method;
484		cell_t ihandle;
485		cell_t align;
486		cell_t len;
487		cell_t status;
488		cell_t phys_hi;
489		cell_t phys_lo;
490	} args;
491
492	args.name = ADR2CELL("call-method");
493	args.nargs = 4;
494	args.nreturns = 3;
495	args.method = ADR2CELL("claim");
496	args.ihandle = HDL2CELL(memh);
497	args.align = align;
498	args.len = len;
499	if (openfirmware(&args) != 0)
500		return -1LL;
501	return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
502}
503
504
505/*
506 * Free some RAM to prom
507 *
508 * Only works while the prom is actively mapping us.
509 */
510static int
511OF_free_phys(paddr_t phys, int len)
512{
513	struct {
514		cell_t name;
515		cell_t nargs;
516		cell_t nreturns;
517		cell_t method;
518		cell_t ihandle;
519		cell_t len;
520		cell_t phys_hi;
521		cell_t phys_lo;
522	} args;
523
524	args.name = ADR2CELL("call-method");
525	args.nargs = 5;
526	args.nreturns = 0;
527	args.method = ADR2CELL("release");
528	args.ihandle = HDL2CELL(memh);
529	args.len = len;
530	args.phys_hi = HDQ2CELL_HI(phys);
531	args.phys_lo = HDQ2CELL_LO(phys);
532	return openfirmware(&args);
533}
534
535
536/*
537 * Claim virtual memory -- does not map it in.
538 */
539
540void *
541OF_claim(void *virt, u_int size, u_int align)
542{
543	/*
544	 * Sun Ultra machines run the firmware with VM enabled,
545	 * so you need to handle allocating and mapping both
546	 * virtual and physical memory.  Ugh.
547	 */
548	paddr_t paddr;
549	void * newvirt = NULL;
550
551	if (virt == NULL) {
552		virt = (void *)OF_alloc_virt(size, align);
553		if (virt == (void *)-1LL) {
554			printf("OF_alloc_virt(%d,%d) failed w/%x\n",
555			       size, align, virt);
556			return virt;
557		}
558	} else {
559		newvirt = (void *)OF_claim_virt((vaddr_t)virt, size);
560		if (newvirt == (void *)-1LL) {
561			printf("OF_claim_virt(%x,%d) failed w/%x\n",
562			       virt, size, newvirt);
563			return newvirt;
564		}
565		virt = newvirt;
566	}
567	if ((paddr = OF_alloc_phys(size, align)) == (paddr_t)-1LL) {
568		printf("OF_alloc_phys(%d,%d) failed\n", size, align);
569		OF_free_virt((vaddr_t)virt, size);
570		return (void *)-1LL;
571	}
572	if (OF_map_phys(paddr, size, (vaddr_t)virt, -1) == -1) {
573		printf("OF_map_phys(%x,%d,%x,%d) failed\n",
574		       paddr, size, virt, -1);
575		OF_free_phys((paddr_t)paddr, size);
576		OF_free_virt((vaddr_t)virt, size);
577		return (void *)-1LL;
578	}
579	return virt;
580}
581
582int
583OF_peer(int phandle)
584{
585	struct {
586		cell_t name;
587		cell_t nargs;
588		cell_t nreturns;
589		cell_t phandle;
590		cell_t sibling;
591	} args;
592
593	args.name = ADR2CELL("peer");
594	args.nargs = 1;
595	args.nreturns = 1;
596	args.phandle = HDL2CELL(phandle);
597	if (openfirmware(&args) == -1)
598		return 0;
599	return args.sibling;
600}
601
602int
603OF_child(int phandle)
604{
605	struct {
606		cell_t name;
607		cell_t nargs;
608		cell_t nreturns;
609		cell_t phandle;
610		cell_t child;
611	} args;
612
613	args.name = ADR2CELL("child");
614	args.nargs = 1;
615	args.nreturns = 1;
616	args.phandle = HDL2CELL(phandle);
617	if (openfirmware(&args) == -1)
618		return 0;
619	return args.child;
620}
621
622int
623OF_parent(int phandle)
624{
625	struct {
626		cell_t name;
627		cell_t nargs;
628		cell_t nreturns;
629		cell_t phandle;
630		cell_t parent;
631	} args;
632
633	args.name = ADR2CELL("parent");
634	args.nargs = 1;
635	args.nreturns = 1;
636	args.phandle = HDL2CELL(phandle);
637	if (openfirmware(&args) == -1)
638		return 0;
639	return args.parent;
640}
641
642int
643OF_package_to_path(int phandle, char *buf, int buflen)
644{
645	struct {
646		cell_t name;
647		cell_t nargs;
648		cell_t nreturns;
649		cell_t phandle;
650		cell_t buf;
651		cell_t buflen;
652		cell_t length;
653	} args;
654
655	if (buflen > PAGE_SIZE)
656		return -1;
657	args.name = ADR2CELL("package-to-path");
658	args.nargs = 3;
659	args.nreturns = 1;
660	args.phandle = HDL2CELL(phandle);
661	args.buf = ADR2CELL(buf);
662	args.buflen = buflen;
663	if (openfirmware(&args) < 0)
664		return -1;
665	return args.length;
666}
667
668void
669putchar(int c)
670{
671	char ch = c;
672
673	if (c == '\n')
674		putchar('\r');
675	OF_write(stdout, &ch, 1);
676}
677
678int
679getchar(void)
680{
681	unsigned char ch = '\0';
682	int l;
683
684	while ((l = OF_read(stdin, &ch, 1)) != 1)
685		if (l != -2 && l != 0)
686			return -1;
687	return ch;
688}
689
690int
691cngetc(void)
692{
693	return getchar();
694}
695