]> git.ozlabs.org Git - yaboot.git/blob - second/yaboot.c
2c616c3863b791076641c3d3c1edb146de746b36
[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 0x100000
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                                    prom_pause();
983                                    break;
984                               }
985                               initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
986                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
987                               initrd_size += initrd_read;
988                          }
989                     }
990                     file.fs->close(&file);
991                     memset(&file, 0, sizeof(file));
992                }
993                if (initrd_base)
994                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
995                                 initrd_base, initrd_size >> 10);
996                else {
997                     prom_printf("ramdisk load failed !\n");
998                     prom_pause();
999                }
1000           }
1001
1002           DEBUG_F("setting kernel args to: %s\n", params.args);
1003           prom_setargs(params.args);
1004           DEBUG_F("flushing icache...");
1005           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1006           DEBUG_F(" done\n");
1007
1008           if (flat_vmlinux) {
1009                /* 
1010                 * Fill new boot infos (only if booting a vmlinux).
1011                 *
1012                 * The birec is low on memory, probably inside the malloc pool,
1013                 * so we don't write it earlier. At this point, we should not
1014                 * use anything coming from the malloc pool.
1015                 */
1016                birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1017
1018                /* We make sure it's mapped. We map only 64k for now, it's
1019                 * plenty enough we don't claim since this precise memory
1020                 * range may already be claimed by the malloc pool.
1021                 */
1022                prom_map (birec, birec, 0x10000);
1023                DEBUG_F("birec at %p\n", birec);
1024                DEBUG_SLEEP;
1025
1026                birec->tag = BI_FIRST;
1027                birec->size = sizeof(struct bi_record);
1028                birec = (struct bi_record *)((ulong)birec + birec->size);
1029         
1030                birec->tag = BI_BOOTLOADER_ID;
1031                sprintf( (char *)birec->data, "yaboot");
1032                birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1033                birec = (struct bi_record *)((ulong)birec + birec->size);
1034         
1035                birec->tag = BI_MACHTYPE;
1036                birec->data[0] = _machine;
1037                birec->size = sizeof(struct bi_record) + sizeof(ulong);
1038                birec = (struct bi_record *)((ulong)birec + birec->size);
1039
1040                if (sysmap_base) {
1041                     birec->tag = BI_SYSMAP;
1042                     birec->data[0] = (ulong)sysmap_base;
1043                     birec->data[1] = sysmap_size;
1044                     birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1045                     birec = (struct bi_record *)((ulong)birec + birec->size);
1046                }
1047                birec->tag = BI_LAST;
1048                birec->size = sizeof(struct bi_record);
1049                birec = (struct bi_record *)((ulong)birec + birec->size);
1050           }
1051
1052           /* compute the kernel's entry point. */
1053           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1054
1055           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1056           DEBUG_F("kernel: arg1 = %p,\n"
1057                   "        arg2 = 0x%08lx,\n"
1058                   "        prom = %p,\n"
1059                   "        arg4 = %d,\n"
1060                   "        arg5 = %d\n\n",
1061                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1062
1063           DEBUG_F("Entering kernel...\n");
1064
1065           /* call the kernel with our stack. */
1066           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1067           continue;
1068      next:
1069           ; /* do nothing */
1070      }
1071 }
1072
1073 static int
1074 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1075 {
1076      int                        i;
1077      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1078      Elf32_Phdr         *p, *ph;
1079      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1080      unsigned long      addr, loadaddr;
1081
1082      /* Read the rest of the Elf header... */
1083      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1084           prom_printf("\nCan't read Elf32 image header\n");
1085           goto bail;
1086      }
1087
1088      DEBUG_F("Elf32 header:\n");
1089      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1090      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1091      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1092      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1093      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1094      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1095      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1096      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1097      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1098      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1099
1100      loadinfo->entry = e->e_entry;
1101
1102      if (e->e_phnum > MAX_HEADERS) {
1103           prom_printf ("Can only load kernels with one program header\n");
1104           goto bail;
1105      }
1106
1107      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1108      if (!ph) {
1109           prom_printf ("Malloc error\n");
1110           goto bail;
1111      }
1112
1113      /* Now, we read the section header */
1114      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1115           prom_printf ("seek error\n");
1116           goto bail;
1117      }
1118      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1119          sizeof(Elf32_Phdr) * e->e_phnum) {
1120           prom_printf ("read error\n");
1121           goto bail;
1122      }
1123
1124      /* Scan through the program header
1125       * HACK:  We must return the _memory size of the kernel image, not the
1126       *        file size (because we have to leave room before other boot
1127       *   infos. This code works as a side effect of the fact that
1128       *   we have one section and vaddr == p_paddr
1129       */
1130      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1131      p = ph;
1132      for (i = 0; i < e->e_phnum; ++i, ++p) {
1133           if (p->p_type != PT_LOAD || p->p_offset == 0)
1134                continue;
1135           if (loadinfo->memsize == 0) {
1136                loadinfo->offset = p->p_offset;
1137                loadinfo->memsize = p->p_memsz;
1138                loadinfo->filesize = p->p_filesz;
1139                loadinfo->load_loc = p->p_vaddr;
1140           } else {
1141                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1142                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1143           }
1144      }
1145
1146      if (loadinfo->memsize == 0) {
1147           prom_printf("Can't find a loadable segment !\n");
1148           goto bail;
1149      }
1150
1151      /* leave some room (1Mb) for boot infos */
1152      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1153      /* Claim OF memory */
1154      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1155
1156      /* Determine whether we are trying to boot a vmlinux or some
1157       * other binary image (eg, zImage).  We load vmlinux's at
1158       * KERNELADDR and all other binaries at their e_entry value.
1159       */
1160      if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1161           flat_vmlinux = 1;
1162           loadaddr = KERNELADDR;
1163      } else {
1164           flat_vmlinux = 0;
1165           loadaddr = loadinfo->load_loc;
1166      }
1167
1168      /* On some systems, loadaddr may already be claimed, so try some
1169       * other nearby addresses before giving up.
1170       */
1171      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1172           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1173           if (loadinfo->base != (void *)-1) break;
1174      }
1175      if (loadinfo->base == (void *)-1) {
1176           prom_printf("Claim error, can't allocate kernel memory\n");
1177           goto bail;
1178      }  
1179
1180      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1181              loadinfo->base, loadinfo->memsize);
1182      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1183              loadaddr, loadinfo->memsize);
1184
1185      /* Load the program segments... */
1186      p = ph;
1187      for (i = 0; i < e->e_phnum; ++i, ++p) {
1188           unsigned long offset;
1189           if (p->p_type != PT_LOAD || p->p_offset == 0)
1190                continue;
1191
1192           /* Now, we skip to the image itself */
1193           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1194                prom_printf ("Seek error\n");
1195                prom_release(loadinfo->base, loadinfo->memsize);
1196                goto bail;
1197           }
1198           offset = p->p_vaddr - loadinfo->load_loc;
1199           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1200                prom_printf ("Read failed\n");
1201                prom_release(loadinfo->base, loadinfo->memsize);
1202                goto bail;
1203           }
1204      }
1205
1206      free(ph);
1207     
1208      /* Return success at loading the Elf32 kernel */
1209      return 1;
1210
1211 bail:
1212      if (ph)
1213        free(ph);
1214      return 0;
1215 }
1216
1217 static int
1218 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1219 {
1220      int                        i;
1221      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1222      Elf64_Phdr         *p, *ph;
1223      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1224      unsigned long      addr, loadaddr;
1225
1226      /* Read the rest of the Elf header... */
1227      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1228           prom_printf("\nCan't read Elf64 image header\n");
1229           goto bail;
1230      }
1231
1232      DEBUG_F("Elf64 header:\n");
1233      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1234      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1235      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1236      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1237      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1238      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1239      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1240      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1241      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1242      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1243
1244      loadinfo->entry = e->e_entry;
1245
1246      if (e->e_phnum > MAX_HEADERS) {
1247           prom_printf ("Can only load kernels with one program header\n");
1248           goto bail;
1249      }
1250
1251      ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1252      if (!ph) {
1253           prom_printf ("Malloc error\n");
1254           goto bail;
1255      }
1256
1257      /* Now, we read the section header */
1258      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1259           prom_printf ("Seek error\n");
1260           goto bail;
1261      }
1262      if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1263          sizeof(Elf64_Phdr) * e->e_phnum) {
1264           prom_printf ("Read error\n");
1265           goto bail;
1266      }
1267
1268      /* Scan through the program header
1269       * HACK:  We must return the _memory size of the kernel image, not the
1270       *        file size (because we have to leave room before other boot
1271       *   infos. This code works as a side effect of the fact that
1272       *   we have one section and vaddr == p_paddr
1273       */
1274      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1275      p = ph;
1276      for (i = 0; i < e->e_phnum; ++i, ++p) {
1277           if (p->p_type != PT_LOAD || p->p_offset == 0)
1278                continue;
1279           if (loadinfo->memsize == 0) {
1280                loadinfo->offset = p->p_offset;
1281                loadinfo->memsize = p->p_memsz;
1282                loadinfo->filesize = p->p_filesz;
1283                loadinfo->load_loc = p->p_vaddr;
1284           } else {
1285                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1286                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1287           }
1288      }
1289
1290      if (loadinfo->memsize == 0) {
1291           prom_printf("Can't find a loadable segment !\n");
1292           goto bail;
1293      }
1294
1295      /* leave some room (1Mb) for boot infos */
1296      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1297      /* Claim OF memory */
1298      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1299
1300      /* Determine whether we are trying to boot a vmlinux or some
1301       * other binary image (eg, zImage).  We load vmlinux's at
1302       * KERNELADDR and all other binaries at their e_entry value.
1303       */
1304      if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1305           flat_vmlinux = 1;
1306           loadaddr = KERNELADDR;
1307      } else {
1308           flat_vmlinux = 0;
1309           loadaddr = e->e_entry;
1310      }
1311
1312      /* On some systems, loadaddr may already be claimed, so try some
1313       * other nearby addresses before giving up.
1314       */
1315      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1316           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1317           if (loadinfo->base != (void *)-1) break;
1318      }
1319      if (loadinfo->base == (void *)-1) {
1320           prom_printf("Claim error, can't allocate kernel memory\n");
1321           goto bail;
1322      }  
1323
1324      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1325              loadinfo->base, loadinfo->memsize);
1326      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1327              loadaddr, loadinfo->memsize);
1328
1329      /* Load the program segments... */
1330      p = ph;
1331      for (i = 0; i < e->e_phnum; ++i, ++p) {
1332           unsigned long offset;
1333           if (p->p_type != PT_LOAD || p->p_offset == 0)
1334                continue;
1335
1336           /* Now, we skip to the image itself */
1337           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1338                prom_printf ("Seek error\n");
1339                prom_release(loadinfo->base, loadinfo->memsize);
1340                goto bail;
1341           }
1342           offset = p->p_vaddr - loadinfo->load_loc;
1343           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1344                prom_printf ("Read failed\n");
1345                prom_release(loadinfo->base, loadinfo->memsize);
1346                goto bail;
1347           }
1348      }
1349
1350      free(ph);
1351     
1352      /* Return success at loading the Elf64 kernel */
1353      return 1;
1354
1355 bail:
1356      if (ph)
1357        free(ph);
1358      return 0;
1359 }
1360
1361 static int
1362 is_elf32(loadinfo_t *loadinfo)
1363 {
1364      Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1365
1366      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1367              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1368              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1369              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1370              e->e_ident[EI_CLASS] == ELFCLASS32  &&
1371              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1372              e->e_type            == ET_EXEC        &&
1373              e->e_machine         == EM_PPC);
1374 }
1375
1376 static int
1377 is_elf64(loadinfo_t *loadinfo)
1378 {
1379      Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1380
1381      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1382              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1383              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1384              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1385              e->e_ident[EI_CLASS] == ELFCLASS64  &&
1386              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1387              e->e_type            == ET_EXEC        &&
1388              e->e_machine         == EM_PPC64);
1389 }
1390
1391 static void
1392 setup_display(void)
1393 {
1394 #ifdef CONFIG_SET_COLORMAP
1395      static unsigned char default_colors[] = {
1396           0x00, 0x00, 0x00,
1397           0x00, 0x00, 0xaa,
1398           0x00, 0xaa, 0x00,
1399           0x00, 0xaa, 0xaa,
1400           0xaa, 0x00, 0x00,
1401           0xaa, 0x00, 0xaa,
1402           0xaa, 0x55, 0x00,
1403           0xaa, 0xaa, 0xaa,
1404           0x55, 0x55, 0x55,
1405           0x55, 0x55, 0xff,
1406           0x55, 0xff, 0x55,
1407           0x55, 0xff, 0xff,
1408           0xff, 0x55, 0x55,
1409           0xff, 0x55, 0xff,
1410           0xff, 0xff, 0x55,
1411           0xff, 0xff, 0xff
1412      };
1413      int i, result;
1414      prom_handle scrn = PROM_INVALID_HANDLE;
1415
1416      /* Try Apple's mac-boot screen ihandle */
1417      result = (int)call_prom_return("interpret", 1, 2,
1418                                     "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1419      DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1420
1421      if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1422           char type[32];
1423           /* Hrm... check to see if stdout is a display */
1424           scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1425           DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1426           if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1427                DEBUG_F("got it ! stdout is a screen\n");
1428                scrn = prom_stdout;
1429           } else {
1430                /* Else, we try to open the package */
1431                scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1432                DEBUG_F("Open screen result: %p\n", scrn);
1433           }
1434      }
1435         
1436      if (scrn == PROM_INVALID_HANDLE) {
1437           prom_printf("No screen device found !/n");
1438           return;
1439      }
1440      for(i=0;i<16;i++) {
1441           prom_set_color(scrn, i, default_colors[i*3],
1442                          default_colors[i*3+1], default_colors[i*3+2]);
1443      }
1444      prom_printf("\x1b[1;37m\x1b[2;40m");       
1445 #ifdef COLOR_TEST
1446      for (i=0;i<16; i++) {
1447           prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1448                       ansi_color_table[i].index,
1449                       ansi_color_table[i].value,
1450                       ansi_color_table[i].name,
1451                       ansi_color_table[i].name);
1452           prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1453                       ansi_color_table[i].index,
1454                       ansi_color_table[i].value+10,
1455                       ansi_color_table[i].name,
1456                       ansi_color_table[i].name);
1457      }
1458      prom_printf("\x1b[1;37m\x1b[2;40m");       
1459 #endif /* COLOR_TEST */
1460
1461 #if !DEBUG
1462      prom_printf("\xc");
1463 #endif /* !DEBUG */
1464
1465 #endif /* CONFIG_SET_COLORMAP */
1466 }
1467
1468 int
1469 yaboot_main(void)
1470 {
1471      char *ptype;
1472
1473      if (_machine == _MACH_Pmac)
1474           setup_display();
1475         
1476      prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1477      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1478      if (bootdevice[0] == 0) {
1479           prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1480           DEBUG_F("boot-device = %s\n", bootdevice);
1481      }
1482      if (bootdevice[0] == 0) {
1483           prom_printf("Couldn't determine boot device\n");
1484           return -1;
1485      }
1486
1487      if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1488           prom_printf("%s: Unable to parse\n", bootdevice);
1489           return -1;
1490      }
1491      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1492              boot.dev, boot.part, boot.file);
1493
1494      if (strlen(boot.file)) {
1495           if (!strncmp(boot.file, "\\\\", 2))
1496                boot.file = "\\\\";
1497           else {
1498                char *p, *last;
1499                p = last = boot.file;
1500                while(*p) {
1501                     if (*p == '\\')
1502                          last = p;
1503                     p++;
1504                }
1505                if (p)
1506                     *(last) = 0;
1507                else
1508                     boot.file = "";
1509                if (strlen(boot.file))
1510                     strcat(boot.file, "\\");
1511           }
1512      }
1513      DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1514              boot.dev, boot.part, boot.file);
1515
1516      useconf = load_config_file(boot.dev, boot.file, boot.part);
1517
1518      prom_printf("Welcome to yaboot version " VERSION "\n");
1519      prom_printf("Enter \"help\" to get some basic usage information\n");
1520
1521      /* I am fed up with lusers using the wrong partition type and
1522         mailing me *when* it breaks */
1523
1524      if (_machine == _MACH_Pmac) {
1525           char *entry = cfg_get_strg(0, "ptypewarning");
1526           int warn = 1;
1527           if (entry)
1528                warn = strcmp(entry,
1529                              "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1530           if (warn) {
1531                ptype = get_part_type(boot.dev, boot.part);
1532                if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1533                     prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1534                                 "         type should be: \"Apple_Bootstrap\"\n\n", ptype);
1535                if (ptype)
1536                     free(ptype);
1537           }
1538      }
1539
1540      yaboot_text_ui();
1541
1542      prom_printf("Bye.\n");
1543      return 0;
1544 }
1545
1546 /* 
1547  * Local variables:
1548  * c-file-style: "k&r"
1549  * c-basic-offset: 5
1550  * End:
1551  */