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