]> git.ozlabs.org Git - yaboot.git/blob - second/prom.c
Allocate malloc region with prom_claim_chunk_top
[yaboot.git] / second / prom.c
1 /*
2  *  prom.c - Routines for talking to the Open Firmware PROM
3  *
4  *  Copyright (C) 2001, 2002 Ethan Benson
5  *
6  *  Copyright (C) 1999 Benjamin Herrenschmidt
7  *
8  *  Copyright (C) 1999 Marius Vollmer
9  *
10  *  Copyright (C) 1996 Paul Mackerras.
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #include "prom.h"
28 #include "stdarg.h"
29 #include "stddef.h"
30 #include "stdlib.h"
31 #include "types.h"
32 #include "ctype.h"
33 #include "asm/processor.h"
34 #include "errors.h"
35 #include "debug.h"
36 #include "string.h"
37
38 #define READ_BLOCKS_USE_READ    1
39
40 static int yaboot_debug;
41
42 prom_entry prom;
43
44 ihandle prom_stdin, prom_stdout;
45
46 static ihandle prom_mem, prom_mmu;
47 static ihandle prom_chosen, prom_options;
48
49 struct prom_args {
50      const char *service;
51      int nargs;
52      int nret;
53      void *args[10];
54 };
55
56 void *
57 call_prom (const char *service, int nargs, int nret, ...)
58 {
59      va_list list;
60      int i;
61      struct prom_args prom_args;
62
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 *);
69      va_end(list);
70      for (i = 0; i < nret; ++i)
71           prom_args.args[i + nargs] = 0;
72      prom (&prom_args);
73      if (nret > 0)
74           return prom_args.args[nargs];
75      else
76           return 0;
77 }
78
79 void *
80 call_prom_return (const char *service, int nargs, int nret, ...)
81 {
82      va_list list;
83      int i;
84      void* result;
85      struct prom_args prom_args;
86
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;
97      if (nret > 0) {
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];
102           }
103      } else
104           result = 0;
105      va_end(list);
106      return result;
107 }
108
109 static void *
110 call_method_1 (char *method, prom_handle h, int nargs, ...)
111 {
112      va_list list;
113      int i;
114      struct prom_args prom_args;
115
116      prom_args.service = "call-method";
117      prom_args.nargs = nargs+2;
118      prom_args.nret = 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 *);
124      va_end(list);
125      prom_args.args[2+nargs] = 0;
126      prom_args.args[2+nargs+1] = 0;
127
128      prom (&prom_args);
129
130      if (prom_args.args[2+nargs] != 0)
131      {
132           prom_printf ("method '%s' failed %p\n", method, prom_args.args[2+nargs]);
133           return 0;
134      }
135      return prom_args.args[2+nargs+1];
136 }
137
138
139 prom_handle
140 prom_finddevice (char *name)
141 {
142      return call_prom ("finddevice", 1, 1, name);
143 }
144
145 prom_handle
146 prom_findpackage(char *path)
147 {
148      return call_prom ("find-package", 1, 1, path);
149 }
150
151 int
152 prom_getprop (prom_handle pack, char *name, void *mem, int len)
153 {
154      return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
155 }
156
157 int
158 prom_getproplen(prom_handle pack, const char *name)
159 {
160      return (int)call_prom("getproplen", 2, 1, pack, name);
161 }
162
163 int
164 prom_setprop (prom_handle pack, char *name, void *mem, int len)
165 {
166      return (int)call_prom ("setprop", 4, 1, pack, name, mem, len);
167 }
168
169 int
170 prom_get_chosen (char *name, void *mem, int len)
171 {
172      return prom_getprop (prom_chosen, name, mem, len);
173 }
174
175 int
176 prom_get_options (char *name, void *mem, int len)
177 {
178      if (prom_options == (void *)-1)
179           return -1;
180      return prom_getprop (prom_options, name, mem, len);
181 }
182
183 int
184 prom_set_options (char *name, void *mem, int len)
185 {
186      if (prom_options == (void *)-1)
187           return -1;
188      return prom_setprop (prom_options, name, mem, len);
189 }
190
191 int
192 prom_get_devtype (char *device)
193 {
194      phandle    dev;
195      int        result;
196      char       tmp[64];
197
198      if (strstr(device, TOK_ISCSI))
199           device = strcpy(tmp, "/vdevice/gscsi/disk");
200
201      /* Find OF device phandle */
202      dev = prom_finddevice(device);
203      if (dev == PROM_INVALID_HANDLE) {
204           return FILE_ERR_BADDEV;
205      }
206
207      /* Check the kind of device */
208      result = prom_getprop(dev, "device_type", tmp, 63);
209      if (result == -1) {
210           prom_printf("can't get <device_type> for device: %s\n", device);
211           return FILE_ERR_BADDEV;
212      }
213      tmp[result] = 0;
214      if (!strcmp(tmp, "block"))
215           return FILE_DEVICE_BLOCK;
216      else if (!strcmp(tmp, "network"))
217           return FILE_DEVICE_NET;
218      else {
219           prom_printf("Unkown device type <%s>\n", tmp);
220           return FILE_ERR_BADDEV;
221      }
222 }
223
224 void
225 prom_init (prom_entry pp)
226 {
227      prom = pp;
228
229      prom_chosen = prom_finddevice ("/chosen");
230      if (prom_chosen == (void *)-1)
231           prom_exit ();
232      prom_options = prom_finddevice ("/options");
233      if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0)
234           prom_exit();
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");
241
242      yaboot_debug = 0;
243      prom_get_options("linux,yaboot-debug", &yaboot_debug, sizeof(yaboot_debug));
244
245   // move cursor to fresh line
246      prom_printf ("\n");
247
248      /* Add a few OF methods (thanks Darwin) */
249 #if DEBUG
250      prom_printf ("Adding OF methods...\n");
251 #endif
252
253      prom_interpret (
254           /* All values in this forth code are in hex */
255           "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"
261           );
262
263      /* Some forth words used by the release method */
264      prom_interpret (
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 )
270                          "else "
271                                  "0 "                                    // ( MEMORY-ihandle 0 )
272                          "then "
273                  "else "
274                          "0 0 "                                          // ( 0 0 )
275                  "then "
276           "else "
277                  "0 0 "                                                  // ( 0 0 )
278           "then\r"
279           "value mmu# "
280           "value mem# "
281           );
282
283      prom_interpret (
284           ": ^mem mem# $CM ; "
285           ": ^mmu mmu# $CM ; "
286           );
287
288      DEBUG_F("OF interface initialized.\n");
289 }
290
291 prom_handle
292 prom_open (char *spec)
293 {
294      return call_prom ("open", 1, 1, spec, strlen(spec));
295 }
296
297 void
298 prom_close (prom_handle file)
299 {
300      call_prom ("close", 1, 0, file);
301 }
302
303 int
304 prom_read (prom_handle file, void *buf, int n)
305 {
306      int result = 0;
307      int retries = 10;
308
309      if (n == 0)
310           return 0;
311      while(--retries) {
312           result = (int)call_prom ("read", 3, 1, file, buf, n);
313           if (result != 0)
314                break;
315           call_prom("interpret", 1, 1, " 10 ms");
316      }
317
318      return result;
319 }
320
321 int
322 prom_write (prom_handle file, void *buf, int n)
323 {
324      return (int)call_prom ("write", 3, 1, file, buf, n);
325 }
326
327 int
328 prom_seek (prom_handle file, int pos)
329 {
330      int status = (int)call_prom ("seek", 3, 1, file, 0, pos);
331      return status == 0 || status == 1;
332 }
333
334 int
335 prom_lseek (prom_handle file, unsigned long long pos)
336 {
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;
340 }
341
342 int
343 prom_loadmethod (prom_handle device, void* addr)
344 {
345      return (int)call_method_1 ("load", device, 1, addr);
346 }
347
348 int
349 prom_getblksize (prom_handle file)
350 {
351      return (int)call_method_1 ("block-size", file, 0);
352 }
353
354 int
355 prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer)
356 {
357 #if READ_BLOCKS_USE_READ
358      int status;
359      unsigned int blksize;
360
361      blksize = prom_getblksize(dev);
362      if (blksize <= 1)
363           blksize = 512;
364      status = prom_seek(dev, blockNum * blksize);
365      if (status != 1) {
366           return 0;
367           prom_printf("Can't seek to 0x%x\n", blockNum * blksize);
368      }
369
370      status = prom_read(dev, buffer, blockCount * blksize);
371 //  prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n",
372 //      blockNum, blockCount, status);
373
374      return status == (blockCount * blksize);
375 #else
376      int result;
377      int retries = 10;
378
379      if (blockCount == 0)
380           return blockCount;
381      while(--retries) {
382           result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount);
383           if (result != 0)
384                break;
385           call_prom("interpret", 1, 1, " 10 ms");
386      }
387
388      return result;
389 #endif
390 }
391
392 int
393 prom_getchar ()
394 {
395      char c;
396      int a;
397
398      while ((a = (int)call_prom ("read", 3, 1, prom_stdin, &c, 1)) == 0)
399           ;
400      if (a == -1)
401           prom_abort ("EOF on console\n");
402      return c;
403 }
404
405 int
406 prom_nbgetchar()
407 {
408      char ch;
409
410      return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1;
411 }
412
413 void
414 prom_putchar (char c)
415 {
416      if (c == '\n')
417           call_prom ("write", 3, 1, prom_stdout, "\r\n", 2);
418      else
419           call_prom ("write", 3, 1, prom_stdout, &c, 1);
420 }
421
422 void
423 prom_puts (prom_handle file, char *s)
424 {
425      const char *p, *q;
426
427      for (p = s; *p != 0; p = q)
428      {
429           for (q = p; *q != 0 && *q != '\n'; ++q)
430                ;
431           if (q > p)
432                call_prom ("write", 3, 1, file, p, q - p);
433           if (*q != 0)
434           {
435                ++q;
436                call_prom ("write", 3, 1, file, "\r\n", 2);
437           }
438      }
439 }
440
441 void
442 prom_vfprintf (prom_handle file, char *fmt, va_list ap)
443 {
444      static char printf_buf[2048];
445      vsprintf (printf_buf, fmt, ap);
446      prom_puts (file, printf_buf);
447 }
448
449 void
450 prom_vprintf (char *fmt, va_list ap)
451 {
452      static char printf_buf[2048];
453      vsprintf (printf_buf, fmt, ap);
454      prom_puts (prom_stdout, printf_buf);
455 }
456
457 void
458 prom_fprintf (prom_handle file, char *fmt, ...)
459 {
460      va_list ap;
461      va_start (ap, fmt);
462      prom_vfprintf (file, fmt, ap);
463      va_end (ap);
464 }
465
466 void
467 prom_printf (char *fmt, ...)
468 {
469      va_list ap;
470      va_start (ap, fmt);
471      prom_vfprintf (prom_stdout, fmt, ap);
472      va_end (ap);
473 }
474
475 void
476 prom_debug (char *fmt, ...)
477 {
478      va_list ap;
479
480      if (!yaboot_debug)
481           return;
482
483      va_start (ap, fmt);
484      prom_vfprintf (prom_stdout, fmt, ap);
485      va_end (ap);
486 }
487
488 void
489 prom_perror (int error, char *filename)
490 {
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);
515      else
516           prom_printf("%s: Unknown error\n", filename);
517 }
518
519 void
520 prom_readline (char *prompt, char *buf, int len)
521 {
522      int i = 0;
523      int c;
524
525      if (prompt)
526           prom_puts (prom_stdout, prompt);
527
528      while (i < len-1 && (c = prom_getchar ()) != '\r')
529      {
530           if (c == 8)
531           {
532                if (i > 0)
533                {
534                     prom_puts (prom_stdout, "\b \b");
535                     i--;
536                }
537                else
538                     prom_putchar ('\a');
539           }
540           else if (isprint (c))
541           {
542                prom_putchar (c);
543                buf[i++] = c;
544           }
545           else
546                prom_putchar ('\a');
547      }
548      prom_putchar ('\n');
549      buf[i] = 0;
550 }
551
552 #ifdef CONFIG_SET_COLORMAP
553 int prom_set_color(prom_handle device, int color, int r, int g, int b)
554 {
555      return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r );
556 }
557 #endif /* CONFIG_SET_COLORMAP */
558
559 void
560 prom_exit ()
561 {
562      call_prom ("exit", 0, 0);
563 }
564
565 void
566 prom_abort (char *fmt, ...)
567 {
568      va_list ap;
569      va_start (ap, fmt);
570      prom_vfprintf (prom_stdout, fmt, ap);
571      va_end (ap);
572      prom_exit ();
573 }
574
575 void
576 prom_sleep (int seconds)
577 {
578      int end;
579      end = (prom_getms() + (seconds * 1000));
580      while (prom_getms() <= end);
581 }
582
583 /* if address given is claimed look for other addresses to get the needed
584  * space before giving up
585  */
586 void *
587 prom_claim_chunk(void *virt, unsigned int size, unsigned int align)
588 {
589      void *found, *addr;
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);
595                return(found);
596           }
597      }
598      prom_printf("ERROR: claim of 0x%x in range 0x%x-0x%x failed\n", size, (int)virt, PROM_CLAIM_MAX_ADDR);
599      return((void*)-1);
600 }
601
602 /* Start from top of memory and work down to get the needed space */
603 void *
604 prom_claim_chunk_top(unsigned int size, unsigned int align)
605 {
606      void *found, *addr;
607      for(addr=(void*)PROM_CLAIM_MAX_ADDR; addr >= (void *)size;
608          addr-=(0x100000/sizeof(addr))) {
609           found = call_prom("claim", 3, 1, addr, size, 0);
610           if (found != (void *)-1) {
611                prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)addr, (int)found);
612                return(found);
613           }
614      }
615      prom_printf("ERROR: claim of 0x%x in range 0x0-0x%x failed\n", size, PROM_CLAIM_MAX_ADDR);
616      return((void*)-1);
617 }
618
619 void *
620 prom_claim (void *virt, unsigned int size, unsigned int align)
621 {
622      void *ret;
623
624      ret = call_prom ("claim", 3, 1, virt, size, align);
625      if (ret == (void *)-1)
626           prom_printf("ERROR: claim of 0x%x at 0x%x failed\n", size, (int)virt);
627      else
628           prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret);
629
630      return ret;
631 }
632
633 void
634 prom_release(void *virt, unsigned int size)
635 {
636      void *ret;
637
638      ret = call_prom ("release", 2, 0, virt, size);
639      prom_debug("release of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret);
640 }
641
642 void
643 prom_map (void *phys, void *virt, int size)
644 {
645      unsigned long msr = mfmsr();
646
647      /* Only create a mapping if we're running with relocation enabled. */
648      if ( (msr & MSR_IR) && (msr & MSR_DR) )
649           call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
650 }
651
652 void
653 prom_unmap (void *phys, void *virt, int size)
654 {
655      unsigned long msr = mfmsr();
656
657      /* Only unmap if we're running with relocation enabled. */
658      if ( (msr & MSR_IR) && (msr & MSR_DR) )
659           call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
660 }
661
662 char *
663 prom_getargs ()
664 {
665      static char args[256];
666      int l;
667
668      l = prom_get_chosen ("bootargs", args, 255);
669      args[l] = '\0';
670      return args;
671 }
672
673 void
674 prom_setargs (char *args)
675 {
676      int l = strlen (args)+1;
677      if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l)
678           prom_printf ("can't set args\n");
679 }
680
681 int prom_interpret (char *forth)
682 {
683      return (int)call_prom("interpret", 1, 1, forth);
684 }
685
686 int
687 prom_getms(void)
688 {
689      return (int) call_prom("milliseconds", 0, 1);
690 }
691
692 void
693 prom_pause(void)
694 {
695      prom_print_available();
696      call_prom("enter", 0, 0);
697 }
698
699 /*
700  * prom_get_netinfo()
701  * returns the packet with all needed info for netboot
702  */
703 struct bootp_packet * prom_get_netinfo (void)
704 {
705      void *bootp_response = NULL;
706      char *propname;
707      struct bootp_packet *packet;
708      /* struct bootp_packet contains a VLA, so sizeof won't work.
709         the VLA /must/ be the last field in the structure so use it's
710         offset as a good estimate of the packet size */
711      size_t packet_size = offsetof(struct bootp_packet, options);
712      int i = 0, size, offset = 0;
713      prom_handle chosen;
714 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
715
716      chosen = prom_finddevice("/chosen");
717      if (chosen < 0) {
718           DEBUG_F("chosen=%d\n", chosen);
719       return 0;
720      }
721
722      for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
723          propname = bootp_response_properties[i].name;
724          size = prom_getproplen(chosen, propname);
725          if (size <= 0)
726              continue;
727
728          DEBUG_F("using /chosen/%s\n", propname);
729          offset = bootp_response_properties[i].offset;
730          break;
731      }
732
733      if (size <= 0)
734          return NULL;
735
736      if (packet_size > size - offset) {
737          prom_printf("Malformed %s property?\n", propname);
738          return NULL;
739      }
740
741      bootp_response = malloc(size);
742      if (!bootp_response)
743          return NULL;
744
745      if (prom_getprop(chosen, propname, bootp_response, size) < 0)
746          return NULL;
747
748      packet = bootp_response + offset;
749      return packet;
750 }
751
752 /*
753  * prom_get_mac()
754  * returns the mac addr of an net card
755  */
756 char * prom_get_mac (struct bootp_packet * packet)
757 {
758      char * conf_path;
759      int i;
760
761      if (!packet)
762         return NULL;
763
764      /* 3 chars per byte in chaddr + \0 */
765      conf_path = malloc(packet->hlen * 3 + 1);
766      if (!conf_path)
767          return NULL;
768      sprintf(conf_path, "%02x", packet->chaddr[0]);
769
770      for (i = 1; i < packet->hlen; i++) {
771       char tmp[4];
772       sprintf(tmp, "-%02x", packet->chaddr[i]);
773       strcat(conf_path, tmp);
774      }
775
776      return conf_path;
777 }
778
779 /*
780  * prom_get_ip()
781  * returns the ip addr of an net card
782  */
783 char * prom_get_ip (struct bootp_packet * packet)
784 {
785      char * conf_path;
786
787      if (!packet)
788         return NULL;
789
790      /* 8 chars in yiaddr + \0 */
791      conf_path = malloc(9);
792      if (!conf_path)
793          return NULL;
794      sprintf(conf_path, "%08x", packet->yiaddr);
795
796      return conf_path;
797 }
798
799 /* We call this too early to use malloc, 128 cells should be large enough */
800 #define NR_AVAILABLE 128
801
802 void prom_print_available(void)
803 {
804      prom_handle root;
805      unsigned int addr_cells, size_cells;
806      ihandle mem;
807      unsigned int available[NR_AVAILABLE];
808      unsigned int len;
809      unsigned int *p;
810
811      if (!yaboot_debug)
812           return;
813
814      root = prom_finddevice("/");
815      if (!root)
816           return;
817
818      addr_cells = 2;
819      prom_getprop(root, "#address-cells", &addr_cells, sizeof(addr_cells));
820
821      size_cells = 1;
822      prom_getprop(root, "#size-cells", &size_cells, sizeof(size_cells));
823
824      mem = prom_finddevice("/memory@0");
825      if (mem == PROM_INVALID_HANDLE)
826           return;
827
828      len = prom_getprop(mem, "available", available, sizeof(available));
829      if (len == -1)
830           return;
831      len /= 4;
832
833      prom_printf("\nAvailable memory ranges:\n");
834
835      p = available;
836      while (len > 0) {
837           unsigned int addr, size;
838
839           /*
840            * Since we are in 32bit mode it should be safe to only print the
841            * bottom 32bits of each range.
842            */
843           p += (addr_cells - 1);
844           addr = *p;
845           p++;
846
847           p += (size_cells - 1);
848           size = *p;
849           p++;
850
851           if (size)
852                prom_printf("0x%08x-0x%08x (%3d MB)\n", addr, addr + size,
853                            size/1024/1024);
854
855           len -= (addr_cells + size_cells);
856      }
857
858      prom_printf("\n");
859 }
860
861 /*
862  * Local variables:
863  * c-file-style: "k&r"
864  * c-basic-offset: 5
865  * End:
866  */