2 * prom.c - Routines for talking to the Open Firmware PROM
4 * Copyright (C) 2001, 2002 Ethan Benson
6 * Copyright (C) 1999 Benjamin Herrenschmidt
8 * Copyright (C) 1999 Marius Vollmer
10 * Copyright (C) 1996 Paul Mackerras.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include "asm/processor.h"
38 #define READ_BLOCKS_USE_READ 1
40 static int yaboot_debug;
44 ihandle prom_stdin, prom_stdout;
46 static ihandle prom_mem, prom_mmu;
47 static ihandle prom_chosen, prom_options;
57 call_prom (const char *service, int nargs, int nret, ...)
61 struct prom_args prom_args;
63 prom_args.service = service;
64 prom_args.nargs = nargs;
65 prom_args.nret = nret;
66 va_start (list, nret);
67 for (i = 0; i < nargs; ++i)
68 prom_args.args[i] = va_arg(list, void *);
70 for (i = 0; i < nret; ++i)
71 prom_args.args[i + nargs] = 0;
74 return prom_args.args[nargs];
80 call_prom_return (const char *service, int nargs, int nret, ...)
85 struct prom_args prom_args;
87 prom_args.service = service;
88 prom_args.nargs = nargs;
89 prom_args.nret = nret;
90 va_start (list, nret);
91 for (i = 0; i < nargs; ++i)
92 prom_args.args[i] = va_arg(list, void *);
93 for (i = 0; i < nret; ++i)
94 prom_args.args[i + nargs] = 0;
95 if (prom (&prom_args) != 0)
96 return PROM_INVALID_HANDLE;
98 result = prom_args.args[nargs];
99 for (i=1; i<nret; i++) {
100 void** rp = va_arg(list, void**);
101 *rp = prom_args.args[i+nargs];
110 call_method_1 (char *method, prom_handle h, int nargs, ...)
114 struct prom_args prom_args;
116 prom_args.service = "call-method";
117 prom_args.nargs = nargs+2;
119 prom_args.args[0] = method;
120 prom_args.args[1] = h;
121 va_start (list, nargs);
122 for (i = 0; i < nargs; ++i)
123 prom_args.args[2+i] = va_arg(list, void *);
125 prom_args.args[2+nargs] = 0;
126 prom_args.args[2+nargs+1] = 0;
130 if (prom_args.args[2+nargs] != 0)
132 prom_printf ("method '%s' failed %p\n", method, prom_args.args[2+nargs]);
135 return prom_args.args[2+nargs+1];
140 prom_finddevice (char *name)
142 return call_prom ("finddevice", 1, 1, name);
146 prom_findpackage(char *path)
148 return call_prom ("find-package", 1, 1, path);
152 prom_getprop (prom_handle pack, char *name, void *mem, int len)
154 return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
158 prom_getproplen(prom_handle pack, const char *name)
160 return (int)call_prom("getproplen", 2, 1, pack, name);
164 prom_setprop (prom_handle pack, char *name, void *mem, int len)
166 return (int)call_prom ("setprop", 4, 1, pack, name, mem, len);
170 prom_get_chosen (char *name, void *mem, int len)
172 return prom_getprop (prom_chosen, name, mem, len);
176 prom_get_options (char *name, void *mem, int len)
178 if (prom_options == (void *)-1)
180 return prom_getprop (prom_options, name, mem, len);
184 prom_set_options (char *name, void *mem, int len)
186 if (prom_options == (void *)-1)
188 return prom_setprop (prom_options, name, mem, len);
192 prom_get_devtype (char *device)
198 if (strstr(device, TOK_ISCSI))
199 device = strcpy(tmp, "/vdevice/gscsi/disk");
201 /* Find OF device phandle */
202 dev = prom_finddevice(device);
203 if (dev == PROM_INVALID_HANDLE) {
204 return FILE_ERR_BADDEV;
207 /* Check the kind of device */
208 result = prom_getprop(dev, "device_type", tmp, 63);
210 prom_printf("can't get <device_type> for device: %s\n", device);
211 return FILE_ERR_BADDEV;
214 if (!strcmp(tmp, "block"))
215 return FILE_DEVICE_BLOCK;
216 else if (!strcmp(tmp, "network"))
217 return FILE_DEVICE_NET;
219 prom_printf("Unkown device type <%s>\n", tmp);
220 return FILE_ERR_BADDEV;
225 prom_init (prom_entry pp)
229 prom_chosen = prom_finddevice ("/chosen");
230 if (prom_chosen == (void *)-1)
232 prom_options = prom_finddevice ("/options");
233 if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0)
235 if (prom_get_chosen ("stdin", &prom_stdin, sizeof(prom_stdin)) <= 0)
236 prom_abort ("\nCan't open stdin");
237 if (prom_get_chosen ("memory", &prom_mem, sizeof(prom_mem)) <= 0)
238 prom_abort ("\nCan't get mem handle");
239 if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0)
240 prom_abort ("\nCan't get mmu handle");
243 prom_get_options("linux,yaboot-debug", &yaboot_debug, sizeof(yaboot_debug));
245 // move cursor to fresh line
248 /* Add a few OF methods (thanks Darwin) */
250 prom_printf ("Adding OF methods...\n");
254 /* All values in this forth code are in hex */
256 /* Those are a few utilities ripped from Apple */
257 ": D2NIP decode-int nip nip ;\r" // A useful function to save space
258 ": GPP$ get-package-property 0= ;\r" // Another useful function to save space
259 ": ^on0 0= if -1 throw then ;\r" // Bail if result zero
260 ": $CM $call-method ;\r"
263 /* Some forth words used by the release method */
265 " \" /chosen\" find-package if "
266 "dup \" memory\" rot GPP$ if "
267 "D2NIP swap " // ( MEMORY-ihandle "/chosen"-phandle )
268 "\" mmu\" rot GPP$ if "
269 "D2NIP " // ( MEMORY-ihandle MMU-ihandle )
271 "0 " // ( MEMORY-ihandle 0 )
288 DEBUG_F("OF interface initialized.\n");
292 prom_open (char *spec)
294 return call_prom ("open", 1, 1, spec, strlen(spec));
298 prom_close (prom_handle file)
300 call_prom ("close", 1, 0, file);
304 prom_read (prom_handle file, void *buf, int n)
312 result = (int)call_prom ("read", 3, 1, file, buf, n);
315 call_prom("interpret", 1, 1, " 10 ms");
322 prom_write (prom_handle file, void *buf, int n)
324 return (int)call_prom ("write", 3, 1, file, buf, n);
328 prom_seek (prom_handle file, int pos)
330 int status = (int)call_prom ("seek", 3, 1, file, 0, pos);
331 return status == 0 || status == 1;
335 prom_lseek (prom_handle file, unsigned long long pos)
337 int status = (int)call_prom ("seek", 3, 1, file,
338 (unsigned int)(pos >> 32), (unsigned int)(pos & 0xffffffffUL));
339 return status == 0 || status == 1;
343 prom_loadmethod (prom_handle device, void* addr)
345 return (int)call_method_1 ("load", device, 1, addr);
349 prom_getblksize (prom_handle file)
351 return (int)call_method_1 ("block-size", file, 0);
355 prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer)
357 #if READ_BLOCKS_USE_READ
359 unsigned int blksize;
361 blksize = prom_getblksize(dev);
364 status = prom_seek(dev, blockNum * blksize);
367 prom_printf("Can't seek to 0x%x\n", blockNum * blksize);
370 status = prom_read(dev, buffer, blockCount * blksize);
371 // prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n",
372 // blockNum, blockCount, status);
374 return status == (blockCount * blksize);
382 result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount);
385 call_prom("interpret", 1, 1, " 10 ms");
398 while ((a = (int)call_prom ("read", 3, 1, prom_stdin, &c, 1)) == 0)
401 prom_abort ("EOF on console\n");
410 return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1;
414 prom_putchar (char c)
417 call_prom ("write", 3, 1, prom_stdout, "\r\n", 2);
419 call_prom ("write", 3, 1, prom_stdout, &c, 1);
423 prom_puts (prom_handle file, char *s)
427 for (p = s; *p != 0; p = q)
429 for (q = p; *q != 0 && *q != '\n'; ++q)
432 call_prom ("write", 3, 1, file, p, q - p);
436 call_prom ("write", 3, 1, file, "\r\n", 2);
442 prom_vfprintf (prom_handle file, char *fmt, va_list ap)
444 static char printf_buf[2048];
445 vsprintf (printf_buf, fmt, ap);
446 prom_puts (file, printf_buf);
450 prom_vprintf (char *fmt, va_list ap)
452 static char printf_buf[2048];
453 vsprintf (printf_buf, fmt, ap);
454 prom_puts (prom_stdout, printf_buf);
458 prom_fprintf (prom_handle file, char *fmt, ...)
462 prom_vfprintf (file, fmt, ap);
467 prom_printf (char *fmt, ...)
471 prom_vfprintf (prom_stdout, fmt, ap);
476 prom_debug (char *fmt, ...)
484 prom_vfprintf (prom_stdout, fmt, ap);
489 prom_perror (int error, char *filename)
491 if (error == FILE_ERR_EOF)
492 prom_printf("%s: Unexpected End Of File\n", filename);
493 else if (error == FILE_ERR_NOTFOUND)
494 prom_printf("%s: No such file or directory\n", filename);
495 else if (error == FILE_CANT_SEEK)
496 prom_printf("%s: Seek error\n", filename);
497 else if (error == FILE_IOERR)
498 prom_printf("%s: Input/output error\n", filename);
499 else if (error == FILE_BAD_PATH)
500 prom_printf("%s: Path too long\n", filename);
501 else if (error == FILE_ERR_BAD_TYPE)
502 prom_printf("%s: Not a regular file\n", filename);
503 else if (error == FILE_ERR_NOTDIR)
504 prom_printf("%s: Not a directory\n", filename);
505 else if (error == FILE_ERR_BAD_FSYS)
506 prom_printf("%s: Unknown or corrupt filesystem\n", filename);
507 else if (error == FILE_ERR_SYMLINK_LOOP)
508 prom_printf("%s: Too many levels of symbolic links\n", filename);
509 else if (error == FILE_ERR_LENGTH)
510 prom_printf("%s: File too large\n", filename);
511 else if (error == FILE_ERR_FSBUSY)
512 prom_printf("%s: Filesystem busy\n", filename);
513 else if (error == FILE_ERR_BADDEV)
514 prom_printf("%s: Unable to open file, Invalid device\n", filename);
516 prom_printf("%s: Unknown error\n", filename);
520 prom_readline (char *prompt, char *buf, int len)
526 prom_puts (prom_stdout, prompt);
528 while (i < len-1 && (c = prom_getchar ()) != '\r')
534 prom_puts (prom_stdout, "\b \b");
540 else if (isprint (c))
552 #ifdef CONFIG_SET_COLORMAP
553 int prom_set_color(prom_handle device, int color, int r, int g, int b)
555 return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r );
557 #endif /* CONFIG_SET_COLORMAP */
562 call_prom ("exit", 0, 0);
566 prom_abort (char *fmt, ...)
570 prom_vfprintf (prom_stdout, fmt, ap);
576 prom_sleep (int seconds)
579 end = (prom_getms() + (seconds * 1000));
580 while (prom_getms() <= end);
583 /* if address given is claimed look for other addresses to get the needed
584 * space before giving up
587 prom_claim_chunk(void *virt, unsigned int size, unsigned int align)
590 for(addr=virt; addr <= (void*)PROM_CLAIM_MAX_ADDR;
591 addr+=(0x100000/sizeof(addr))) {
592 found = call_prom("claim", 3, 1, addr, size, 0);
593 if (found != (void *)-1) {
594 prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)addr, (int)found);
598 prom_printf("ERROR: claim of 0x%x in range 0x%x-0x%x failed\n", size, (int)virt, PROM_CLAIM_MAX_ADDR);
603 prom_claim (void *virt, unsigned int size, unsigned int align)
607 ret = call_prom ("claim", 3, 1, virt, size, align);
608 if (ret == (void *)-1)
609 prom_printf("ERROR: claim of 0x%x at 0x%x failed\n", size, (int)virt);
611 prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret);
617 prom_release(void *virt, unsigned int size)
621 ret = call_prom ("release", 2, 0, virt, size);
622 prom_debug("release of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret);
626 prom_map (void *phys, void *virt, int size)
628 unsigned long msr = mfmsr();
630 /* Only create a mapping if we're running with relocation enabled. */
631 if ( (msr & MSR_IR) && (msr & MSR_DR) )
632 call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
636 prom_unmap (void *phys, void *virt, int size)
638 unsigned long msr = mfmsr();
640 /* Only unmap if we're running with relocation enabled. */
641 if ( (msr & MSR_IR) && (msr & MSR_DR) )
642 call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
648 static char args[256];
651 l = prom_get_chosen ("bootargs", args, 255);
657 prom_setargs (char *args)
659 int l = strlen (args)+1;
660 if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l)
661 prom_printf ("can't set args\n");
664 int prom_interpret (char *forth)
666 return (int)call_prom("interpret", 1, 1, forth);
672 return (int) call_prom("milliseconds", 0, 1);
678 prom_print_available();
679 call_prom("enter", 0, 0);
684 * returns the packet with all needed info for netboot
686 struct bootp_packet * prom_get_netinfo (void)
688 void *bootp_response = NULL;
690 struct bootp_packet *packet;
691 /* struct bootp_packet contains a VLA, so sizeof won't work.
692 the VLA /must/ be the last field in the structure so use it's
693 offset as a good estimate of the packet size */
694 size_t packet_size = offsetof(struct bootp_packet, options);
695 int i = 0, size, offset = 0;
697 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
699 chosen = prom_finddevice("/chosen");
701 DEBUG_F("chosen=%d\n", chosen);
705 for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
706 propname = bootp_response_properties[i].name;
707 size = prom_getproplen(chosen, propname);
711 DEBUG_F("using /chosen/%s\n", propname);
712 offset = bootp_response_properties[i].offset;
719 if (packet_size > size - offset) {
720 prom_printf("Malformed %s property?\n", propname);
724 bootp_response = malloc(size);
728 if (prom_getprop(chosen, propname, bootp_response, size) < 0)
731 packet = bootp_response + offset;
737 * returns the mac addr of an net card
739 char * prom_get_mac (struct bootp_packet * packet)
747 /* 3 chars per byte in chaddr + \0 */
748 conf_path = malloc(packet->hlen * 3 + 1);
751 sprintf(conf_path, "%02x", packet->chaddr[0]);
753 for (i = 1; i < packet->hlen; i++) {
755 sprintf(tmp, "-%02x", packet->chaddr[i]);
756 strcat(conf_path, tmp);
764 * returns the ip addr of an net card
766 char * prom_get_ip (struct bootp_packet * packet)
773 /* 8 chars in yiaddr + \0 */
774 conf_path = malloc(9);
777 sprintf(conf_path, "%08x", packet->yiaddr);
782 /* We call this too early to use malloc, 128 cells should be large enough */
783 #define NR_AVAILABLE 128
785 void prom_print_available(void)
788 unsigned int addr_cells, size_cells;
790 unsigned int available[NR_AVAILABLE];
797 root = prom_finddevice("/");
802 prom_getprop(root, "#address-cells", &addr_cells, sizeof(addr_cells));
805 prom_getprop(root, "#size-cells", &size_cells, sizeof(size_cells));
807 mem = prom_finddevice("/memory@0");
808 if (mem == PROM_INVALID_HANDLE)
811 len = prom_getprop(mem, "available", available, sizeof(available));
816 prom_printf("\nAvailable memory ranges:\n");
820 unsigned int addr, size;
823 * Since we are in 32bit mode it should be safe to only print the
824 * bottom 32bits of each range.
826 p += (addr_cells - 1);
830 p += (size_cells - 1);
835 prom_printf("0x%08x-0x%08x (%3d MB)\n", addr, addr + size,
838 len -= (addr_cells + size_cells);
846 * c-file-style: "k&r"