2 Routines for talking to the Open Firmware PROM on
3 Power Macintosh computers.
5 Copyright (C) 1999 Benjamin Herrenschmidt
6 Copyright (C) 1999 Marius Vollmer
7 Copyright (C) 1996 Paul Mackerras.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "asm/processor.h"
33 #define READ_BLOCKS_USE_READ 1
37 ihandle prom_stdin, prom_stdout;
39 //extern int vsprintf(char *buf, const char *fmt, va_list args);
41 static ihandle prom_mem, prom_mmu;
42 static ihandle prom_chosen, prom_options;
52 call_prom (const char *service, int nargs, int nret, ...)
56 struct prom_args prom_args;
58 prom_args.service = service;
59 prom_args.nargs = nargs;
60 prom_args.nret = nret;
61 va_start (list, nret);
62 for (i = 0; i < nargs; ++i)
63 prom_args.args[i] = va_arg(list, void *);
65 for (i = 0; i < nret; ++i)
66 prom_args.args[i + nargs] = 0;
69 return prom_args.args[nargs];
75 call_prom_return (const char *service, int nargs, int nret, ...)
80 struct prom_args prom_args;
82 prom_args.service = service;
83 prom_args.nargs = nargs;
84 prom_args.nret = nret;
85 va_start (list, nret);
86 for (i = 0; i < nargs; ++i)
87 prom_args.args[i] = va_arg(list, void *);
88 for (i = 0; i < nret; ++i)
89 prom_args.args[i + nargs] = 0;
90 if (prom (&prom_args) != 0)
91 return PROM_INVALID_HANDLE;
93 result = prom_args.args[nargs];
94 for (i=1; i<nret; i++) {
95 void** rp = va_arg(list, void**);
96 *rp = prom_args.args[i+nargs];
105 call_method_1 (char *method, prom_handle h, int nargs, ...)
109 struct prom_args prom_args;
111 prom_args.service = "call-method";
112 prom_args.nargs = nargs+2;
114 prom_args.args[0] = method;
115 prom_args.args[1] = h;
116 va_start (list, nargs);
117 for (i = 0; i < nargs; ++i)
118 prom_args.args[2+i] = va_arg(list, void *);
120 prom_args.args[2+nargs] = 0;
121 prom_args.args[2+nargs+1] = 0;
125 if (prom_args.args[2+nargs] != 0)
127 prom_printf ("method '%s' failed %d\n", method, prom_args.args[2+nargs]);
130 return prom_args.args[2+nargs+1];
135 prom_finddevice (char *name)
137 return call_prom ("finddevice", 1, 1, name);
141 prom_findpackage(char *path)
143 return call_prom ("find-package", 1, 1, path);
147 prom_getprop (prom_handle pack, char *name, void *mem, int len)
149 return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
153 prom_get_chosen (char *name, void *mem, int len)
155 return prom_getprop (prom_chosen, name, mem, len);
159 prom_get_options (char *name, void *mem, int len)
161 if (prom_options == (void *)-1)
163 return prom_getprop (prom_options, name, mem, len);
167 prom_init (prom_entry pp)
171 prom_chosen = prom_finddevice ("/chosen");
172 if (prom_chosen == (void *)-1)
174 prom_options = prom_finddevice ("/options");
175 if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0)
177 if (prom_get_chosen ("stdin", &prom_stdin, sizeof(prom_stdin)) <= 0)
178 prom_abort ("\nCan't open stdin");
179 if (prom_get_chosen ("memory", &prom_mem, sizeof(prom_mem)) <= 0)
180 prom_abort ("\nCan't get mem handle");
181 if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0)
182 prom_abort ("\nCan't get mmu handle");
184 // move cursor to fresh line
187 /* Add a few OF methods (thanks Darwin) */
189 prom_printf ("Adding OF methods...\n");
193 /* All values in this forth code are in hex */
195 /* Those are a few utilities ripped from Apple */
196 ": D2NIP decode-int nip nip ;\r" // A useful function to save space
197 ": GPP$ get-package-property 0= ;\r" // Another useful function to save space
198 ": ^on0 0= if -1 throw then ;\r" // Bail if result zero
199 ": $CM $call-method ;\r"
202 /* Some forth words used by the release method */
204 " \" /chosen\" find-package if "
205 "dup \" memory\" rot GPP$ if "
206 "D2NIP swap " // ( MEMORY-ihandle "/chosen"-phandle )
207 "\" mmu\" rot GPP$ if "
208 "D2NIP " // ( MEMORY-ihandle MMU-ihandle )
210 "0 " // ( MEMORY-ihandle 0 )
228 prom_printf ("OF interface initialized.\n");
233 prom_open (char *spec)
235 return call_prom ("open", 1, 1, spec, strlen(spec));
239 prom_close (prom_handle file)
241 call_prom ("close", 1, 0, file);
245 prom_read (prom_handle file, void *buf, int n)
253 result = (int)call_prom ("read", 3, 1, file, buf, n);
256 call_prom("interpret", 1, 1, " 10 ms");
263 prom_write (prom_handle file, void *buf, int n)
265 return (int)call_prom ("write", 3, 1, file, buf, n);
269 prom_seek (prom_handle file, int pos)
271 int status = (int)call_prom ("seek", 3, 1, file, 0, pos);
272 return status == 0 || status == 1;
276 prom_lseek (prom_handle file, unsigned long long pos)
278 int status = (int)call_prom ("seek", 3, 1, file,
279 (unsigned int)(pos >> 32), (unsigned int)(pos & 0xffffffffUL));
280 return status == 0 || status == 1;
284 prom_loadmethod (prom_handle device, void* addr)
286 return (int)call_method_1 ("load", device, 1, addr);
290 prom_getblksize (prom_handle file)
292 return (int)call_method_1 ("block-size", file, 0);
296 prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer)
298 #if READ_BLOCKS_USE_READ
300 unsigned int blksize;
302 blksize = prom_getblksize(dev);
305 status = prom_seek(dev, blockNum * blksize);
308 prom_printf("Can't seek to 0x%x\n", blockNum * blksize);
311 status = prom_read(dev, buffer, blockCount * blksize);
312 // prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n",
313 // blockNum, blockCount, status);
315 return status == (blockCount * blksize);
323 result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount);
326 call_prom("interpret", 1, 1, " 10 ms");
339 while ((a = (int)call_prom ("read", 3, 1, prom_stdin, c, 4)) == 0)
342 prom_abort ("EOF on console\n");
343 if (a == 3 && c[0] == '\e' && c[1] == '[')
353 return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1;
357 prom_putchar (char c)
360 call_prom ("write", 3, 1, prom_stdout, "\r\n", 2);
362 call_prom ("write", 3, 1, prom_stdout, &c, 1);
366 prom_puts (prom_handle file, char *s)
370 for (p = s; *p != 0; p = q)
372 for (q = p; *q != 0 && *q != '\n'; ++q)
375 call_prom ("write", 3, 1, file, p, q - p);
379 call_prom ("write", 3, 1, file, "\r\n", 2);
385 prom_vfprintf (prom_handle file, char *fmt, va_list ap)
387 static char printf_buf[1024];
388 vsprintf (printf_buf, fmt, ap);
389 prom_puts (file, printf_buf);
393 prom_vprintf (char *fmt, va_list ap)
395 static char printf_buf[1024];
396 vsprintf (printf_buf, fmt, ap);
397 prom_puts (prom_stdout, printf_buf);
401 prom_fprintf (prom_handle file, char *fmt, ...)
405 prom_vfprintf (file, fmt, ap);
410 prom_printf (char *fmt, ...)
414 prom_vfprintf (prom_stdout, fmt, ap);
419 prom_readline (char *prompt, char *buf, int len)
425 prom_puts (prom_stdout, prompt);
427 while (i < len-1 && (c = prom_getchar ()) != '\r')
435 prom_puts (prom_stdout, "\b \b");
441 else if (isprint (c))
453 #ifdef CONFIG_SET_COLORMAP
454 int prom_set_color(prom_handle device, int color, int r, int g, int b)
456 return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r );
458 #endif /* CONFIG_SET_COLORMAP */
463 call_prom ("exit", 0, 0);
467 prom_abort (char *fmt, ...)
471 prom_vfprintf (prom_stdout, fmt, ap);
477 prom_claim (void *virt, unsigned int size, unsigned int align)
479 return call_prom ("claim", 3, 1, virt, size, align);
483 prom_release(void *virt, unsigned int size)
485 // call_prom ("release", 2, 1, virt, size);
486 /* release in not enough, it needs also an unmap call. This bit of forth
487 * code inspired from Darwin's bootloader but could be replaced by direct
488 * calls to the MMU package if needed
490 call_prom ("interpret", 3, 1,
492 ".\" ReleaseMem:\" 2dup . . cr "
494 "over \" translate\" ^mmu " // Find out physical base
495 "^on0 " // Bail if translation failed
496 "drop " // Leaving phys on top of stack
497 "2dup \" unmap\" ^mmu " // Unmap the space first
498 "2dup \" release\" ^mmu " // Then free the virtual pages
499 "\" release\" ^mem " // Then free the physical pages
505 prom_map (void *phys, void *virt, int size)
507 unsigned long msr = mfmsr();
509 /* Only create a mapping if we're running with relocation enabled. */
510 if ( (msr & MSR_IR) && (msr & MSR_DR) )
511 call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
515 prom_unmap (void *phys, void *virt, int size)
517 unsigned long msr = mfmsr();
519 /* Only unmap if we're running with relocation enabled. */
520 if ( (msr & MSR_IR) && (msr & MSR_DR) )
521 call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
527 static char args[256];
530 l = prom_get_chosen ("bootargs", args, 255);
536 prom_setargs (char *args)
538 int l = strlen (args)+1;
539 if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l)
540 prom_printf ("can't set args\n");
543 int prom_interpret (char *forth)
545 return (int)call_prom("interpret", 1, 1, forth);
551 return (int) call_prom("milliseconds", 0, 1);
557 call_prom("enter", 0, 0);