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