xref: /openbsd/sys/arch/sparc64/stand/ofwboot/Locore.c (revision cecf84d4)
1 /*	$OpenBSD: Locore.c,v 1.13 2014/12/11 10:52:07 stsp 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 #include "openfirm.h"
37 
38 #include <machine/cpu.h>
39 
40 static vaddr_t OF_claim_virt(vaddr_t vaddr, int len);
41 static vaddr_t OF_alloc_virt(int len, int align);
42 static int OF_free_virt(vaddr_t vaddr, int len);
43 static vaddr_t OF_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode);
44 static paddr_t OF_alloc_phys(int len, int align);
45 static int OF_free_phys(paddr_t paddr, int len);
46 
47 extern int openfirmware(void *);
48 
49 void setup(void);
50 
51 __dead void
52 _rtt(void)
53 {
54 	struct {
55 		cell_t name;
56 		cell_t nargs;
57 		cell_t nreturns;
58 	} args;
59 
60 #ifdef SOFTRAID
61 	sr_clear_keys();
62 #endif
63 
64 	args.name = ADR2CELL("exit");
65 	args.nargs = 0;
66 	args.nreturns = 0;
67 	openfirmware(&args);
68 	while (1);			/* just in case */
69 }
70 
71 void
72 OF_enter(void)
73 {
74 	struct {
75 		cell_t name;
76 		cell_t nargs;
77 		cell_t nreturns;
78 	} args;
79 
80 	args.name = ADR2CELL("enter");
81 	args.nargs = 0;
82 	args.nreturns = 0;
83 	openfirmware(&args);
84 }
85 
86 int
87 OF_finddevice(char *name)
88 {
89 	struct {
90 		cell_t name;
91 		cell_t nargs;
92 		cell_t nreturns;
93 		cell_t device;
94 		cell_t phandle;
95 	} args;
96 
97 	args.name = ADR2CELL("finddevice");
98 	args.nargs = 1;
99 	args.nreturns = 1;
100 	args.device = ADR2CELL(name);
101 	if (openfirmware(&args) == -1)
102 		return -1;
103 	return args.phandle;
104 }
105 
106 int
107 OF_instance_to_package(int ihandle)
108 {
109 	struct {
110 		cell_t name;
111 		cell_t nargs;
112 		cell_t nreturns;
113 		cell_t ihandle;
114 		cell_t phandle;
115 	} args;
116 
117 	args.name = ADR2CELL("instance-to-package");
118 	args.nargs = 1;
119 	args.nreturns = 1;
120 	args.ihandle = HDL2CELL(ihandle);
121 	if (openfirmware(&args) == -1)
122 		return -1;
123 	return args.phandle;
124 }
125 
126 int
127 OF_getprop(int handle, char *prop, void *buf, int buflen)
128 {
129 	struct {
130 		cell_t name;
131 		cell_t nargs;
132 		cell_t nreturns;
133 		cell_t phandle;
134 		cell_t prop;
135 		cell_t buf;
136 		cell_t buflen;
137 		cell_t size;
138 	} args;
139 
140 	args.name = ADR2CELL("getprop");
141 	args.nargs = 4;
142 	args.nreturns = 1;
143 	args.phandle = HDL2CELL(handle);
144 	args.prop = ADR2CELL(prop);
145 	args.buf = ADR2CELL(buf);
146 	args.buflen = buflen;
147 	if (openfirmware(&args) == -1)
148 		return -1;
149 	return args.size;
150 }
151 
152 int
153 OF_open(char *dname)
154 {
155 	struct {
156 		cell_t name;
157 		cell_t nargs;
158 		cell_t nreturns;
159 		cell_t dname;
160 		cell_t handle;
161 	} args;
162 
163 	args.name = ADR2CELL("open");
164 	args.nargs = 1;
165 	args.nreturns = 1;
166 	args.dname = ADR2CELL(dname);
167 	if (openfirmware(&args) == -1 ||
168 	    args.handle == 0)
169 		return -1;
170 	return args.handle;
171 }
172 
173 void
174 OF_close(int handle)
175 {
176 	struct {
177 		cell_t name;
178 		cell_t nargs;
179 		cell_t nreturns;
180 		cell_t handle;
181 	} args;
182 
183 	args.name = ADR2CELL("close");
184 	args.nargs = 1;
185 	args.nreturns = 0;
186 	args.handle = HDL2CELL(handle);
187 	openfirmware(&args);
188 }
189 
190 int
191 OF_write(int handle, void *addr, int len)
192 {
193 	struct {
194 		cell_t name;
195 		cell_t nargs;
196 		cell_t nreturns;
197 		cell_t ihandle;
198 		cell_t addr;
199 		cell_t len;
200 		cell_t actual;
201 	} args;
202 
203 	args.name = ADR2CELL("write");
204 	args.nargs = 3;
205 	args.nreturns = 1;
206 	args.ihandle = HDL2CELL(handle);
207 	args.addr = ADR2CELL(addr);
208 	args.len = len;
209 	if (openfirmware(&args) == -1)
210 		return -1;
211 	return args.actual;
212 }
213 
214 int
215 OF_read(int handle, void *addr, int len)
216 {
217 	struct {
218 		cell_t name;
219 		cell_t nargs;
220 		cell_t nreturns;
221 		cell_t ihandle;
222 		cell_t addr;
223 		cell_t len;
224 		cell_t actual;
225 	} args;
226 
227 	args.name = ADR2CELL("read");
228 	args.nargs = 3;
229 	args.nreturns = 1;
230 	args.ihandle = HDL2CELL(handle);
231 	args.addr = ADR2CELL(addr);
232 	args.len = len;
233 	if (openfirmware(&args) == -1) {
234 		return -1;
235 	}
236 	return args.actual;
237 }
238 
239 int
240 OF_seek(int handle, u_quad_t pos)
241 {
242 	struct {
243 		cell_t name;
244 		cell_t nargs;
245 		cell_t nreturns;
246 		cell_t handle;
247 		cell_t poshi;
248 		cell_t poslo;
249 		cell_t status;
250 	} args;
251 
252 	args.name = ADR2CELL("seek");
253 	args.nargs = 3;
254 	args.nreturns = 1;
255 	args.handle = HDL2CELL(handle);
256 	args.poshi = HDQ2CELL_HI(pos);
257 	args.poslo = HDQ2CELL_LO(pos);
258 	if (openfirmware(&args) == -1) {
259 		return -1;
260 	}
261 	return args.status;
262 }
263 
264 void
265 OF_release(void *virt, u_int size)
266 {
267 	struct {
268 		cell_t name;
269 		cell_t nargs;
270 		cell_t nreturns;
271 		cell_t virt;
272 		cell_t size;
273 	} args;
274 
275 	args.name = ADR2CELL("release");
276 	args.nargs = 2;
277 	args.nreturns = 0;
278 	args.virt = ADR2CELL(virt);
279 	args.size = size;
280 	openfirmware(&args);
281 }
282 
283 int
284 OF_milliseconds(void)
285 {
286 	struct {
287 		cell_t name;
288 		cell_t nargs;
289 		cell_t nreturns;
290 		cell_t ms;
291 	} args;
292 
293 	args.name = ADR2CELL("milliseconds");
294 	args.nargs = 0;
295 	args.nreturns = 1;
296 	openfirmware(&args);
297 	return args.ms;
298 }
299 
300 void
301 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
302 {
303 	extern int64_t romp;
304 
305 	entry(0, arg, len, (unsigned long)romp, (unsigned long)romp);
306 	panic("OF_chain: kernel returned!");
307 	__asm("ta 2" : :);
308 }
309 
310 static u_int stdin;
311 static u_int stdout;
312 static u_int mmuh = -1;
313 static u_int memh = -1;
314 
315 void
316 setup(void)
317 {
318 	u_int chosen;
319 
320 	if ((chosen = OF_finddevice("/chosen")) == -1)
321 		_rtt();
322 	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) != sizeof(stdin)
323 	    || OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) != sizeof(stdout)
324 	    || OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) != sizeof(mmuh)
325 	    || OF_getprop(chosen, "memory", &memh, sizeof(memh)) != sizeof(memh))
326 		_rtt();
327 }
328 
329 /*
330  * The following need either the handle to memory or the handle to the MMU.
331  */
332 
333 /*
334  * Grab some address space from the prom
335  *
336  * Only works while the prom is actively mapping us.
337  */
338 static vaddr_t
339 OF_claim_virt(vaddr_t vaddr, int len)
340 {
341 	struct {
342 		cell_t name;
343 		cell_t nargs;
344 		cell_t nreturns;
345 		cell_t method;
346 		cell_t ihandle;
347 		cell_t align;
348 		cell_t len;
349 		cell_t vaddr;
350 		cell_t status;
351 		cell_t retaddr;
352 	} args;
353 
354 	args.name = ADR2CELL("call-method");
355 	args.nargs = 5;
356 	args.nreturns = 2;
357 	args.method = ADR2CELL("claim");
358 	args.ihandle = HDL2CELL(mmuh);
359 	args.align = 0;
360 	args.len = len;
361 	args.vaddr = ADR2CELL(vaddr);
362 	if (openfirmware(&args) != 0)
363 		return -1LL;
364 	return (vaddr_t)args.retaddr;
365 }
366 
367 /*
368  * Request some address space from the prom
369  *
370  * Only works while the prom is actively mapping us.
371  */
372 static vaddr_t
373 OF_alloc_virt(int len, int align)
374 {
375 	int retaddr=-1;
376 	struct {
377 		cell_t name;
378 		cell_t nargs;
379 		cell_t nreturns;
380 		cell_t method;
381 		cell_t ihandle;
382 		cell_t align;
383 		cell_t len;
384 		cell_t status;
385 		cell_t retaddr;
386 	} args;
387 
388 	args.name = ADR2CELL("call-method");
389 	args.nargs = 4;
390 	args.nreturns = 2;
391 	args.method = ADR2CELL("claim");
392 	args.ihandle = HDL2CELL(mmuh);
393 	args.align = align;
394 	args.len = len;
395 	args.retaddr = ADR2CELL(&retaddr);
396 	if (openfirmware(&args) != 0)
397 		return -1LL;
398 	return (vaddr_t)args.retaddr;
399 }
400 
401 /*
402  * Release some address space to the prom
403  *
404  * Only works while the prom is actively mapping us.
405  */
406 static int
407 OF_free_virt(vaddr_t vaddr, int len)
408 {
409 	struct {
410 		cell_t name;
411 		cell_t nargs;
412 		cell_t nreturns;
413 		cell_t method;
414 		cell_t ihandle;
415 		cell_t len;
416 		cell_t vaddr;
417 	} args;
418 
419 	args.name = ADR2CELL("call-method");
420 	args.nargs = 4;
421 	args.nreturns = 0;
422 	args.method = ADR2CELL("release");
423 	args.ihandle = HDL2CELL(mmuh);
424 	args.vaddr = ADR2CELL(vaddr);
425 	args.len = len;
426 	return openfirmware(&args);
427 }
428 
429 
430 /*
431  * Have prom map in some memory
432  *
433  * Only works while the prom is actively mapping us.
434  */
435 static vaddr_t
436 OF_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode)
437 {
438 	struct {
439 		cell_t name;
440 		cell_t nargs;
441 		cell_t nreturns;
442 		cell_t method;
443 		cell_t ihandle;
444 		cell_t mode;
445 		cell_t size;
446 		cell_t vaddr;
447 		cell_t paddr_hi;
448 		cell_t paddr_lo;
449 		cell_t status;
450 		cell_t retaddr;
451 	} args;
452 
453 	args.name = ADR2CELL("call-method");
454 	args.nargs = 7;
455 	args.nreturns = 1;
456 	args.method = ADR2CELL("map");
457 	args.ihandle = HDL2CELL(mmuh);
458 	args.mode = mode;
459 	args.size = size;
460 	args.vaddr = ADR2CELL(vaddr);
461 	args.paddr_hi = HDQ2CELL_HI(paddr);
462 	args.paddr_lo = HDQ2CELL_LO(paddr);
463 
464 	if (openfirmware(&args) == -1)
465 		return -1;
466 	if (args.status)
467 		return -1;
468 	return (vaddr_t)args.retaddr;
469 }
470 
471 
472 /*
473  * Request some RAM from the prom
474  *
475  * Only works while the prom is actively mapping us.
476  */
477 static paddr_t
478 OF_alloc_phys(int len, int align)
479 {
480 	struct {
481 		cell_t name;
482 		cell_t nargs;
483 		cell_t nreturns;
484 		cell_t method;
485 		cell_t ihandle;
486 		cell_t align;
487 		cell_t len;
488 		cell_t status;
489 		cell_t phys_hi;
490 		cell_t phys_lo;
491 	} args;
492 
493 	args.name = ADR2CELL("call-method");
494 	args.nargs = 4;
495 	args.nreturns = 3;
496 	args.method = ADR2CELL("claim");
497 	args.ihandle = HDL2CELL(memh);
498 	args.align = align;
499 	args.len = len;
500 	if (openfirmware(&args) != 0)
501 		return -1LL;
502 	return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
503 }
504 
505 
506 /*
507  * Free some RAM to prom
508  *
509  * Only works while the prom is actively mapping us.
510  */
511 static int
512 OF_free_phys(paddr_t phys, int len)
513 {
514 	struct {
515 		cell_t name;
516 		cell_t nargs;
517 		cell_t nreturns;
518 		cell_t method;
519 		cell_t ihandle;
520 		cell_t len;
521 		cell_t phys_hi;
522 		cell_t phys_lo;
523 	} args;
524 
525 	args.name = ADR2CELL("call-method");
526 	args.nargs = 5;
527 	args.nreturns = 0;
528 	args.method = ADR2CELL("release");
529 	args.ihandle = HDL2CELL(memh);
530 	args.len = len;
531 	args.phys_hi = HDQ2CELL_HI(phys);
532 	args.phys_lo = HDQ2CELL_LO(phys);
533 	return openfirmware(&args);
534 }
535 
536 
537 /*
538  * Claim virtual memory -- does not map it in.
539  */
540 
541 void *
542 OF_claim(void *virt, u_int size, u_int align)
543 {
544 	/*
545 	 * Sun Ultra machines run the firmware with VM enabled,
546 	 * so you need to handle allocating and mapping both
547 	 * virtual and physical memory.  Ugh.
548 	 */
549 	paddr_t paddr;
550 	void * newvirt = NULL;
551 
552 	if (virt == NULL) {
553 		virt = (void *)OF_alloc_virt(size, align);
554 		if (virt == (void *)-1LL) {
555 			printf("OF_alloc_virt(%d,%d) failed w/%x\n",
556 			       size, align, virt);
557 			return virt;
558 		}
559 	} else {
560 		newvirt = (void *)OF_claim_virt((vaddr_t)virt, size);
561 		if (newvirt == (void *)-1LL) {
562 			printf("OF_claim_virt(%x,%d) failed w/%x\n",
563 			       virt, size, newvirt);
564 			return newvirt;
565 		}
566 		virt = newvirt;
567 	}
568 	if ((paddr = OF_alloc_phys(size, align)) == (paddr_t)-1LL) {
569 		printf("OF_alloc_phys(%d,%d) failed\n", size, align);
570 		OF_free_virt((vaddr_t)virt, size);
571 		return (void *)-1LL;
572 	}
573 	if (OF_map_phys(paddr, size, (vaddr_t)virt, -1) == -1) {
574 		printf("OF_map_phys(%x,%d,%x,%d) failed\n",
575 		       paddr, size, virt, -1);
576 		OF_free_phys((paddr_t)paddr, size);
577 		OF_free_virt((vaddr_t)virt, size);
578 		return (void *)-1LL;
579 	}
580 	return virt;
581 }
582 
583 int
584 OF_peer(int phandle)
585 {
586 	struct {
587 		cell_t name;
588 		cell_t nargs;
589 		cell_t nreturns;
590 		cell_t phandle;
591 		cell_t sibling;
592 	} args;
593 
594 	args.name = ADR2CELL("peer");
595 	args.nargs = 1;
596 	args.nreturns = 1;
597 	args.phandle = HDL2CELL(phandle);
598 	if (openfirmware(&args) == -1)
599 		return 0;
600 	return args.sibling;
601 }
602 
603 int
604 OF_child(int phandle)
605 {
606 	struct {
607 		cell_t name;
608 		cell_t nargs;
609 		cell_t nreturns;
610 		cell_t phandle;
611 		cell_t child;
612 	} args;
613 
614 	args.name = ADR2CELL("child");
615 	args.nargs = 1;
616 	args.nreturns = 1;
617 	args.phandle = HDL2CELL(phandle);
618 	if (openfirmware(&args) == -1)
619 		return 0;
620 	return args.child;
621 }
622 
623 int
624 OF_package_to_path(int phandle, char *buf, int buflen)
625 {
626 	struct {
627 		cell_t name;
628 		cell_t nargs;
629 		cell_t nreturns;
630 		cell_t phandle;
631 		cell_t buf;
632 		cell_t buflen;
633 		cell_t length;
634 	} args;
635 
636 	if (buflen > PAGE_SIZE)
637 		return -1;
638 	args.name = ADR2CELL("package-to-path");
639 	args.nargs = 3;
640 	args.nreturns = 1;
641 	args.phandle = HDL2CELL(phandle);
642 	args.buf = ADR2CELL(buf);
643 	args.buflen = buflen;
644 	if (openfirmware(&args) < 0)
645 		return -1;
646 	return args.length;
647 }
648 
649 void
650 putchar(int c)
651 {
652 	char ch = c;
653 
654 	if (c == '\n')
655 		putchar('\r');
656 	OF_write(stdout, &ch, 1);
657 }
658 
659 int
660 getchar(void)
661 {
662 	unsigned char ch = '\0';
663 	int l;
664 
665 	while ((l = OF_read(stdin, &ch, 1)) != 1)
666 		if (l != -2 && l != 0)
667 			return -1;
668 	return ch;
669 }
670