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