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"
37 #define READ_BLOCKS_USE_READ 1
41 ihandle prom_stdin, prom_stdout;
43 //extern int vsprintf(char *buf, const char *fmt, va_list args);
45 static ihandle prom_mem, prom_mmu;
46 static ihandle prom_chosen, prom_options;
56 call_prom (const char *service, int nargs, int nret, ...)
60 struct prom_args prom_args;
62 prom_args.service = service;
63 prom_args.nargs = nargs;
64 prom_args.nret = nret;
65 va_start (list, nret);
66 for (i = 0; i < nargs; ++i)
67 prom_args.args[i] = va_arg(list, void *);
69 for (i = 0; i < nret; ++i)
70 prom_args.args[i + nargs] = 0;
73 return prom_args.args[nargs];
79 call_prom_return (const char *service, int nargs, int nret, ...)
84 struct prom_args prom_args;
86 prom_args.service = service;
87 prom_args.nargs = nargs;
88 prom_args.nret = nret;
89 va_start (list, nret);
90 for (i = 0; i < nargs; ++i)
91 prom_args.args[i] = va_arg(list, void *);
92 for (i = 0; i < nret; ++i)
93 prom_args.args[i + nargs] = 0;
94 if (prom (&prom_args) != 0)
95 return PROM_INVALID_HANDLE;
97 result = prom_args.args[nargs];
98 for (i=1; i<nret; i++) {
99 void** rp = va_arg(list, void**);
100 *rp = prom_args.args[i+nargs];
109 call_method_1 (char *method, prom_handle h, int nargs, ...)
113 struct prom_args prom_args;
115 prom_args.service = "call-method";
116 prom_args.nargs = nargs+2;
118 prom_args.args[0] = method;
119 prom_args.args[1] = h;
120 va_start (list, nargs);
121 for (i = 0; i < nargs; ++i)
122 prom_args.args[2+i] = va_arg(list, void *);
124 prom_args.args[2+nargs] = 0;
125 prom_args.args[2+nargs+1] = 0;
129 if (prom_args.args[2+nargs] != 0)
131 prom_printf ("method '%s' failed %p\n", method, prom_args.args[2+nargs]);
134 return prom_args.args[2+nargs+1];
139 prom_finddevice (char *name)
141 return call_prom ("finddevice", 1, 1, name);
145 prom_findpackage(char *path)
147 return call_prom ("find-package", 1, 1, path);
151 prom_getprop (prom_handle pack, char *name, void *mem, int len)
153 return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
157 prom_getproplen(prom_handle pack, const char *name)
159 return (int)call_prom("getproplen", 2, 1, pack, name);
163 prom_get_chosen (char *name, void *mem, int len)
165 return prom_getprop (prom_chosen, name, mem, len);
169 prom_get_options (char *name, void *mem, int len)
171 if (prom_options == (void *)-1)
173 return prom_getprop (prom_options, name, mem, len);
177 prom_get_devtype (char *device)
183 if (strstr(device, TOK_ISCSI))
184 device = strcpy(tmp, "/vdevice/gscsi/disk");
186 /* Find OF device phandle */
187 dev = prom_finddevice(device);
188 if (dev == PROM_INVALID_HANDLE) {
189 return FILE_ERR_BADDEV;
192 /* Check the kind of device */
193 result = prom_getprop(dev, "device_type", tmp, 63);
195 prom_printf("can't get <device_type> for device: %s\n", device);
196 return FILE_ERR_BADDEV;
199 if (!strcmp(tmp, "block"))
200 return FILE_DEVICE_BLOCK;
201 else if (!strcmp(tmp, "network"))
202 return FILE_DEVICE_NET;
204 prom_printf("Unkown device type <%s>\n", tmp);
205 return FILE_ERR_BADDEV;
210 prom_init (prom_entry pp)
214 prom_chosen = prom_finddevice ("/chosen");
215 if (prom_chosen == (void *)-1)
217 prom_options = prom_finddevice ("/options");
218 if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0)
220 if (prom_get_chosen ("stdin", &prom_stdin, sizeof(prom_stdin)) <= 0)
221 prom_abort ("\nCan't open stdin");
222 if (prom_get_chosen ("memory", &prom_mem, sizeof(prom_mem)) <= 0)
223 prom_abort ("\nCan't get mem handle");
224 if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0)
225 prom_abort ("\nCan't get mmu handle");
227 // move cursor to fresh line
230 /* Add a few OF methods (thanks Darwin) */
232 prom_printf ("Adding OF methods...\n");
236 /* All values in this forth code are in hex */
238 /* Those are a few utilities ripped from Apple */
239 ": D2NIP decode-int nip nip ;\r" // A useful function to save space
240 ": GPP$ get-package-property 0= ;\r" // Another useful function to save space
241 ": ^on0 0= if -1 throw then ;\r" // Bail if result zero
242 ": $CM $call-method ;\r"
245 /* Some forth words used by the release method */
247 " \" /chosen\" find-package if "
248 "dup \" memory\" rot GPP$ if "
249 "D2NIP swap " // ( MEMORY-ihandle "/chosen"-phandle )
250 "\" mmu\" rot GPP$ if "
251 "D2NIP " // ( MEMORY-ihandle MMU-ihandle )
253 "0 " // ( MEMORY-ihandle 0 )
270 DEBUG_F("OF interface initialized.\n");
274 prom_open (char *spec)
276 return call_prom ("open", 1, 1, spec, strlen(spec));
280 prom_close (prom_handle file)
282 call_prom ("close", 1, 0, file);
286 prom_read (prom_handle file, void *buf, int n)
294 result = (int)call_prom ("read", 3, 1, file, buf, n);
297 call_prom("interpret", 1, 1, " 10 ms");
304 prom_write (prom_handle file, void *buf, int n)
306 return (int)call_prom ("write", 3, 1, file, buf, n);
310 prom_seek (prom_handle file, int pos)
312 int status = (int)call_prom ("seek", 3, 1, file, 0, pos);
313 return status == 0 || status == 1;
317 prom_lseek (prom_handle file, unsigned long long pos)
319 int status = (int)call_prom ("seek", 3, 1, file,
320 (unsigned int)(pos >> 32), (unsigned int)(pos & 0xffffffffUL));
321 return status == 0 || status == 1;
325 prom_loadmethod (prom_handle device, void* addr)
327 return (int)call_method_1 ("load", device, 1, addr);
331 prom_getblksize (prom_handle file)
333 return (int)call_method_1 ("block-size", file, 0);
337 prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer)
339 #if READ_BLOCKS_USE_READ
341 unsigned int blksize;
343 blksize = prom_getblksize(dev);
346 status = prom_seek(dev, blockNum * blksize);
349 prom_printf("Can't seek to 0x%x\n", blockNum * blksize);
352 status = prom_read(dev, buffer, blockCount * blksize);
353 // prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n",
354 // blockNum, blockCount, status);
356 return status == (blockCount * blksize);
364 result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount);
367 call_prom("interpret", 1, 1, " 10 ms");
380 while ((a = (int)call_prom ("read", 3, 1, prom_stdin, c, 4)) == 0)
383 prom_abort ("EOF on console\n");
384 if (a == 3 && c[0] == '\e' && c[1] == '[')
394 return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1;
398 prom_putchar (char c)
401 call_prom ("write", 3, 1, prom_stdout, "\r\n", 2);
403 call_prom ("write", 3, 1, prom_stdout, &c, 1);
407 prom_puts (prom_handle file, char *s)
411 for (p = s; *p != 0; p = q)
413 for (q = p; *q != 0 && *q != '\n'; ++q)
416 call_prom ("write", 3, 1, file, p, q - p);
420 call_prom ("write", 3, 1, file, "\r\n", 2);
426 prom_vfprintf (prom_handle file, char *fmt, va_list ap)
428 static char printf_buf[2048];
429 vsprintf (printf_buf, fmt, ap);
430 prom_puts (file, printf_buf);
434 prom_vprintf (char *fmt, va_list ap)
436 static char printf_buf[2048];
437 vsprintf (printf_buf, fmt, ap);
438 prom_puts (prom_stdout, printf_buf);
442 prom_fprintf (prom_handle file, char *fmt, ...)
446 prom_vfprintf (file, fmt, ap);
451 prom_printf (char *fmt, ...)
455 prom_vfprintf (prom_stdout, fmt, ap);
460 prom_perror (int error, char *filename)
462 if (error == FILE_ERR_EOF)
463 prom_printf("%s: Unexpected End Of File\n", filename);
464 else if (error == FILE_ERR_NOTFOUND)
465 prom_printf("%s: No such file or directory\n", filename);
466 else if (error == FILE_CANT_SEEK)
467 prom_printf("%s: Seek error\n", filename);
468 else if (error == FILE_IOERR)
469 prom_printf("%s: Input/output error\n", filename);
470 else if (error == FILE_BAD_PATH)
471 prom_printf("%s: Path too long\n", filename);
472 else if (error == FILE_ERR_BAD_TYPE)
473 prom_printf("%s: Not a regular file\n", filename);
474 else if (error == FILE_ERR_NOTDIR)
475 prom_printf("%s: Not a directory\n", filename);
476 else if (error == FILE_ERR_BAD_FSYS)
477 prom_printf("%s: Unknown or corrupt filesystem\n", filename);
478 else if (error == FILE_ERR_SYMLINK_LOOP)
479 prom_printf("%s: Too many levels of symbolic links\n", filename);
480 else if (error == FILE_ERR_LENGTH)
481 prom_printf("%s: File too large\n", filename);
482 else if (error == FILE_ERR_FSBUSY)
483 prom_printf("%s: Filesystem busy\n", filename);
484 else if (error == FILE_ERR_BADDEV)
485 prom_printf("%s: Unable to open file, Invalid device\n", filename);
487 prom_printf("%s: Unknown error\n", filename);
491 prom_readline (char *prompt, char *buf, int len)
497 prom_puts (prom_stdout, prompt);
499 while (i < len-1 && (c = prom_getchar ()) != '\r')
507 prom_puts (prom_stdout, "\b \b");
513 else if (isprint (c))
525 #ifdef CONFIG_SET_COLORMAP
526 int prom_set_color(prom_handle device, int color, int r, int g, int b)
528 return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r );
530 #endif /* CONFIG_SET_COLORMAP */
535 call_prom ("exit", 0, 0);
539 prom_abort (char *fmt, ...)
543 prom_vfprintf (prom_stdout, fmt, ap);
549 prom_sleep (int seconds)
552 end = (prom_getms() + (seconds * 1000));
553 while (prom_getms() <= end);
557 prom_claim (void *virt, unsigned int size, unsigned int align)
559 return call_prom ("claim", 3, 1, virt, size, align);
563 prom_release(void *virt, unsigned int size)
565 call_prom ("release", 2, 0, virt, size);
566 #if 0 /* this is bullshit, newworld OF RELEASE method works fine. */
568 /* release in not enough, it needs also an unmap call. This bit of forth
569 * code inspired from Darwin's bootloader but could be replaced by direct
570 * calls to the MMU package if needed
572 call_prom ("interpret", 3, 1,
574 ".\" ReleaseMem:\" 2dup . . cr "
576 "over \" translate\" ^mmu " // Find out physical base
577 "^on0 " // Bail if translation failed
578 "drop " // Leaving phys on top of stack
579 "2dup \" unmap\" ^mmu " // Unmap the space first
580 "2dup \" release\" ^mmu " // Then free the virtual pages
581 "\" release\" ^mem " // Then free the physical pages
584 #endif /* bullshit */
588 prom_map (void *phys, void *virt, int size)
590 unsigned long msr = mfmsr();
592 /* Only create a mapping if we're running with relocation enabled. */
593 if ( (msr & MSR_IR) && (msr & MSR_DR) )
594 call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
598 prom_unmap (void *phys, void *virt, int size)
600 unsigned long msr = mfmsr();
602 /* Only unmap if we're running with relocation enabled. */
603 if ( (msr & MSR_IR) && (msr & MSR_DR) )
604 call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
610 static char args[256];
613 l = prom_get_chosen ("bootargs", args, 255);
619 prom_setargs (char *args)
621 int l = strlen (args)+1;
622 if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l)
623 prom_printf ("can't set args\n");
626 int prom_interpret (char *forth)
628 return (int)call_prom("interpret", 1, 1, forth);
634 return (int) call_prom("milliseconds", 0, 1);
640 call_prom("enter", 0, 0);
645 * c-file-style: "k&r"