1/*	$NetBSD: Locore.c,v 1.17 2022/05/14 07:11:23 hgutch Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <lib/libsa/stand.h>
35#include "openfirm.h"
36
37#include <machine/cpu.h>
38#include <machine/vmparam.h>
39
40/*
41 * We are trying to boot a sparc v9 cpu, so openfirmware has to be 64bit,
42 * and the kernel we load will be dealing with 64bits too (even if it is
43 * a 32bit kernel.
44 * Make sure we picked up the right defines:
45 */
46__CTASSERT(sizeof(cell_t)==8);
47__CTASSERT(sizeof(paddr_t)==8);
48
49extern int openfirmware(void *);
50
51
52__dead void
53_rtt(void)
54{
55
56	OF_exit();
57}
58
59void __attribute__((__noreturn__))
60OF_exit(void)
61{
62	struct {
63		cell_t name;
64		cell_t nargs;
65		cell_t nreturns;
66	} args;
67
68	args.name = ADR2CELL("exit");
69	args.nargs = 0;
70	args.nreturns = 0;
71	openfirmware(&args);
72
73	printf("OF_exit failed");
74	for (;;)
75		continue;
76}
77
78void
79OF_enter(void)
80{
81	struct {
82		cell_t name;
83		cell_t nargs;
84		cell_t nreturns;
85	} args;
86
87	args.name = ADR2CELL("enter");
88	args.nargs = 0;
89	args.nreturns = 0;
90	openfirmware(&args);
91}
92
93int
94OF_finddevice(const char *name)
95{
96	struct {
97		cell_t name;
98		cell_t nargs;
99		cell_t nreturns;
100		cell_t device;
101		cell_t phandle;
102	} args;
103
104	args.name = ADR2CELL("finddevice");
105	args.nargs = 1;
106	args.nreturns = 1;
107	args.device = ADR2CELL(name);
108	if (openfirmware(&args) == -1)
109		return -1;
110	return args.phandle;
111}
112
113int
114OF_instance_to_package(int ihandle)
115{
116	struct {
117		cell_t name;
118		cell_t nargs;
119		cell_t nreturns;
120		cell_t ihandle;
121		cell_t phandle;
122	} args;
123
124	args.name = ADR2CELL("instance-to-package");
125	args.nargs = 1;
126	args.nreturns = 1;
127	args.ihandle = HDL2CELL(ihandle);
128	if (openfirmware(&args) == -1)
129		return -1;
130	return args.phandle;
131}
132
133int
134OF_instance_to_path(int ihandle, char *buf, int buflen)
135{
136	struct {
137		cell_t name;
138		cell_t nargs;
139		cell_t nreturns;
140		cell_t ihandle;
141		cell_t buf;
142		cell_t buflen;
143		cell_t length;
144	} args;
145
146	args.name = ADR2CELL("instance-to-path");
147	args.nargs = 3;
148	args.nreturns = 1;
149	args.ihandle = HDL2CELL(ihandle);
150	args.buf = ADR2CELL(buf);
151	args.buflen = buflen;
152	if (openfirmware(&args) < 0)
153		return -1;
154	return args.length;
155}
156
157int
158OF_parent(int phandle)
159{
160	struct {
161		cell_t name;
162		cell_t nargs;
163		cell_t nreturns;
164		cell_t phandle;
165		cell_t parent;
166	} args;
167
168	args.name = ADR2CELL("parent");
169	args.nargs = 1;
170	args.nreturns = 1;
171	args.phandle = HDL2CELL(phandle);
172	if (openfirmware(&args) == -1)
173		return 0;
174	return args.parent;
175}
176
177int
178OF_getprop(int handle, const char *prop, void *buf, int buflen)
179{
180	struct {
181		cell_t name;
182		cell_t nargs;
183		cell_t nreturns;
184		cell_t phandle;
185		cell_t prop;
186		cell_t buf;
187		cell_t buflen;
188		cell_t size;
189	} args;
190
191	args.name = ADR2CELL("getprop");
192	args.nargs = 4;
193	args.nreturns = 1;
194	args.phandle = HDL2CELL(handle);
195	args.prop = ADR2CELL(prop);
196	args.buf = ADR2CELL(buf);
197	args.buflen = buflen;
198	if (openfirmware(&args) == -1)
199		return -1;
200	return args.size;
201}
202
203#ifdef	__notyet__	/* Has a bug on FirePower */
204int
205OF_setprop(u_int handle, char *prop, void *buf, int len)
206{
207	struct {
208		cell_t name;
209		cell_t nargs;
210		cell_t nreturns;
211		cell_t phandle;
212		cell_t prop;
213		cell_t buf;
214		cell_t len;
215		cell_t size;
216	} args;
217
218	args.name = ADR2CELL("setprop");
219	args.nargs = 4;
220	args.nreturns = 1;
221	args.phandle = HDL2CELL(handle);
222	args.prop = ADR2CELL(prop);
223	args.buf = ADR2CELL(buf);
224	args.len = len;
225	if (openfirmware(&args) == -1)
226		return -1;
227	return args.size;
228}
229#endif
230
231int
232OF_interpret(const char *cmd, int nargs, int nreturns, ...)
233{
234	va_list ap;
235	struct {
236		cell_t name;
237		cell_t nargs;
238		cell_t nreturns;
239		cell_t slot[16];
240	} args;
241	cell_t status;
242	int i = 0;
243
244	args.name = ADR2CELL("interpret");
245	args.nargs = ++nargs;
246	args.nreturns = ++nreturns;
247	args.slot[i++] = ADR2CELL(cmd);
248	va_start(ap, nreturns);
249	while (i < nargs) {
250		args.slot[i++] = va_arg(ap, cell_t);
251	}
252	if (openfirmware(&args) == -1) {
253		va_end(ap);
254		return (-1);
255	}
256	status = args.slot[i++];
257	while (i < nargs+nreturns) {
258		*va_arg(ap, cell_t *) = args.slot[i++];
259	}
260	va_end(ap);
261
262	return status;
263}
264
265int
266OF_package_to_path(int phandle, char *buf, int buflen)
267{
268	struct {
269		cell_t name;
270		cell_t nargs;
271		cell_t nreturns;
272		cell_t phandle;
273		cell_t buf;
274		cell_t buflen;
275		cell_t length;
276	} args;
277
278	if (buflen > PAGE_SIZE)
279		return -1;
280	args.name = ADR2CELL("package-to-path");
281	args.nargs = 3;
282	args.nreturns = 1;
283	args.phandle = HDL2CELL(phandle);
284	args.buf = ADR2CELL(buf);
285	args.buflen = buflen;
286	if (openfirmware(&args) < 0)
287		return -1;
288	return args.length;
289}
290
291int
292OF_open(const char *dname)
293{
294	struct {
295		cell_t name;
296		cell_t nargs;
297		cell_t nreturns;
298		cell_t dname;
299		cell_t handle;
300	} args;
301
302	args.name = ADR2CELL("open");
303	args.nargs = 1;
304	args.nreturns = 1;
305	args.dname = ADR2CELL(dname);
306	if (openfirmware(&args) == -1 ||
307	    args.handle == 0)
308		return -1;
309	return args.handle;
310}
311
312void
313OF_close(int handle)
314{
315	struct {
316		cell_t name;
317		cell_t nargs;
318		cell_t nreturns;
319		cell_t handle;
320	} args;
321
322	args.name = ADR2CELL("close");
323	args.nargs = 1;
324	args.nreturns = 0;
325	args.handle = HDL2CELL(handle);
326	openfirmware(&args);
327}
328
329int
330OF_write(int handle, const void *addr, int len)
331{
332	struct {
333		cell_t name;
334		cell_t nargs;
335		cell_t nreturns;
336		cell_t ihandle;
337		cell_t addr;
338		cell_t len;
339		cell_t actual;
340	} args;
341
342	args.name = ADR2CELL("write");
343	args.nargs = 3;
344	args.nreturns = 1;
345	args.ihandle = HDL2CELL(handle);
346	args.addr = ADR2CELL(addr);
347	args.len = len;
348	if (openfirmware(&args) == -1)
349		return -1;
350	return args.actual;
351}
352
353int
354OF_read(int handle, void *addr, int len)
355{
356	struct {
357		cell_t name;
358		cell_t nargs;
359		cell_t nreturns;
360		cell_t ihandle;
361		cell_t addr;
362		cell_t len;
363		cell_t actual;
364	} args;
365
366	args.name = ADR2CELL("read");
367	args.nargs = 3;
368	args.nreturns = 1;
369	args.ihandle = HDL2CELL(handle);
370	args.addr = ADR2CELL(addr);
371	args.len = len;
372	if (openfirmware(&args) == -1) {
373		return -1;
374	}
375	return args.actual;
376}
377
378int
379OF_seek(int handle, u_quad_t pos)
380{
381	struct {
382		cell_t name;
383		cell_t nargs;
384		cell_t nreturns;
385		cell_t handle;
386		cell_t poshi;
387		cell_t poslo;
388		cell_t status;
389	} args;
390
391	args.name = ADR2CELL("seek");
392	args.nargs = 3;
393	args.nreturns = 1;
394	args.handle = HDL2CELL(handle);
395	args.poshi = HDQ2CELL_HI(pos);
396	args.poslo = HDQ2CELL_LO(pos);
397	if (openfirmware(&args) == -1) {
398		return -1;
399	}
400	return args.status;
401}
402
403void
404OF_release(void *virt, u_int size)
405{
406	struct {
407		cell_t name;
408		cell_t nargs;
409		cell_t nreturns;
410		cell_t virt;
411		cell_t size;
412	} args;
413
414	args.name = ADR2CELL("release");
415	args.nargs = 2;
416	args.nreturns = 0;
417	args.virt = ADR2CELL(virt);
418	args.size = size;
419	openfirmware(&args);
420}
421
422int
423OF_milliseconds(void)
424{
425	struct {
426		cell_t name;
427		cell_t nargs;
428		cell_t nreturns;
429		cell_t ms;
430	} args;
431
432	args.name = ADR2CELL("milliseconds");
433	args.nargs = 0;
434	args.nreturns = 1;
435	openfirmware(&args);
436	return args.ms;
437}
438
439int
440OF_peer(int phandle)
441{
442	struct {
443		cell_t name;
444		cell_t nargs;
445		cell_t nreturns;
446		cell_t phandle;
447		cell_t sibling;
448	} args;
449
450	args.name = ADR2CELL("peer");
451	args.nargs = 1;
452	args.nreturns = 1;
453	args.phandle = HDL2CELL(phandle);
454	if (openfirmware(&args) == -1)
455		return 0;
456	return args.sibling;
457}
458
459int
460OF_child(int phandle)
461{
462	struct {
463		cell_t name;
464		cell_t nargs;
465		cell_t nreturns;
466		cell_t phandle;
467		cell_t child;
468	} args;
469
470	args.name = ADR2CELL("child");
471	args.nargs = 1;
472	args.nreturns = 1;
473	args.phandle = HDL2CELL(phandle);
474	if (openfirmware(&args) == -1)
475		return 0;
476	return args.child;
477}
478
479static u_int mmuh = -1;
480static u_int memh = -1;
481
482void
483OF_initialize(void)
484{
485	u_int chosen;
486
487	if ( (chosen = OF_finddevice("/chosen")) == -1) {
488		OF_exit();
489	}
490	if (OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) != sizeof(mmuh)
491	    || OF_getprop(chosen, "memory", &memh, sizeof(memh)) != sizeof(memh))
492		OF_exit();
493}
494
495/*
496 * The following need either the handle to memory or the handle to the MMU.
497 */
498
499/*
500 * Grab some address space from the prom
501 *
502 * Only works while the prom is actively mapping us.
503 */
504vaddr_t
505OF_claim_virt(vaddr_t vaddr, int len)
506{
507	struct {
508		cell_t name;
509		cell_t nargs;
510		cell_t nreturns;
511		cell_t method;
512		cell_t ihandle;
513		cell_t align;
514		cell_t len;
515		cell_t vaddr;
516		cell_t status;
517		cell_t retaddr;
518	} args;
519
520#ifdef	__notyet
521	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
522		OF_printf("OF_claim_virt: cannot get mmuh\r\n");
523		return -1LL;
524	}
525#endif
526	args.name = ADR2CELL("call-method");
527	args.nargs = 5;
528	args.nreturns = 2;
529	args.method = ADR2CELL("claim");
530	args.ihandle = HDL2CELL(mmuh);
531	args.align = 0;
532	args.len = len;
533	args.vaddr = ADR2CELL(vaddr);
534	if (openfirmware(&args) != 0)
535		return -1LL;
536	return (vaddr_t)args.retaddr;
537}
538
539/*
540 * Request some address space from the prom
541 *
542 * Only works while the prom is actively mapping us.
543 */
544vaddr_t
545OF_alloc_virt(int len, int align)
546{
547	int retaddr=-1;
548	struct {
549		cell_t name;
550		cell_t nargs;
551		cell_t nreturns;
552		cell_t method;
553		cell_t ihandle;
554		cell_t align;
555		cell_t len;
556		cell_t status;
557		cell_t retaddr;
558	} args;
559
560#ifdef	__notyet
561	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
562		OF_printf("OF_alloc_virt: cannot get mmuh\r\n");
563		return -1LL;
564	}
565#endif
566	args.name = ADR2CELL("call-method");
567	args.nargs = 4;
568	args.nreturns = 2;
569	args.method = ADR2CELL("claim");
570	args.ihandle = HDL2CELL(mmuh);
571	args.align = align;
572	args.len = len;
573	args.retaddr = ADR2CELL(&retaddr);
574	if (openfirmware(&args) != 0)
575		return -1LL;
576	return (vaddr_t)args.retaddr;
577}
578
579/*
580 * Release some address space to the prom
581 *
582 * Only works while the prom is actively mapping us.
583 */
584int
585OF_free_virt(vaddr_t vaddr, int len)
586{
587	struct {
588		cell_t name;
589		cell_t nargs;
590		cell_t nreturns;
591		cell_t method;
592		cell_t ihandle;
593		cell_t len;
594		cell_t vaddr;
595	} args;
596
597#ifdef	__notyet
598	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
599		OF_printf("OF_claim_virt: cannot get mmuh\r\n");
600		return -1;
601	}
602#endif
603	args.name = ADR2CELL("call-method");
604	args.nargs = 4;
605	args.nreturns = 0;
606	args.method = ADR2CELL("release");
607	args.ihandle = HDL2CELL(mmuh);
608	args.vaddr = ADR2CELL(vaddr);
609	args.len = len;
610	return openfirmware(&args);
611}
612
613
614/*
615 * Unmap some address space
616 *
617 * Only works while the prom is actively mapping us.
618 */
619int
620OF_unmap_virt(vaddr_t vaddr, int len)
621{
622	struct {
623		cell_t name;
624		cell_t nargs;
625		cell_t nreturns;
626		cell_t method;
627		cell_t ihandle;
628		cell_t len;
629		cell_t vaddr;
630	} args;
631
632#ifdef	__notyet
633	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
634		OF_printf("OF_claim_virt: cannot get mmuh\r\n");
635		return -1;
636	}
637#endif
638	args.name = ADR2CELL("call-method");
639	args.nargs = 4;
640	args.nreturns = 0;
641	args.method = ADR2CELL("unmap");
642	args.ihandle = HDL2CELL(mmuh);
643	args.vaddr = ADR2CELL(vaddr);
644	args.len = len;
645	return openfirmware(&args);
646}
647
648/*
649 * Have prom map in some memory
650 *
651 * Only works while the prom is actively mapping us.
652 */
653vaddr_t
654OF_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode)
655{
656	struct {
657		cell_t name;
658		cell_t nargs;
659		cell_t nreturns;
660		cell_t method;
661		cell_t ihandle;
662		cell_t mode;
663		cell_t size;
664		cell_t vaddr;
665		cell_t paddr_hi;
666		cell_t paddr_lo;
667	} args;
668
669#ifdef	__notyet
670	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
671		OF_printf("OF_map_phys: cannot get mmuh\r\n");
672		return 0LL;
673	}
674#endif
675	args.name = ADR2CELL("call-method");
676	args.nargs = 7;
677	args.nreturns = 0;
678	args.method = ADR2CELL("map");
679	args.ihandle = HDL2CELL(mmuh);
680	args.mode = mode;
681	args.size = size;
682	args.vaddr = ADR2CELL(vaddr);
683	args.paddr_hi = HDQ2CELL_HI(paddr);
684	args.paddr_lo = HDQ2CELL_LO(paddr);
685
686	if (openfirmware(&args) == -1)
687		return -1;
688	return 0;
689}
690
691
692/*
693 * Request some RAM from the prom
694 *
695 * Only works while the prom is actively mapping us.
696 */
697paddr_t
698OF_alloc_phys(int len, int align)
699{
700	struct {
701		cell_t name;
702		cell_t nargs;
703		cell_t nreturns;
704		cell_t method;
705		cell_t ihandle;
706		cell_t align;
707		cell_t len;
708		cell_t status;
709		cell_t phys_hi;
710		cell_t phys_lo;
711	} args;
712
713#ifdef	__notyet
714	if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
715		OF_printf("OF_alloc_phys: cannot get memh\r\n");
716		return -1LL;
717	}
718#endif
719	args.name = ADR2CELL("call-method");
720	args.nargs = 4;
721	args.nreturns = 3;
722	args.method = ADR2CELL("claim");
723	args.ihandle = HDL2CELL(memh);
724	args.align = align;
725	args.len = len;
726	if (openfirmware(&args) != 0)
727		return -1LL;
728	return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
729}
730
731/*
732 * Request some specific RAM from the prom
733 *
734 * Only works while the prom is actively mapping us.
735 */
736paddr_t
737OF_claim_phys(paddr_t phys, int len)
738{
739	struct {
740		cell_t name;
741		cell_t nargs;
742		cell_t nreturns;
743		cell_t method;
744		cell_t ihandle;
745		cell_t align;
746		cell_t len;
747		cell_t phys_hi;
748		cell_t phys_lo;
749		cell_t status;
750		cell_t res;
751		cell_t rphys_hi;
752		cell_t rphys_lo;
753	} args;
754
755#ifdef	__notyet
756	if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
757		OF_printf("OF_alloc_phys: cannot get memh\r\n");
758		return 0LL;
759	}
760#endif
761	args.name = ADR2CELL("call-method");
762	args.nargs = 6;
763	args.nreturns = 4;
764	args.method = ADR2CELL("claim");
765	args.ihandle = HDL2CELL(memh);
766	args.align = 0;
767	args.len = len;
768	args.phys_hi = HDQ2CELL_HI(phys);
769	args.phys_lo = HDQ2CELL_LO(phys);
770	if (openfirmware(&args) != 0)
771		return 0LL;
772	return (paddr_t)CELL2HDQ(args.rphys_hi, args.rphys_lo);
773}
774
775/*
776 * Free some RAM to prom
777 *
778 * Only works while the prom is actively mapping us.
779 */
780int
781OF_free_phys(paddr_t phys, int len)
782{
783	struct {
784		cell_t name;
785		cell_t nargs;
786		cell_t nreturns;
787		cell_t method;
788		cell_t ihandle;
789		cell_t len;
790		cell_t phys_hi;
791		cell_t phys_lo;
792	} args;
793
794#ifdef	__notyet
795	if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
796		OF_printf("OF_free_phys: cannot get memh\r\n");
797		return -1;
798	}
799#endif
800	args.name = ADR2CELL("call-method");
801	args.nargs = 5;
802	args.nreturns = 0;
803	args.method = ADR2CELL("release");
804	args.ihandle = HDL2CELL(memh);
805	args.len = len;
806	args.phys_hi = HDQ2CELL_HI(phys);
807	args.phys_lo = HDQ2CELL_LO(phys);
808	return openfirmware(&args);
809}
810
811
812/*
813 * Claim virtual memory -- does not map it in.
814 */
815
816void *
817OF_claim(void *virt, u_int size, u_int align)
818{
819#define SUNVMOF
820#ifndef SUNVMOF
821	struct {
822		cell_t name;
823		cell_t nargs;
824		cell_t nreturns;
825		cell_t virt;
826		cell_t size;
827		cell_t align;
828		cell_t baseaddr;
829	} args;
830
831
832	args.name = ADR2CELL("claim");
833	args.nargs = 3;
834	args.nreturns = 1;
835	args.virt = virt;
836	args.size = size;
837	args.align = align;
838	if (openfirmware(&args) == -1)
839		return (void *)-1;
840	return args.baseaddr;
841#else
842/*
843 * Sun Ultra machines run the firmware with VM enabled,
844 * so you need to handle allocating and mapping both
845 * virtual and physical memory.  Ugh.
846 */
847
848	paddr_t paddr;
849	void* newvirt = NULL;
850
851	if (virt == NULL) {
852		if ((virt = (void*)OF_alloc_virt(size, align)) == (void*)-1) {
853			printf("OF_alloc_virt(%d,%d) failed w/%p\n", size, align, virt);
854			return (void *)-1;
855		}
856	} else {
857		if ((newvirt = (void*)OF_claim_virt((vaddr_t)virt, size)) == (void*)-1) {
858			printf("OF_claim_virt(%p,%d) failed w/%p\n", virt, size, newvirt);
859			return (void *)-1;
860		}
861	}
862	if ((paddr = OF_alloc_phys(size, align)) == (paddr_t)-1) {
863		printf("OF_alloc_phys(%d,%d) failed\n", size, align);
864		OF_free_virt((vaddr_t)virt, size);
865		return (void *)-1;
866	}
867	if (OF_map_phys(paddr, size, (vaddr_t)virt, -1) == -1) {
868		printf("OF_map_phys(0x%lx,%d,%p,%d) failed\n",
869		    (u_long)paddr, size, virt, -1);
870		OF_free_phys((paddr_t)paddr, size);
871		OF_free_virt((vaddr_t)virt, size);
872		return (void *)-1;
873	}
874	return (void *)virt;
875#endif
876}
877