Commit yaboot 1.3.0
[yaboot.git] / second / yaboot.c
1 /* Yaboot - secondary boot loader for Linux on ppc.
2
3    Copyright (C) 1999 Benjamin Herrenschmidt
4
5    portions based on poof
6
7    Copyright (C) 1999 Marius Vollmer
8
9    portions based on quik
10    
11    Copyright (C) 1996 Paul Mackerras.
12
13    Because this program is derived from the corresponding file in the
14    silo-0.64 distribution, it is also
15 sys
16    Copyright (C) 1996 Pete A. Zaitcev
17                  1996 Maurizio Plaza
18                  1996 David S. Miller
19                  1996 Miguel de Icaza
20                  1996 Jakub Jelinek
21
22    This program is free software; you can redistribute it and/or modify
23    it under the terms of the GNU General Public License as published by
24    the Free Software Foundation; either version 2 of the License, or
25    (at your option) any later version.
26
27    This program is distributed in the hope that it will be useful,
28    but WITHOUT ANY WARRANTY; without even the implied warranty of
29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30    GNU General Public License for more details.
31
32    You should have received a copy of the GNU General Public License
33    along with this program; if not, write to the Free Software
34    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
35 */
36
37 #include "stdarg.h"
38 #include "string.h"
39 #include "ctype.h"
40 #include "stdlib.h"
41 #include "prom.h"
42 #include "file.h"
43 #include "cfg.h"
44 #include "cmdline.h"
45 #include "yaboot.h"
46 #include "linux/elf.h"
47 #include "bootinfo.h"
48
49 #define CONFIG_FILE_NAME        "yaboot.conf"
50 #define CONFIG_FILE_MAX         0x8000          /* 32k */
51
52 #ifdef CONFIG_SPLASH_SCREEN
53 #include "gui.h"
54 #endif /* CONFIG_SPLASH_SCREEN */
55
56 #ifdef USE_MD5_PASSWORDS
57 #include "md5.h"
58 #endif /* USE_MD5_PASSWORDS */
59
60 /* align addr on a size boundry - adjust address up if needed -- Cort */
61 #define _ALIGN(addr,size)       (((addr)+size-1)&(~(size-1)))
62
63 /* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at.
64  * These are used to determine whether we are booting a vmlinux, in
65  * which case, it will be loaded at KERNELADDR.  Otherwise (eg zImage),
66  * we load the binary where it was linked at (ie, e_entry field in
67  * the ELF header).
68  */
69 #define KERNEL_LINK_ADDR_PPC32  0xC0000000UL
70 #define KERNEL_LINK_ADDR_PPC64  0xC000000000000000ULL
71
72 typedef struct {
73     union {
74         Elf32_Ehdr  elf32hdr;
75         Elf64_Ehdr  elf64hdr;
76     } elf;
77     void*           base;
78     unsigned long   memsize;
79     unsigned long   filesize;
80     unsigned long   offset;
81     unsigned long   load_loc;
82     unsigned long   entry;
83 } loadinfo_t;
84
85 typedef void (*kernel_entry_t)( void *,
86                                 unsigned long,
87                                 prom_entry,
88                                 unsigned long,
89                                 unsigned long );
90
91 /* Imported functions */
92 extern unsigned long reloc_offset(void);
93 extern long flush_icache_range(unsigned long start, unsigned long stop);
94
95 /* Exported functions */
96 int     yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
97
98 /* Local functions */
99 static int      yaboot_main(void);
100 static int      is_elf32(loadinfo_t *loadinfo);
101 static int      is_elf64(loadinfo_t *loadinfo);
102 static int      load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
103 static int      load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
104 static void     setup_display(void);
105
106 /* Locals & globals */
107
108 int useconf = 0;
109 char bootdevice[1024];
110 char *bootpath = NULL;
111 char *password = NULL;
112 int bootpartition = -1;
113 int _machine = _MACH_Pmac;
114
115 #ifdef CONFIG_COLOR_TEXT
116
117 /* Color values for text ui */
118 static struct ansi_color_t {
119         char*   name;
120         int     index;
121         int     value;
122 } ansi_color_table[] = {
123         { "black",              2, 30 },
124         { "blue",               0, 31 },
125         { "green",              0, 32 },
126         { "cyan",               0, 33 },
127         { "red",                0, 34 },
128         { "purple",             0, 35 },
129         { "brown",              0, 36 },
130         { "light-gray",         0, 37 },
131         { "dark-gray",          1, 30 },
132         { "light-blue",         1, 31 },
133         { "light-green",        1, 32 },
134         { "light-cyan",         1, 33 },
135         { "light-red",          1, 34 },
136         { "light-purple",       1, 35 },
137         { "yellow",             1, 36 },
138         { "white",              1, 37 },
139         { NULL,                 0, 0 },
140 };
141
142 /* Default colors for text ui */
143 int fgcolor = 15;
144 int bgcolor = 0;
145 #endif /* CONFIG_COLOR_TEXT */
146
147 #if DEBUG
148 static int test_bss;
149 static int test_data = 0;
150 #endif
151 static int pause_after;
152 static char *pause_message = "Type go<return> to continue.\n";
153 static char given_bootargs[1024];
154 static int given_bootargs_by_user = 0;
155
156 extern unsigned char linux_logo_red[];
157 extern unsigned char linux_logo_green[];
158 extern unsigned char linux_logo_blue[];
159
160 #define DEFAULT_TIMEOUT         -1
161
162 /* Entry, currently called directly by crt0 (bss not inited) */
163
164 extern char* __bss_start;
165 extern char* _end;
166
167 static struct first_info *quik_fip = NULL;
168
169 int
170 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
171 {
172         int result;
173         void* malloc_base = NULL;
174         prom_handle root;
175
176         /* OF seems to do it, but I'm not very confident */
177         memset(&__bss_start, 0, &_end - &__bss_start);
178         
179         /* Check for quik first stage bootloader (but I don't think we are
180          * compatible with it anyway, I'll look into backporting to older OF
181          * versions later
182          */
183         if (r5 == 0xdeadbeef) {
184                 r5 = r3;
185                 quik_fip = (struct first_info *)r4;
186         }
187
188         /* Initialize OF interface */
189         prom_init ((prom_entry) r5);
190         
191         /* Allocate some memory for malloc'ator */
192         malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
193         if (malloc_base == (void *)-1) {
194                 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08lx)\n",
195                         MALLOCSIZE, MALLOCADDR);
196                 return -1;
197         }
198         malloc_init(malloc_base, MALLOCSIZE);
199 #if DEBUG
200         prom_printf("Malloc buffer allocated at 0x%x (%d bytes)\n",
201                 malloc_base, MALLOCSIZE);
202 #endif
203                 
204         /* A few useless printf's */
205 #if DEBUG
206         prom_printf("reloc_offset :  %ld         (should be 0)\n", reloc_offset());
207         prom_printf("test_bss     :  %d         (should be 0)\n", test_bss);
208         prom_printf("test_data    :  %d         (should be 0)\n", test_data);
209         prom_printf("&test_data   :  0x%08lx\n", &test_data);
210         prom_printf("&test_bss    :  0x%08lx\n", &test_bss);
211         prom_printf("linked at    :  0x%08lx\n", TEXTADDR);
212 #endif  
213         /* ask the OF info if we're a chrp or pmac */
214         /* we need to set _machine before calling finish_device_tree */
215         root = prom_finddevice("/");
216         if (root != 0) {
217                 static char model[256];
218                 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
219                         !strncmp("chrp", model, 4))
220                         _machine = _MACH_chrp;
221                 else {
222                         if (prom_getprop(root, "model", model, 256 ) > 0 &&
223                                 !strncmp(model, "IBM", 3))
224                                 _machine = _MACH_chrp;
225                 }
226         }
227         
228 #if DEBUG
229         prom_printf("Running on _machine = %d\n", _machine);
230 #endif
231
232         /* Call out main */
233         result = yaboot_main();
234
235         /* Get rid of malloc pool */
236         malloc_dispose();
237         prom_release(malloc_base, MALLOCSIZE);
238 #if DEBUG
239         prom_printf("Malloc buffer released. Exiting with code %d\n",
240                 result);
241
242 #endif
243
244         /* Return to OF */
245         prom_exit();
246         
247         return result;
248         
249 }
250
251 #ifdef CONFIG_COLOR_TEXT
252 /*
253  * Validify color for text ui
254  */
255 static int
256 check_color_text_ui(char *color)
257 {
258         int i = 0;
259         while(ansi_color_table[i].name) {
260                 if (!strcmp(color, ansi_color_table[i].name))
261                         return i;
262                 i++;
263         }
264         return -1;
265 }      
266 #endif /* CONFIG_COLOR_TEXT */
267
268 /* Currently, the config file must be at the root of the filesystem.
269  * todo: recognize the full path to myself and use it to load the
270  * config file. Handle the "\\" (blessed system folder)
271  */
272 static int
273 load_config_file(char *device, char* path, int partition)
274 {
275     char *conf_file = NULL, *p;
276     struct boot_file_t file;
277     int sz, opened = 0, result = 0;
278     char conf_path[512];
279     struct boot_fspec_t fspec;
280
281     /* Allocate a buffer for the config file */
282     conf_file = malloc(CONFIG_FILE_MAX);
283     if (!conf_file) {
284         prom_printf("Can't alloc config file buffer\n");
285         goto bail;
286     }
287
288     /* Build the path to the file */
289     if (path)
290         strcpy(conf_path, path);
291     else if ( _machine == _MACH_chrp )
292         strcpy(conf_path, "/etc/");
293     else
294         conf_path[0] = 0;
295     strcat(conf_path, CONFIG_FILE_NAME);
296
297     /* Open it */
298     fspec.dev = device;
299     fspec.file = conf_path;
300     fspec.part = partition;
301     result = open_file(&fspec, &file);
302     if (result != FILE_ERR_OK) {
303         prom_printf("Can't open config file '%s', err: %d\n", conf_path, result);
304         goto bail;
305     }
306     opened = 1;
307
308     /* Read it */
309     sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
310     if (sz <= 0) {
311         prom_printf("Error, can't read config file\n");
312         goto bail;
313     }
314     prom_printf("Config file read, %d bytes\n", sz);
315
316     /* Close the file */
317     if (opened)
318         file.fs->close(&file);
319     opened = 0;
320
321     /* Call the parsing code in cfg.c */
322     if (cfg_parse(conf_path, conf_file, sz) < 0) {
323         prom_printf ("Syntax error or read error config\n");
324         goto bail;
325     }
326
327 #if DEBUG
328     prom_printf("Config file successfully parsed\n", sz);
329 #endif
330
331     /* Now, we do the initialisations stored in the config file */
332     p = cfg_get_strg(0, "init-code");
333     if (p)
334         prom_interpret(p);
335
336     password = cfg_get_strg(0, "password");
337         
338 #ifdef CONFIG_COLOR_TEXT
339     p = cfg_get_strg(0, "fgcolor");
340     if (p) {
341 #if DEBUG       
342        prom_printf("fgcolor=%s\n", p);
343 #endif
344        fgcolor = check_color_text_ui(p);
345        if (fgcolor == -1) {
346           prom_printf("Invalid fgcolor: \"%s\".\n", p);
347        }
348     }
349     p = cfg_get_strg(0, "bgcolor");
350     if (p) {
351 #if DEBUG      
352        prom_printf("bgcolor=%s\n", p);
353 #endif
354        bgcolor = check_color_text_ui(p);
355        if (bgcolor == -1)
356           prom_printf("Invalid bgcolor: \"%s\".\n", p);
357     }
358     if (bgcolor >= 0) {
359         char temp[64];
360         sprintf(temp, "%x to background-color", bgcolor); 
361         prom_interpret(temp); 
362 #if !DEBUG
363         prom_printf("\xc");
364 #endif  
365     }
366     if (fgcolor >= 0) {
367         char temp[64];
368         sprintf(temp, "%x to foreground-color", fgcolor); 
369         prom_interpret(temp); 
370     }
371 #endif /* CONFIG_COLOR_TEXT */
372    
373     p = cfg_get_strg(0, "init-message");
374     if (p)
375         prom_printf("%s\n", p);
376 #if 0
377     p = cfg_get_strg(0, "message");
378     if (p)
379         print_message_file(p);
380 #endif          
381
382     result = 1;
383     
384 bail:
385
386     if (opened)
387         file.fs->close(&file);
388     
389     if (result != 1 && conf_file)
390         free(conf_file);
391         
392     return result;
393 }
394
395 void maintabfunc (void)
396 {
397     if (useconf) {
398         cfg_print_images();
399         prom_printf("boot: %s", cbuff);
400     }
401 }
402
403 void
404 word_split(char **linep, char **paramsp)
405 {
406     char *p;
407
408     *paramsp = 0;
409     p = *linep;
410     if (p == 0)
411         return;
412     while (*p == ' ')
413         ++p;
414     if (*p == 0) {
415         *linep = 0;
416         return;
417     }
418     *linep = p;
419     while (*p != 0 && *p != ' ')
420         ++p;
421     while (*p == ' ')
422         *p++ = 0;
423     if (*p != 0)
424         *paramsp = p;
425 }
426
427 char *
428 make_params(char *label, char *params)
429 {
430     char *p, *q;
431     static char buffer[2048];
432
433     q = buffer;
434     *q = 0;
435
436     p = cfg_get_strg(label, "literal");
437     if (p) {
438         strcpy(q, p);
439         q = strchr(q, 0);
440         if (params) {
441             if (*p)
442                 *q++ = ' ';
443             strcpy(q, params);
444         }
445         return buffer;
446     }
447
448     p = cfg_get_strg(label, "root");
449     if (p) {
450         strcpy (q, "root=");
451         strcpy (q + 5, p);
452         q = strchr (q, 0);
453         *q++ = ' ';
454     }
455     if (cfg_get_flag(label, "read-only")) {
456         strcpy (q, "ro ");
457         q += 3;
458     }
459     if (cfg_get_flag(label, "read-write")) {
460         strcpy (q, "rw ");
461         q += 3;
462     }
463     p = cfg_get_strg(label, "ramdisk");
464     if (p) {
465         strcpy (q, "ramdisk=");
466         strcpy (q + 8, p);
467         q = strchr (q, 0);
468         *q++ = ' ';
469     }
470     p = cfg_get_strg(label, "initrd-size");
471     if (p) {
472         strcpy (q, "ramdisk_size=");
473         strcpy (q + 13, p);
474         q = strchr (q, 0);
475         *q++ = ' ';
476     }
477     if (cfg_get_flag(label, "novideo")) {
478         strcpy (q, "video=ofonly");
479         q = strchr (q, 0);
480         *q++ = ' ';
481     }
482     p = cfg_get_strg (label, "append");
483     if (p) {
484         strcpy (q, p);
485         q = strchr (q, 0);
486         *q++ = ' ';
487     }
488     *q = 0;
489     pause_after = cfg_get_flag (label, "pause-after");
490     p = cfg_get_strg(label, "pause-message");
491     if (p)
492         pause_message = p;
493     if (params)
494         strcpy(q, params);
495
496     return buffer;
497 }
498
499 void check_password(char *str)
500 {
501     int i, end;
502
503     for (i = 0; i < 3; i++) {
504          prom_printf ("\n%sassword: ", str);
505          passwdbuff[0] = 0;
506          cmdedit ((void (*)(void)) 0, 1);
507          prom_printf ("\n");
508 #ifdef USE_MD5_PASSWORDS
509          if (!strncmp (password, "$1$", 3)) {
510             if (!check_md5_password(passwdbuff, password))
511                return;
512          } 
513          else if (!strcmp (password, passwdbuff))
514             return;
515 #else
516          if (!strcmp (password, passwdbuff))
517             return;
518 #endif
519          if (i < 2)
520             prom_printf ("Password incorrect. Please try again...");
521     }
522     prom_printf ("Seems like you don't know the access password.  Go away!\n");
523     end = (prom_getms() + 3000);
524     while (prom_getms() <= end);
525     prom_interpret("reset-all");
526 }
527
528 int get_params(struct boot_param_t* params)
529 {
530     int defpart;
531     char *defdevice = 0;
532     char *p, *q, *endp;
533     int c, n;
534     char *imagename = 0, *label;
535     int timeout = -1;
536     int beg = 0, end;
537     int singlekey = 0;
538     int restricted = 0;
539     static int first = 1;
540     static char bootargs[1024];
541     static char imagepath[1024];
542     static char initrdpath[1024];
543     static char sysmappath[1024];
544 #ifdef CONFIG_SPLASH_SCREEN
545     static char splashpath[1024];
546 #endif /* CONFIG_SPLASH_SCREEN */
547
548     pause_after = 0;
549     memset(params, 0, sizeof(*params));
550     params->args = "";
551     params->kernel.part = -1;
552     params->rd.part = -1;
553     params->sysmap.part = -1;
554     params->splash.part = -1;
555     defpart = bootpartition;
556     
557     cmdinit();
558
559     if (first) {
560         first = 0;
561         prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
562         imagename = bootargs;
563         word_split(&imagename, &params->args);
564         timeout = DEFAULT_TIMEOUT;
565         if (imagename) {
566              prom_printf("Default supplied on the command line: ");
567              prom_printf("%s ", imagename);
568              if (params->args)
569                   prom_printf("%s", params->args);
570              prom_printf("\n");
571         }
572         if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
573             timeout = simple_strtol(q, NULL, 0);
574     }
575
576     prom_printf("boot: ");
577     c = -1;
578     if (timeout != -1) {
579          beg = prom_getms();
580          if (timeout > 0) {
581               end = beg + 100 * timeout;
582               do {
583                    c = prom_nbgetchar();
584               } while (c == -1 && prom_getms() <= end);
585          }
586          if (c == -1)
587               c = '\n';
588          else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
589               cbuff[0] = c;
590               cbuff[1] = 0;
591          }
592     }
593
594     if (c != -1 && c != '\n' && c != '\r') {
595          if (c == '\t') {
596               maintabfunc ();
597          }  else if (c >= ' ') {
598               cbuff[0] = c;
599               cbuff[1] = 0;
600               if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
601                    imagename = cbuff;
602                    singlekey = 1;
603                    prom_printf("%s\n", cbuff);
604               }
605          }
606     }
607
608     if (c == '\n' || c == '\r') {
609          if (!imagename)
610               imagename = cfg_get_default();
611          if (imagename)
612               prom_printf("%s", imagename);
613          if (params->args)
614               prom_printf(" %s", params->args);
615          prom_printf("\n");
616     } else if (!singlekey) {
617          cmdedit(maintabfunc, 0);
618          prom_printf("\n");
619          strcpy(given_bootargs, cbuff);
620          given_bootargs_by_user = 1;
621          imagename = cbuff;
622          word_split(&imagename, &params->args);
623     }
624
625     /* chrp gets this wrong, force it -- Cort */
626     if ( useconf && (!imagename || imagename[0] == 0 ))
627         imagename = cfg_get_default();
628
629     label = 0;
630     defdevice = bootdevice;
631
632     if (useconf) {
633         defdevice = cfg_get_strg(0, "device");
634         p = cfg_get_strg(0, "partition");
635         if (p) {
636             n = simple_strtol(p, &endp, 10);
637             if (endp != p && *endp == 0)
638                 defpart = n;
639         }
640         p = cfg_get_strg(0, "pause-message");
641         if (p)
642             pause_message = p;
643         if (cfg_get_flag(0, "restricted"))
644             restricted = 1;
645         p = cfg_get_strg(imagename, "image");
646         if (p && *p) {
647             label = imagename;
648             imagename = p;
649             defdevice = cfg_get_strg(label, "device");
650             if(!defdevice) defdevice=bootdevice;
651             p = cfg_get_strg(label, "partition");
652             if (p) {
653                 n = simple_strtol(p, &endp, 10);
654                 if (endp != p && *endp == 0)
655                     defpart = n;
656             }
657             if (cfg_get_flag(label, "restricted"))
658                  restricted = 1;
659             if (label) {
660                  if (params->args && password && restricted)
661                       check_password ("To specify image arguments you must enter the p");
662                  else if (password && !restricted)
663                       check_password ("P");
664             }
665             params->args = make_params(label, params->args);
666         }
667     }
668
669     if (!strcmp (imagename, "halt")) {
670          if (password)
671               check_password ("P");
672          prom_pause();
673          return 0;
674     }
675     if (!strcmp (imagename, "bye")) {
676          if (password) {
677               check_password ("P");
678               return 1;
679          }
680          return 1; 
681     }
682
683     if (imagename[0] == '$') {
684         /* forth command string */
685          if (password)
686               check_password ("P");
687          prom_interpret(imagename+1);
688          return 0;
689     }
690
691     strncpy(imagepath, imagename, 1024);
692
693     if (!label && password)
694          check_password ("To boot a custom image you must enter the p");
695
696     params->kernel.dev = parse_device_path(imagepath, &params->kernel.file,
697         &params->kernel.part);
698     if (validate_fspec(&params->kernel, defdevice, defpart) != FILE_ERR_OK) {
699         prom_printf(
700 "Enter the kernel image name as [device:][partno]/path, where partno is a\n"
701 "number from 0 to 16.  Instead of /path you can type [mm-nn] to specify a\n"
702 "range of disk blocks (512B)\n"
703 "Example: hd:3,/vmlinux\n");
704         return 0;
705     }
706
707     if (useconf) {
708         p = cfg_get_strg(label, "initrd");
709         if (p && *p) {
710 #if DEBUG
711             prom_printf("parsing initrd path <%s>\n", p);
712 #endif      
713             strncpy(initrdpath, p, 1024);
714             params->rd.dev = parse_device_path(initrdpath,
715                 &params->rd.file, &params->rd.part);
716             validate_fspec(&params->rd, defdevice, defpart);
717         }
718         p = cfg_get_strg(label, "sysmap");
719         if (p && *p) {
720 #if DEBUG
721             prom_printf("parsing sysmap path <%s>\n", p);
722 #endif      
723             strncpy(sysmappath, p, 1024);
724             params->sysmap.dev = parse_device_path(sysmappath,
725                 &params->sysmap.file, &params->sysmap.part);
726             validate_fspec(&params->sysmap, defdevice, defpart);
727         }
728 #ifdef CONFIG_SPLASH_SCREEN
729         p = cfg_get_strg(label, "splash");
730         if (p && *p) {
731 #if DEBUG
732             prom_printf("parsing splash path <%s>\n", p);
733 #endif      
734             strncpy(splashpath, p, 1024);
735             params->splash.dev = parse_device_path(splashpath,
736                 &params->splash.file, &params->splash.part);
737             validate_fspec(&params->splash, defdevice, defpart);
738         }
739 #endif /* CONFIG_SPLASH_SCREEN */
740    }
741     
742     return 0;
743 }
744
745 /* This is derived from quik core. To be changed to first parse the headers
746  * doing lazy-loading, and then claim the memory before loading the kernel
747  * to it
748  * We also need to add initrd support to this whole mecanism
749  */
750 void
751 yaboot_text_ui(void)
752 {
753 #define MAX_HEADERS     32
754
755     struct boot_file_t  file;
756     int                 result;
757     static struct boot_param_t  params;
758     void                *initrd_base;
759     unsigned long       initrd_size;
760     void                *sysmap_base;
761     unsigned long       sysmap_size;
762     kernel_entry_t      kernel_entry;
763     struct bi_record*   birec;
764     char*               loc=NULL;
765     loadinfo_t          loadinfo;
766     void                *initrd_more,*initrd_want;
767     unsigned long       initrd_read;
768     
769     loadinfo.load_loc = 0;
770
771     for (;;) {
772         initrd_size = 0;
773         initrd_base = 0;
774         sysmap_base = 0;
775         sysmap_size = 0;
776         
777         if (get_params(&params))
778             return;
779         if (!params.kernel.file)
780             continue;
781         
782 #ifdef CONFIG_SPLASH_SCREEN
783         if (params.splash.file)
784                 fxDisplaySplash(&params.splash);
785 #endif /* CONFIG_SPLASH_SCREEN */
786         prom_printf("Please wait, loading kernel...\n");
787
788         if(bootpath && !strcmp(bootpath,"\\\\") && params.kernel.file[0] != '/') {
789                 loc=(char*)malloc(strlen(params.kernel.file)+3);
790                 if (!loc) {
791                         prom_printf ("malloc error\n");
792                         goto next;
793                 }
794                 strcpy(loc,bootpath);
795                 strcat(loc,params.kernel.file);
796                 free(params.kernel.file);
797                 params.kernel.file=loc;
798         }
799         result = open_file(&params.kernel, &file);
800         if (result != FILE_ERR_OK) {
801             prom_printf("\nImage not found.... try again\n");
802             goto next;
803         }
804
805         /* Read the Elf e_ident, e_type and e_machine fields to
806          * determine Elf file type
807          */
808         if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
809             prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
810             goto next;
811         }
812
813         if ( is_elf32(&loadinfo) ) {
814             if ( !load_elf32(&file, &loadinfo) )
815                 goto next;
816             prom_printf("   Elf32 kernel loaded...\n");
817         } else if ( is_elf64(&loadinfo) ) {
818             if ( !load_elf64(&file, &loadinfo) )
819                 goto next;
820             prom_printf("   Elf64 kernel loaded...\n");
821         } else {
822             prom_printf ("Not a valid ELF image\n");
823             goto next;
824         }
825         file.fs->close(&file);
826
827         /* If sysmap, load it. 
828          */
829         if (params.sysmap.file) {
830             prom_printf("Loading System.map ...\n");
831             if(bootpath && !strcmp(bootpath,"\\\\") && params.sysmap.file[0] != '/') {
832                     if (loc) free(loc);
833                     loc=(char*)malloc(strlen(params.sysmap.file)+3);
834                     if (!loc) {
835                             prom_printf ("malloc error\n");
836                             goto next;
837                     }
838                     strcpy(loc,bootpath);
839                     strcat(loc,params.sysmap.file);
840                     free(params.sysmap.file);
841                     params.sysmap.file=loc;
842             }
843
844             result = open_file(&params.sysmap, &file);
845             if (result != FILE_ERR_OK)
846                 prom_printf("\nSystem.map file not found.\n");
847             else {
848                 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
849                 if (sysmap_base == (void *)-1) {
850                     prom_printf("claim failed for sysmap memory\n");
851                     sysmap_base = 0;
852                 } else {
853                     sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
854                     if (sysmap_size == 0)
855                         sysmap_base = 0;
856                     else
857                         ((char *)sysmap_base)[sysmap_size++] = 0;
858                 }
859                 file.fs->close(&file);
860             }
861             if (sysmap_base) {
862                 prom_printf("System.map loaded at 0x%08lx, size: %d Kbytes\n",
863                         sysmap_base, sysmap_size >> 10);
864                 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
865             } else {
866                 prom_printf("System.map load failed !\n");
867                 prom_pause();
868             }
869         }
870
871         /* If ramdisk, load it. For now, we can't tell the size it will be
872          * so we claim an arbitrary amount of 4Mb
873          */
874         if (params.rd.file) {
875             if(bootpath && !strcmp(bootpath,"\\\\") && params.rd.file[0] != '/')
876             {
877                 if (loc) free(loc);
878                 loc=(char*)malloc(strlen(params.rd.file)+3);
879                 if (!loc) {
880                     prom_printf ("malloc error\n");
881                     goto next;
882                 }
883                 strcpy(loc,bootpath);
884                 strcat(loc,params.rd.file);
885                 free(params.rd.file);
886                 params.rd.file=loc;
887             }
888             prom_printf("Loading ramdisk...\n");
889             result = open_file(&params.rd, &file);
890             if (result != FILE_ERR_OK)
891                 prom_printf("\nRamdisk image not found.\n");
892             else {
893 #define INITRD_CHUNKSIZE 0x400000
894                 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
895                 if (initrd_base == (void *)-1) {
896                     prom_printf("claim failed for initrd memory\n");
897                     initrd_base = 0;
898                 } else {
899                     initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
900                     if (initrd_size == 0)
901                         initrd_base = 0;
902                     initrd_read = initrd_size;
903                     initrd_more = initrd_base;
904                     while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
905                       initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
906                       initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
907                       if (initrd_more != initrd_want) {
908                         prom_printf("claim failed for initrd memory at %x rc=%x\n",initrd_want,initrd_more);
909                         break;
910                       }
911                     initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
912 #if DEBUG
913                     prom_printf("  block at %x rc=%x\n",initrd_more,initrd_read);
914 #endif
915                     initrd_size += initrd_read;
916                     }
917                 }
918                 file.fs->close(&file);
919             }
920             if (initrd_base)
921                 prom_printf("ramdisk loaded at 0x%08lx, size: %d Kbytes\n",
922                         initrd_base, initrd_size >> 10);
923             else {
924                 prom_printf("ramdisk load failed !\n");
925                 prom_pause();
926             }
927         }
928
929 #if DEBUG
930         prom_printf("setting kernel args to: %s\n", params.args);
931 #endif  
932         prom_setargs(params.args);
933 #if DEBUG
934         prom_printf("flushing icache...");
935 #endif  
936         flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
937 #if DEBUG
938         prom_printf(" done\n");
939 #endif  
940
941         /* 
942          * Fill mew boot infos
943          *
944          * The birec is low on memory, probably inside the malloc pool, so
945          * we don't write it earlier. At this point, we should not use anything
946          * coming from the malloc pool
947          */
948         birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
949
950         /* We make sure it's mapped. We map only 64k for now, it's plenty enough
951          * we don't claim since this precise memory range may already be claimed
952          * by the malloc pool
953          */
954         prom_map (birec, birec, 0x10000);
955 #if DEBUG
956         prom_printf("birec at 0x%08lx\n", birec);
957         {
958             int i = prom_getms();
959             while((prom_getms() - i) < 2000)
960                 ;
961         }
962 #endif  
963
964         birec->tag = BI_FIRST;
965         birec->size = sizeof(struct bi_record);
966         birec = (struct bi_record *)((unsigned long)birec + birec->size);
967         
968         birec->tag = BI_BOOTLOADER_ID;
969         sprintf( (char *)birec->data, "yaboot");
970         birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
971         birec = (struct bi_record *)((unsigned long)birec + birec->size);
972         
973         birec->tag = BI_MACHTYPE;
974         birec->data[0] = _machine;
975         birec->size = sizeof(struct bi_record) + sizeof(unsigned long);
976         birec = (struct bi_record *)((unsigned long)birec + birec->size);
977
978         if (sysmap_base) {
979                 birec->tag = BI_SYSMAP;
980                 birec->data[0] = (unsigned long)sysmap_base;
981                 birec->data[1] = sysmap_size;
982                 birec->size = sizeof(struct bi_record) + sizeof(unsigned long)*2;
983                 birec = (struct bi_record *)((unsigned long)birec + birec->size);
984         }
985         birec->tag = BI_LAST;
986         birec->size = sizeof(struct bi_record);
987         birec = (struct bi_record *)((unsigned long)birec + birec->size);
988
989         /* compute the kernel's entry point. */
990         kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
991
992 #if DEBUG
993         prom_printf("Kernel entry point = 0x%08lx\n", kernel_entry);
994         prom_printf("kernel: arg1 = 0x%08lx,\n"
995                     "        arg2 = 0x%08lx,\n"
996                     "        prom = 0x%08lx,\n"
997                     "        arg4 = 0x%08lx,\n"
998                     "        arg5 = 0x%08lx\n\n",
999                 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1000
1001 #endif  
1002
1003 #if DEBUG
1004         prom_printf("entering kernel...\n");
1005 #endif
1006         /* call the kernel with our stack. */
1007         kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1008         continue;
1009 next:
1010         if( file.fs != NULL )
1011             file.fs->close(&file);    
1012     }
1013 }
1014
1015 static int
1016 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1017 {
1018     int                 i;
1019     Elf32_Ehdr          *e = &(loadinfo->elf.elf32hdr);
1020     Elf32_Phdr          *p, *ph;
1021     int                 size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1022     unsigned long       addr, loadaddr;
1023
1024     /* Read the rest of the Elf header... */
1025     if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1026         prom_printf("\nCan't read Elf32 image header\n");
1027         return 0;
1028     }
1029
1030 #if DEBUG
1031     prom_printf("Elf32 header:\n");
1032     prom_printf(" e.e_type      = %d\n", (int)e->e_type);
1033     prom_printf(" e.e_machine   = %d\n", (int)e->e_machine);
1034     prom_printf(" e.e_version   = %d\n", (int)e->e_version);
1035     prom_printf(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1036     prom_printf(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1037     prom_printf(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1038     prom_printf(" e.e_flags     = %d\n", (int)e->e_flags);
1039     prom_printf(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1040     prom_printf(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1041     prom_printf(" e.e_phnum     = %d\n", (int)e->e_phnum);
1042 #endif      
1043
1044     loadinfo->entry = e->e_entry;
1045
1046     if (e->e_phnum > MAX_HEADERS) {
1047         prom_printf ("can only load kernels with one program header\n");
1048         return 0;
1049     }
1050
1051     ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1052     if (!ph) {
1053         prom_printf ("malloc error\n");
1054         return 0;
1055     }
1056
1057     /* Now, we read the section header */
1058     if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1059         prom_printf ("seek error\n");
1060         return 0;
1061     }
1062     if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1063             sizeof(Elf32_Phdr) * e->e_phnum) {
1064         prom_printf ("read error\n");
1065         return 0;
1066     }
1067
1068     /* Scan through the program header
1069      * HACK:  We must return the _memory size of the kernel image, not the
1070      *        file size (because we have to leave room before other boot
1071      *    infos. This code works as a side effect of the fact that
1072      *    we have one section and vaddr == p_paddr
1073      */
1074     loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1075     p = ph;
1076     for (i = 0; i < e->e_phnum; ++i, ++p) {
1077         if (p->p_type != PT_LOAD || p->p_offset == 0)
1078             continue;
1079         if (loadinfo->memsize == 0) {
1080             loadinfo->offset = p->p_offset;
1081             loadinfo->memsize = p->p_memsz;
1082             loadinfo->filesize = p->p_filesz;
1083             loadinfo->load_loc = p->p_vaddr;
1084         } else {
1085             loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1086             loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1087         }
1088     }
1089
1090     if (loadinfo->memsize == 0) {
1091         prom_printf("Can't find a loadable segment !\n");
1092         return 0;
1093     }
1094
1095     /* leave some room (1Mb) for boot infos */
1096     loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1097     /* Claim OF memory */
1098 #if DEBUG
1099     prom_printf("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1100 #endif    
1101
1102     /* On some systems, loadaddr may already be claimed, so try some
1103      * other nearby addresses before giving up.
1104      */
1105     loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC32) ? KERNELADDR : e->e_entry;
1106     for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1107         loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1108         if (loadinfo->base != (void *)-1) break;
1109     }
1110     if (loadinfo->base == (void *)-1) {
1111         prom_printf("claim error, can't allocate kernel memory\n");
1112         return 0;
1113     }   
1114
1115 #if DEBUG
1116     prom_printf("After ELF parsing, load base: 0x%08lx, mem_sz: 0x%08lx\n",
1117             loadinfo->base, loadinfo->memsize);
1118     prom_printf("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1119             loadaddr, loadinfo->memsize);
1120 #endif    
1121
1122     /* Load the program segments... */
1123     p = ph;
1124     for (i = 0; i < e->e_phnum; ++i, ++p) {
1125             unsigned long offset;
1126             if (p->p_type != PT_LOAD || p->p_offset == 0)
1127                     continue;
1128
1129             /* Now, we skip to the image itself */
1130             if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1131                     prom_printf ("seek error\n");
1132                     prom_release(loadinfo->base, loadinfo->memsize);
1133                     return 0;
1134             }
1135             offset = p->p_vaddr - loadinfo->load_loc;
1136 #ifdef CONFIG_SPLASH_SCREEN
1137             if (fxReadImage(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1138 #else /* CONFIG_SPLASH_SCREEN */
1139             if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1140 #endif /* CONFIG_SPLASH_SCREEN */
1141                     prom_printf ("read failed\n");
1142                     prom_release(loadinfo->base, loadinfo->memsize);
1143                     return 0;
1144             }
1145     }
1146
1147 #if 0   /* to make editor happy */
1148     }
1149 #endif  
1150     (*(file->fs->close))(file);
1151
1152     free(ph);
1153     
1154     /* Return success at loading the Elf32 kernel */
1155     return 1;
1156 }
1157
1158 static int
1159 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1160 {
1161     int                 i;
1162     Elf64_Ehdr          *e = &(loadinfo->elf.elf64hdr);
1163     Elf64_Phdr          *p, *ph;
1164     int                 size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1165     unsigned long       addr, loadaddr;
1166
1167     /* Read the rest of the Elf header... */
1168     if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1169         prom_printf("\nCan't read Elf64 image header\n");
1170         return 0;
1171     }
1172
1173 #if DEBUG
1174     prom_printf("Elf64 header:\n");
1175     prom_printf(" e.e_type      = %d\n", (int)e->e_type);
1176     prom_printf(" e.e_machine   = %d\n", (int)e->e_machine);
1177     prom_printf(" e.e_version   = %d\n", (int)e->e_version);
1178     prom_printf(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1179     prom_printf(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1180     prom_printf(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1181     prom_printf(" e.e_flags     = %d\n", (int)e->e_flags);
1182     prom_printf(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1183     prom_printf(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1184     prom_printf(" e.e_phnum     = %d\n", (int)e->e_phnum);
1185 #endif      
1186
1187     loadinfo->entry = e->e_entry;
1188
1189     if (e->e_phnum > MAX_HEADERS) {
1190         prom_printf ("can only load kernels with one program header\n");
1191         return 0;
1192     }
1193
1194     ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1195     if (!ph) {
1196         prom_printf ("malloc error\n");
1197         return 0;
1198     }
1199
1200     /* Now, we read the section header */
1201     if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1202         prom_printf ("seek error\n");
1203         return 0;
1204     }
1205     if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1206             sizeof(Elf64_Phdr) * e->e_phnum) {
1207         prom_printf ("read error\n");
1208         return 0;
1209     }
1210
1211     /* Scan through the program header
1212      * HACK:  We must return the _memory size of the kernel image, not the
1213      *        file size (because we have to leave room before other boot
1214      *    infos. This code works as a side effect of the fact that
1215      *    we have one section and vaddr == p_paddr
1216      */
1217     loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1218     p = ph;
1219     for (i = 0; i < e->e_phnum; ++i, ++p) {
1220         if (p->p_type != PT_LOAD || p->p_offset == 0)
1221             continue;
1222         if (loadinfo->memsize == 0) {
1223             loadinfo->offset = p->p_offset;
1224             loadinfo->memsize = p->p_memsz;
1225             loadinfo->filesize = p->p_filesz;
1226             loadinfo->load_loc = p->p_vaddr;
1227         } else {
1228             loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1229             loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1230         }
1231     }
1232
1233     if (loadinfo->memsize == 0) {
1234         prom_printf("Can't find a loadable segment !\n");
1235         return 0;
1236     }
1237
1238     /* leave some room (1Mb) for boot infos */
1239     loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1240     /* Claim OF memory */
1241 #if DEBUG
1242     prom_printf("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1243 #endif    
1244
1245     /* On some systems, loadaddr may already be claimed, so try some
1246      * other nearby addresses before giving up.
1247      */
1248     loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC64) ? KERNELADDR : e->e_entry;
1249     for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1250         loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1251         if (loadinfo->base != (void *)-1) break;
1252     }
1253     if (loadinfo->base == (void *)-1) {
1254         prom_printf("claim error, can't allocate kernel memory\n");
1255         return 0;
1256     }   
1257
1258 #if DEBUG
1259     prom_printf("After ELF parsing, load base: 0x%08lx, mem_sz: 0x%08lx\n",
1260             loadinfo->base, loadinfo->memsize);
1261     prom_printf("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1262             loadaddr, loadinfo->memsize);
1263 #endif    
1264
1265     /* Load the program segments... */
1266     p = ph;
1267     for (i = 0; i < e->e_phnum; ++i, ++p) {
1268             unsigned long offset;
1269             if (p->p_type != PT_LOAD || p->p_offset == 0)
1270                     continue;
1271
1272             /* Now, we skip to the image itself */
1273             if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1274                     prom_printf ("seek error\n");
1275                     prom_release(loadinfo->base, loadinfo->memsize);
1276                     return 0;
1277             }
1278             offset = p->p_vaddr - loadinfo->load_loc;
1279 #ifdef CONFIG_SPLASH_SCREEN
1280             if (fxReadImage(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1281 #else /* CONFIG_SPLASH_SCREEN */
1282             if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1283 #endif /* CONFIG_SPLASH_SCREEN */
1284                     prom_printf ("read failed\n");
1285                     prom_release(loadinfo->base, loadinfo->memsize);
1286                     return 0;
1287             }
1288     }
1289
1290 #if 0   /* to make editor happy */
1291     }
1292 #endif  
1293     (*(file->fs->close))(file);
1294
1295     free(ph);
1296     
1297     /* Return success at loading the Elf64 kernel */
1298     return 1;
1299 }
1300
1301 static int
1302 is_elf32(loadinfo_t *loadinfo)
1303 {
1304         Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1305
1306         return (e->e_ident[EI_MAG0]  == ELFMAG0     &&
1307                 e->e_ident[EI_MAG1]  == ELFMAG1     &&
1308                 e->e_ident[EI_MAG2]  == ELFMAG2     &&
1309                 e->e_ident[EI_MAG3]  == ELFMAG3     &&
1310                 e->e_ident[EI_CLASS] == ELFCLASS32  &&
1311                 e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1312                 e->e_type            == ET_EXEC     &&
1313                 e->e_machine         == EM_PPC);
1314 }
1315
1316 static int
1317 is_elf64(loadinfo_t *loadinfo)
1318 {
1319         Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1320
1321         return (e->e_ident[EI_MAG0]  == ELFMAG0     &&
1322                 e->e_ident[EI_MAG1]  == ELFMAG1     &&
1323                 e->e_ident[EI_MAG2]  == ELFMAG2     &&
1324                 e->e_ident[EI_MAG3]  == ELFMAG3     &&
1325                 e->e_ident[EI_CLASS] == ELFCLASS64  &&
1326                 e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1327                 e->e_type            == ET_EXEC     &&
1328                 e->e_machine         == EM_PPC64);
1329 }
1330
1331 static void
1332 setup_display(void)
1333 {
1334 #ifdef CONFIG_SET_COLORMAP
1335         static unsigned char default_colors[] = {
1336                 0x00, 0x00, 0x00,
1337                 0x00, 0x00, 0xaa,
1338                 0x00, 0xaa, 0x00,
1339                 0x00, 0xaa, 0xaa,
1340                 0xaa, 0x00, 0x00,
1341                 0xaa, 0x00, 0xaa,
1342                 0xaa, 0x55, 0x00,
1343                 0xaa, 0xaa, 0xaa,
1344                 0x55, 0x55, 0x55,
1345                 0x55, 0x55, 0xff,
1346                 0x55, 0xff, 0x55,
1347                 0x55, 0xff, 0xff,
1348                 0xff, 0x55, 0x55,
1349                 0xff, 0x55, 0xff,
1350                 0xff, 0xff, 0x55,
1351                 0xff, 0xff, 0xff
1352         };
1353         int i, result;
1354         prom_handle scrn = PROM_INVALID_HANDLE;
1355
1356         /* Try Apple's mac-boot screen ihandle */
1357         result = (int)call_prom_return("interpret", 1, 2,
1358                 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1359 #if DEBUG
1360         prom_printf("trying to get screen ihandle, result: 0x%x, scrn: 0x%x\n", result, scrn);
1361 #endif          
1362         if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1363                 char type[32];
1364                 /* Hrm... check to see if stdout is a display */
1365                 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1366 #if DEBUG
1367                 prom_printf("instance-to-package of stdout is: 0x%x\n", scrn);
1368 #endif          
1369                 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1370 #if DEBUG
1371                         prom_printf("got it ! stdout is a screen\n");
1372 #endif          
1373                         scrn = prom_stdout;
1374                 } else {
1375                         /* Else, we try to open the package */
1376                         scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1377 #if DEBUG
1378                         prom_printf("Open screen result: 0x%x\n", scrn);
1379 #endif          
1380                 }
1381         }
1382         
1383         if (scrn == PROM_INVALID_HANDLE) {
1384                 prom_printf("no screen device found !/n");
1385                 return;
1386         }
1387         for(i=0;i<16;i++) {
1388                 prom_set_color(scrn, i, default_colors[i*3],
1389                         default_colors[i*3+1], default_colors[i*3+2]);
1390         }
1391         prom_printf("\x1b[1;37m\x1b[2;40m");    
1392 #ifdef COLOR_TEST
1393         for (i=0;i<16; i++) {
1394                 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1395                         ansi_color_table[i].index,
1396                         ansi_color_table[i].value,
1397                         ansi_color_table[i].name,
1398                         ansi_color_table[i].name);
1399                 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1400                         ansi_color_table[i].index,
1401                         ansi_color_table[i].value+10,
1402                         ansi_color_table[i].name,
1403                         ansi_color_table[i].name);
1404         }
1405         prom_printf("\x1b[1;37m\x1b[2;40m");    
1406 #endif
1407 #if !DEBUG
1408         prom_printf("\xc");
1409 #endif  
1410 #endif /* CONFIG_SET_COLORMAP */
1411 }
1412
1413 int
1414 yaboot_main(void)
1415 {
1416         if (_machine == _MACH_Pmac)
1417                 setup_display();
1418         
1419         prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1420 #if DEBUG
1421         prom_printf("/chosen/bootpath = %s\n", bootdevice);
1422 #endif  
1423         if (bootdevice[0] == 0)
1424                 prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1425         if (bootdevice[0] == 0) {
1426             prom_printf("Couldn't determine boot device\n");
1427             return -1;
1428         }
1429         parse_device_path(bootdevice, &bootpath, &bootpartition);
1430 #if DEBUG
1431         prom_printf("after parse_device_path: device:%s, path: %s, partition: %d\n",
1432                 bootdevice, bootpath ? bootpath : NULL, bootpartition);
1433 #endif  
1434         if (bootpath) {
1435                 if (!strncmp(bootpath, "\\\\", 2))
1436                         bootpath[2] = 0;
1437                 else {
1438                         char *p, *last;
1439                         p = last = bootpath;
1440                         while(*p) {
1441                             if (*p == '\\')
1442                                 last = p;
1443                             p++;
1444                         }
1445                         if (p)
1446                                 *(last) = 0;
1447                         else
1448                                 bootpath = NULL;
1449                         if (bootpath && strlen(bootpath))
1450                                 strcat(bootpath, "\\");
1451                 }
1452         }
1453 #if DEBUG
1454         prom_printf("after path fixup: device:%s, path: %s, partition: %d\n",
1455                 bootdevice, bootpath ? bootpath : NULL, bootpartition);
1456 #endif  
1457         useconf = load_config_file(bootdevice, bootpath, bootpartition);
1458
1459         prom_printf("Welcome to yaboot version " VERSION "\n");
1460         
1461         yaboot_text_ui();
1462         
1463         prom_printf("Bye.\n");
1464         return 0;
1465 }