Commit yaboot 1.3.6-pre1
[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      for (i = 0; i < 3; i++) {
546           prom_printf ("\n%sassword: ", str);
547           passwdbuff[0] = 0;
548           cmdedit ((void (*)(void)) 0, 1);
549           prom_printf ("\n");
550 #ifdef USE_MD5_PASSWORDS
551           if (!strncmp (password, "$1$", 3)) {
552                if (!check_md5_password(passwdbuff, password))
553                     return;
554           } 
555           else if (!strcmp (password, passwdbuff))
556                return;
557 #else /* !MD5 */
558           if (!strcmp (password, passwdbuff))
559                return;
560 #endif /* USE_MD5_PASSWORDS */
561           if (i < 2)
562                prom_printf ("Password incorrect. Please try again...");
563      }
564      prom_printf ("Seems like you don't know the access password.  Go away!\n");
565      prom_sleep(3);
566      prom_interpret("reset-all");
567 }
568
569 int get_params(struct boot_param_t* params)
570 {
571      int defpart;
572      char *defdevice = 0;
573      char *p, *q, *endp;
574      int c, n;
575      char *imagename = 0, *label;
576      int timeout = -1;
577      int beg = 0, end;
578      int singlekey = 0;
579      int restricted = 0;
580      static int first = 1;
581      static char bootargs[1024];
582      static char imagepath[1024];
583      static char initrdpath[1024];
584      static char sysmappath[1024];
585
586      pause_after = 0;
587      memset(params, 0, sizeof(*params));
588      params->args = "";
589      params->kernel.part = -1;
590      params->rd.part = -1;
591      params->sysmap.part = -1;
592      defpart = boot.part;
593     
594      cmdinit();
595
596      if (first) {
597           first = 0;
598           prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
599           imagename = bootargs;
600           word_split(&imagename, &params->args);
601           timeout = DEFAULT_TIMEOUT;
602           if (imagename) {
603                prom_printf("Default supplied on the command line: %s ", imagename);
604                if (params->args)
605                     prom_printf("%s", params->args);
606                prom_printf("\n");
607           }
608           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
609                timeout = simple_strtol(q, NULL, 0);
610      }
611
612      prom_printf("boot: ");
613      c = -1;
614      if (timeout != -1) {
615           beg = prom_getms();
616           if (timeout > 0) {
617                end = beg + 100 * timeout;
618                do {
619                     c = prom_nbgetchar();
620                } while (c == -1 && prom_getms() <= end);
621           }
622           if (c == -1)
623                c = '\n';
624           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
625                cbuff[0] = c;
626                cbuff[1] = 0;
627           }
628      }
629
630      if (c != -1 && c != '\n' && c != '\r') {
631           if (c == '\t') {
632                maintabfunc ();
633           }  else if (c >= ' ') {
634                cbuff[0] = c;
635                cbuff[1] = 0;
636                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
637                     imagename = cbuff;
638                     singlekey = 1;
639                     prom_printf("%s\n", cbuff);
640                }
641           }
642      }
643
644      if (c == '\n' || c == '\r') {
645           if (!imagename)
646                imagename = cfg_get_default();
647           if (imagename)
648                prom_printf("%s", imagename);
649           if (params->args)
650                prom_printf(" %s", params->args);
651           prom_printf("\n");
652      } else if (!singlekey) {
653           cmdedit(maintabfunc, 0);
654           prom_printf("\n");
655           strcpy(given_bootargs, cbuff);
656           given_bootargs_by_user = 1;
657           imagename = cbuff;
658           word_split(&imagename, &params->args);
659      }
660
661      /* chrp gets this wrong, force it -- Cort */
662      if ( useconf && (!imagename || imagename[0] == 0 ))
663           imagename = cfg_get_default();
664
665      label = 0;
666      defdevice = boot.dev;
667
668      if (useconf) {
669           defdevice = cfg_get_strg(0, "device");
670           p = cfg_get_strg(0, "partition");
671           if (p) {
672                n = simple_strtol(p, &endp, 10);
673                if (endp != p && *endp == 0)
674                     defpart = n;
675           }
676           p = cfg_get_strg(0, "pause-message");
677           if (p)
678                pause_message = p;
679           if (cfg_get_flag(0, "restricted"))
680                restricted = 1;
681           p = cfg_get_strg(imagename, "image");
682           if (p && *p) {
683                label = imagename;
684                imagename = p;
685                defdevice = cfg_get_strg(label, "device");
686                if(!defdevice) defdevice=boot.dev;
687                p = cfg_get_strg(label, "partition");
688                if (p) {
689                     n = simple_strtol(p, &endp, 10);
690                     if (endp != p && *endp == 0)
691                          defpart = n;
692                }
693                if (cfg_get_flag(label, "restricted"))
694                     restricted = 1;
695                if (label) {
696                     if (params->args && password && restricted)
697                          check_password ("To specify image arguments you must enter the p");
698                     else if (password && !restricted)
699                          check_password ("P");
700                }
701                params->args = make_params(label, params->args);
702           }
703      }
704
705      if (!strcmp (imagename, "help")) {
706           prom_printf(
707                "\nPress the tab key for a list of defined images.\n"
708                "The label marked with a \"*\" is is the default image, "
709                "press <return> to boot it.\n\n"
710                "To boot any other label simply type its name and press <return>.\n\n"
711                "To boot a kernel image which is not defined in the yaboot configuration \n"
712                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
713                "\"device:\" is the OpenFirmware device path to the disk the image \n"
714                "resides on, and \"partno\" is the partition number the image resides on.\n"
715                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
716                "device, if you only specify a filename you should not start it with a \",\"\n\n"
717                "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
718                "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
719                "device=%s\n"
720                "partition=%d\n\n", defdevice, defpart);
721           return 0;
722      }
723
724      if (!strcmp (imagename, "halt")) {
725           if (password)
726                check_password ("P");
727           prom_pause();
728           return 0;
729      }
730      if (!strcmp (imagename, "bye")) {
731           if (password) {
732                check_password ("P");
733                return 1;
734           }
735           return 1; 
736      }
737
738      if (imagename[0] == '$') {
739           /* forth command string */
740           if (password)
741                check_password ("P");
742           prom_interpret(imagename+1);
743           return 0;
744      }
745
746      strncpy(imagepath, imagename, 1024);
747
748      if (!label && password)
749           check_password ("To boot a custom image you must enter the p");
750
751      if (!parse_device_path(imagepath, defdevice, defpart,
752                             "/vmlinux", &params->kernel)) {
753           prom_printf("%s: Unable to parse\n", imagepath);
754           return 0;
755      }
756      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
757              params->kernel.part, params->kernel.file);
758
759      if (useconf) {
760           p = cfg_get_strg(label, "initrd");
761           if (p && *p) {
762                DEBUG_F("Parsing initrd path <%s>\n", p);
763                strncpy(initrdpath, p, 1024);
764                if (!parse_device_path(initrdpath, defdevice, defpart,
765                                       "/root.bin", &params->rd)) {
766                     prom_printf("%s: Unable to parse\n", imagepath);
767                     return 0;
768                }
769           }
770           p = cfg_get_strg(label, "sysmap");
771           if (p && *p) {
772                DEBUG_F("Parsing sysmap path <%s>\n", p);
773                strncpy(sysmappath, p, 1024);
774                if (!parse_device_path(sysmappath, defdevice, defpart,
775                                       "/boot/System.map", &params->sysmap)) {
776                     prom_printf("%s: Unable to parse\n", imagepath);
777                     return 0;
778                }
779           }
780      }
781      return 0;
782 }
783
784 /* This is derived from quik core. To be changed to first parse the headers
785  * doing lazy-loading, and then claim the memory before loading the kernel
786  * to it
787  * We also need to add initrd support to this whole mecanism
788  */
789 void
790 yaboot_text_ui(void)
791 {
792 #define MAX_HEADERS     32
793
794      struct boot_file_t file;
795      int                        result;
796      static struct boot_param_t params;
797      void               *initrd_base;
798      unsigned long      initrd_size;
799      void                *sysmap_base;
800      unsigned long      sysmap_size;
801      kernel_entry_t      kernel_entry;
802      struct bi_record*  birec;
803      char*               loc=NULL;
804      loadinfo_t          loadinfo;
805      void                *initrd_more,*initrd_want;
806      unsigned long       initrd_read;
807     
808      loadinfo.load_loc = 0;
809
810      for (;;) {
811           initrd_size = 0;
812           initrd_base = 0;
813           sysmap_base = 0;
814           sysmap_size = 0;
815         
816           if (get_params(&params))
817                return;
818           if (!params.kernel.file)
819                continue;
820         
821           prom_printf("Please wait, loading kernel...\n");
822
823           memset(&file, 0, sizeof(file));
824
825           if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
826               && params.kernel.file[0] != '\\') {
827                loc=(char*)malloc(strlen(params.kernel.file)+3);
828                if (!loc) {
829                     prom_printf ("malloc error\n");
830                     goto next;
831                }
832                strcpy(loc,boot.file);
833                strcat(loc,params.kernel.file);
834                free(params.kernel.file);
835                params.kernel.file=loc;
836           }
837           result = open_file(&params.kernel, &file);
838           if (result != FILE_ERR_OK) {
839                prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
840                prom_perror(result, params.kernel.file);
841                goto next;
842           }
843
844           /* Read the Elf e_ident, e_type and e_machine fields to
845            * determine Elf file type
846            */
847           if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
848                prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
849                file.fs->close(&file);
850                memset(&file, 0, sizeof(file));
851                goto next;
852           }
853
854           if (is_elf32(&loadinfo)) {
855                if (!load_elf32(&file, &loadinfo)) {
856                     file.fs->close(&file);
857                     memset(&file, 0, sizeof(file));
858                     goto next;
859                }
860                prom_printf("   Elf32 kernel loaded...\n");
861           } else if (is_elf64(&loadinfo)) {
862                if (!load_elf64(&file, &loadinfo)) {
863                     file.fs->close(&file);
864                     memset(&file, 0, sizeof(file));
865                     goto next;
866                }
867                prom_printf("   Elf64 kernel loaded...\n");
868           } else {
869                prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
870                file.fs->close(&file);
871                memset(&file, 0, sizeof(file));
872                goto next;
873           }
874           file.fs->close(&file);
875           memset(&file, 0, sizeof(file));
876
877           /* If sysmap, load it (only if booting a vmlinux).
878            */
879           if (flat_vmlinux && params.sysmap.file) {
880                prom_printf("Loading System.map ...\n");
881                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
882                   && params.sysmap.file[0] != '\\') {
883                     if (loc) free(loc);
884                     loc=(char*)malloc(strlen(params.sysmap.file)+3);
885                     if (!loc) {
886                          prom_printf ("malloc error\n");
887                          goto next;
888                     }
889                     strcpy(loc,boot.file);
890                     strcat(loc,params.sysmap.file);
891                     free(params.sysmap.file);
892                     params.sysmap.file=loc;
893                }
894              
895                result = open_file(&params.sysmap, &file);
896                if (result != FILE_ERR_OK) {
897                     prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
898                     prom_perror(result, params.sysmap.file);
899                }
900                else {
901                     sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
902                     if (sysmap_base == (void *)-1) {
903                          prom_printf("Claim failed for sysmap memory\n");
904                          sysmap_base = 0;
905                     } else {
906                          sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
907                          if (sysmap_size == 0)
908                               sysmap_base = 0;
909                          else
910                               ((char *)sysmap_base)[sysmap_size++] = 0;
911                     }
912                     file.fs->close(&file);
913                     memset(&file, 0, sizeof(file));
914                }
915                if (sysmap_base) {
916                     prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
917                                 sysmap_base, sysmap_size >> 10);
918                     loadinfo.memsize += _ALIGN(0x100000, 0x1000);
919                } else {
920                     prom_printf("System.map load failed !\n");
921                     prom_pause();
922                }
923           }
924
925           /* If ramdisk, load it (only if booting a vmlinux).  For now, we
926            * can't tell the size it will be so we claim an arbitrary amount
927            * of 4Mb.
928            */
929           if (flat_vmlinux && params.rd.file) {
930                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
931                   && params.kernel.file[0] != '\\')
932                {
933                     if (loc) free(loc);
934                     loc=(char*)malloc(strlen(params.rd.file)+3);
935                     if (!loc) {
936                          prom_printf ("Malloc error\n");
937                          goto next;
938                     }
939                     strcpy(loc,boot.file);
940                     strcat(loc,params.rd.file);
941                     free(params.rd.file);
942                     params.rd.file=loc;
943                }
944                prom_printf("Loading ramdisk...\n");
945                result = open_file(&params.rd, &file);
946                if (result != FILE_ERR_OK) {
947                     prom_printf("%s:%d,", params.rd.dev, params.rd.part);
948                     prom_perror(result, params.rd.file);
949                }
950                else {
951 #define INITRD_CHUNKSIZE 0x400000
952                     initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
953                     if (initrd_base == (void *)-1) {
954                          prom_printf("Claim failed for initrd memory\n");
955                          initrd_base = 0;
956                     } else {
957                          initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
958                          if (initrd_size == 0)
959                               initrd_base = 0;
960                          initrd_read = initrd_size;
961                          initrd_more = initrd_base;
962                          while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
963                               initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
964                               initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
965                               if (initrd_more != initrd_want) {
966                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
967                                    break;
968                               }
969                               initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
970                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
971                               initrd_size += initrd_read;
972                          }
973                     }
974                     file.fs->close(&file);
975                     memset(&file, 0, sizeof(file));
976                }
977                if (initrd_base)
978                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
979                                 initrd_base, initrd_size >> 10);
980                else {
981                     prom_printf("ramdisk load failed !\n");
982                     prom_pause();
983                }
984           }
985
986           DEBUG_F("setting kernel args to: %s\n", params.args);
987           prom_setargs(params.args);
988           DEBUG_F("flushing icache...");
989           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
990           DEBUG_F(" done\n");
991
992           if (flat_vmlinux) {
993                /* 
994                 * Fill new boot infos (only if booting a vmlinux).
995                 *
996                 * The birec is low on memory, probably inside the malloc pool,
997                 * so we don't write it earlier. At this point, we should not
998                 * use anything coming from the malloc pool.
999                 */
1000                birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1001
1002                /* We make sure it's mapped. We map only 64k for now, it's
1003                 * plenty enough we don't claim since this precise memory
1004                 * range may already be claimed by the malloc pool.
1005                 */
1006                prom_map (birec, birec, 0x10000);
1007                DEBUG_F("birec at %p\n", birec);
1008                DEBUG_SLEEP;
1009
1010                birec->tag = BI_FIRST;
1011                birec->size = sizeof(struct bi_record);
1012                birec = (struct bi_record *)((ulong)birec + birec->size);
1013         
1014                birec->tag = BI_BOOTLOADER_ID;
1015                sprintf( (char *)birec->data, "yaboot");
1016                birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1017                birec = (struct bi_record *)((ulong)birec + birec->size);
1018         
1019                birec->tag = BI_MACHTYPE;
1020                birec->data[0] = _machine;
1021                birec->size = sizeof(struct bi_record) + sizeof(ulong);
1022                birec = (struct bi_record *)((ulong)birec + birec->size);
1023
1024                if (sysmap_base) {
1025                     birec->tag = BI_SYSMAP;
1026                     birec->data[0] = (ulong)sysmap_base;
1027                     birec->data[1] = sysmap_size;
1028                     birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1029                     birec = (struct bi_record *)((ulong)birec + birec->size);
1030                }
1031                birec->tag = BI_LAST;
1032                birec->size = sizeof(struct bi_record);
1033                birec = (struct bi_record *)((ulong)birec + birec->size);
1034           }
1035
1036           /* compute the kernel's entry point. */
1037           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1038
1039           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1040           DEBUG_F("kernel: arg1 = %p,\n"
1041                   "        arg2 = 0x%08lx,\n"
1042                   "        prom = %p,\n"
1043                   "        arg4 = %d,\n"
1044                   "        arg5 = %d\n\n",
1045                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1046
1047           DEBUG_F("Entering kernel...\n");
1048
1049           /* call the kernel with our stack. */
1050           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1051           continue;
1052      next:
1053           ; /* do nothing */
1054      }
1055 }
1056
1057 static int
1058 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1059 {
1060      int                        i;
1061      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1062      Elf32_Phdr         *p, *ph;
1063      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1064      unsigned long      addr, loadaddr;
1065
1066      /* Read the rest of the Elf header... */
1067      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1068           prom_printf("\nCan't read Elf32 image header\n");
1069           return 0;
1070      }
1071
1072      DEBUG_F("Elf32 header:\n");
1073      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1074      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1075      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1076      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1077      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1078      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1079      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1080      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1081      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1082      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1083
1084      loadinfo->entry = e->e_entry;
1085
1086      if (e->e_phnum > MAX_HEADERS) {
1087           prom_printf ("Can only load kernels with one program header\n");
1088           return 0;
1089      }
1090
1091      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1092      if (!ph) {
1093           prom_printf ("Malloc error\n");
1094           return 0;
1095      }
1096
1097      /* Now, we read the section header */
1098      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1099           prom_printf ("seek error\n");
1100           return 0;
1101      }
1102      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1103          sizeof(Elf32_Phdr) * e->e_phnum) {
1104           prom_printf ("read error\n");
1105           return 0;
1106      }
1107
1108      /* Scan through the program header
1109       * HACK:  We must return the _memory size of the kernel image, not the
1110       *        file size (because we have to leave room before other boot
1111       *   infos. This code works as a side effect of the fact that
1112       *   we have one section and vaddr == p_paddr
1113       */
1114      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1115      p = ph;
1116      for (i = 0; i < e->e_phnum; ++i, ++p) {
1117           if (p->p_type != PT_LOAD || p->p_offset == 0)
1118                continue;
1119           if (loadinfo->memsize == 0) {
1120                loadinfo->offset = p->p_offset;
1121                loadinfo->memsize = p->p_memsz;
1122                loadinfo->filesize = p->p_filesz;
1123                loadinfo->load_loc = p->p_vaddr;
1124           } else {
1125                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1126                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1127           }
1128      }
1129
1130      if (loadinfo->memsize == 0) {
1131           prom_printf("Can't find a loadable segment !\n");
1132           return 0;
1133      }
1134
1135      /* leave some room (1Mb) for boot infos */
1136      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1137      /* Claim OF memory */
1138      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1139
1140      /* Determine whether we are trying to boot a vmlinux or some
1141       * other binary image (eg, zImage).  We load vmlinux's at
1142       * KERNELADDR and all other binaries at their e_entry value.
1143       */
1144      if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1145           flat_vmlinux = 1;
1146           loadaddr = KERNELADDR;
1147      } else {
1148           flat_vmlinux = 0;
1149           loadaddr = e->e_entry;
1150      }
1151
1152      /* On some systems, loadaddr may already be claimed, so try some
1153       * other nearby addresses before giving up.
1154       */
1155      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1156           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1157           if (loadinfo->base != (void *)-1) break;
1158      }
1159      if (loadinfo->base == (void *)-1) {
1160           prom_printf("Claim error, can't allocate kernel memory\n");
1161           return 0;
1162      }  
1163
1164      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1165              loadinfo->base, loadinfo->memsize);
1166      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1167              loadaddr, loadinfo->memsize);
1168
1169      /* Load the program segments... */
1170      p = ph;
1171      for (i = 0; i < e->e_phnum; ++i, ++p) {
1172           unsigned long offset;
1173           if (p->p_type != PT_LOAD || p->p_offset == 0)
1174                continue;
1175
1176           /* Now, we skip to the image itself */
1177           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1178                prom_printf ("Seek error\n");
1179                prom_release(loadinfo->base, loadinfo->memsize);
1180                return 0;
1181           }
1182           offset = p->p_vaddr - loadinfo->load_loc;
1183           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1184                prom_printf ("Read failed\n");
1185                prom_release(loadinfo->base, loadinfo->memsize);
1186                return 0;
1187           }
1188      }
1189
1190      free(ph);
1191     
1192      /* Return success at loading the Elf32 kernel */
1193      return 1;
1194 }
1195
1196 static int
1197 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1198 {
1199      int                        i;
1200      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1201      Elf64_Phdr         *p, *ph;
1202      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1203      unsigned long      addr, loadaddr;
1204
1205      /* Read the rest of the Elf header... */
1206      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1207           prom_printf("\nCan't read Elf64 image header\n");
1208           return 0;
1209      }
1210
1211      DEBUG_F("Elf64 header:\n");
1212      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1213      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1214      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1215      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1216      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1217      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1218      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1219      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1220      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1221      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1222
1223      loadinfo->entry = e->e_entry;
1224
1225      if (e->e_phnum > MAX_HEADERS) {
1226           prom_printf ("Can only load kernels with one program header\n");
1227           return 0;
1228      }
1229
1230      ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1231      if (!ph) {
1232           prom_printf ("Malloc error\n");
1233           return 0;
1234      }
1235
1236      /* Now, we read the section header */
1237      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1238           prom_printf ("Seek error\n");
1239           return 0;
1240      }
1241      if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1242          sizeof(Elf64_Phdr) * e->e_phnum) {
1243           prom_printf ("Read error\n");
1244           return 0;
1245      }
1246
1247      /* Scan through the program header
1248       * HACK:  We must return the _memory size of the kernel image, not the
1249       *        file size (because we have to leave room before other boot
1250       *   infos. This code works as a side effect of the fact that
1251       *   we have one section and vaddr == p_paddr
1252       */
1253      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1254      p = ph;
1255      for (i = 0; i < e->e_phnum; ++i, ++p) {
1256           if (p->p_type != PT_LOAD || p->p_offset == 0)
1257                continue;
1258           if (loadinfo->memsize == 0) {
1259                loadinfo->offset = p->p_offset;
1260                loadinfo->memsize = p->p_memsz;
1261                loadinfo->filesize = p->p_filesz;
1262                loadinfo->load_loc = p->p_vaddr;
1263           } else {
1264                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1265                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1266           }
1267      }
1268
1269      if (loadinfo->memsize == 0) {
1270           prom_printf("Can't find a loadable segment !\n");
1271           return 0;
1272      }
1273
1274      /* leave some room (1Mb) for boot infos */
1275      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1276      /* Claim OF memory */
1277      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1278
1279      /* Determine whether we are trying to boot a vmlinux or some
1280       * other binary image (eg, zImage).  We load vmlinux's at
1281       * KERNELADDR and all other binaries at their e_entry value.
1282       */
1283      if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1284           flat_vmlinux = 1;
1285           loadaddr = KERNELADDR;
1286      } else {
1287           flat_vmlinux = 0;
1288           loadaddr = e->e_entry;
1289      }
1290
1291      /* On some systems, loadaddr may already be claimed, so try some
1292       * other nearby addresses before giving up.
1293       */
1294      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1295           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1296           if (loadinfo->base != (void *)-1) break;
1297      }
1298      if (loadinfo->base == (void *)-1) {
1299           prom_printf("Claim error, can't allocate kernel memory\n");
1300           return 0;
1301      }  
1302
1303      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1304              loadinfo->base, loadinfo->memsize);
1305      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1306              loadaddr, loadinfo->memsize);
1307
1308      /* Load the program segments... */
1309      p = ph;
1310      for (i = 0; i < e->e_phnum; ++i, ++p) {
1311           unsigned long offset;
1312           if (p->p_type != PT_LOAD || p->p_offset == 0)
1313                continue;
1314
1315           /* Now, we skip to the image itself */
1316           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1317                prom_printf ("Seek error\n");
1318                prom_release(loadinfo->base, loadinfo->memsize);
1319                return 0;
1320           }
1321           offset = p->p_vaddr - loadinfo->load_loc;
1322           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1323                prom_printf ("Read failed\n");
1324                prom_release(loadinfo->base, loadinfo->memsize);
1325                return 0;
1326           }
1327      }
1328
1329      free(ph);
1330     
1331      /* Return success at loading the Elf64 kernel */
1332      return 1;
1333 }
1334
1335 static int
1336 is_elf32(loadinfo_t *loadinfo)
1337 {
1338      Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1339
1340      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1341              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1342              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1343              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1344              e->e_ident[EI_CLASS] == ELFCLASS32  &&
1345              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1346              e->e_type            == ET_EXEC        &&
1347              e->e_machine         == EM_PPC);
1348 }
1349
1350 static int
1351 is_elf64(loadinfo_t *loadinfo)
1352 {
1353      Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1354
1355      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1356              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1357              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1358              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1359              e->e_ident[EI_CLASS] == ELFCLASS64  &&
1360              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1361              e->e_type            == ET_EXEC        &&
1362              e->e_machine         == EM_PPC64);
1363 }
1364
1365 static void
1366 setup_display(void)
1367 {
1368 #ifdef CONFIG_SET_COLORMAP
1369      static unsigned char default_colors[] = {
1370           0x00, 0x00, 0x00,
1371           0x00, 0x00, 0xaa,
1372           0x00, 0xaa, 0x00,
1373           0x00, 0xaa, 0xaa,
1374           0xaa, 0x00, 0x00,
1375           0xaa, 0x00, 0xaa,
1376           0xaa, 0x55, 0x00,
1377           0xaa, 0xaa, 0xaa,
1378           0x55, 0x55, 0x55,
1379           0x55, 0x55, 0xff,
1380           0x55, 0xff, 0x55,
1381           0x55, 0xff, 0xff,
1382           0xff, 0x55, 0x55,
1383           0xff, 0x55, 0xff,
1384           0xff, 0xff, 0x55,
1385           0xff, 0xff, 0xff
1386      };
1387      int i, result;
1388      prom_handle scrn = PROM_INVALID_HANDLE;
1389
1390      /* Try Apple's mac-boot screen ihandle */
1391      result = (int)call_prom_return("interpret", 1, 2,
1392                                     "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1393      DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1394
1395      if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1396           char type[32];
1397           /* Hrm... check to see if stdout is a display */
1398           scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1399           DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1400           if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1401                DEBUG_F("got it ! stdout is a screen\n");
1402                scrn = prom_stdout;
1403           } else {
1404                /* Else, we try to open the package */
1405                scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1406                DEBUG_F("Open screen result: %p\n", scrn);
1407           }
1408      }
1409         
1410      if (scrn == PROM_INVALID_HANDLE) {
1411           prom_printf("No screen device found !/n");
1412           return;
1413      }
1414      for(i=0;i<16;i++) {
1415           prom_set_color(scrn, i, default_colors[i*3],
1416                          default_colors[i*3+1], default_colors[i*3+2]);
1417      }
1418      prom_printf("\x1b[1;37m\x1b[2;40m");       
1419 #ifdef COLOR_TEST
1420      for (i=0;i<16; i++) {
1421           prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1422                       ansi_color_table[i].index,
1423                       ansi_color_table[i].value,
1424                       ansi_color_table[i].name,
1425                       ansi_color_table[i].name);
1426           prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1427                       ansi_color_table[i].index,
1428                       ansi_color_table[i].value+10,
1429                       ansi_color_table[i].name,
1430                       ansi_color_table[i].name);
1431      }
1432      prom_printf("\x1b[1;37m\x1b[2;40m");       
1433 #endif /* COLOR_TEST */
1434
1435 #if !DEBUG
1436      prom_printf("\xc");
1437 #endif /* !DEBUG */
1438
1439 #endif /* CONFIG_SET_COLORMAP */
1440 }
1441
1442 int
1443 yaboot_main(void)
1444 {
1445      char *ptype;
1446
1447      if (_machine == _MACH_Pmac)
1448           setup_display();
1449         
1450      prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1451      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1452      if (bootdevice[0] == 0) {
1453           prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1454           DEBUG_F("boot-device = %s\n", bootdevice);
1455      }
1456      if (bootdevice[0] == 0) {
1457           prom_printf("Couldn't determine boot device\n");
1458           return -1;
1459      }
1460
1461      if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1462           prom_printf("%s: Unable to parse\n", bootdevice);
1463           return -1;
1464      }
1465      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1466              boot.dev, boot.part, boot.file);
1467
1468      if (strlen(boot.file)) {
1469           if (!strncmp(boot.file, "\\\\", 2))
1470                boot.file = "\\\\";
1471           else {
1472                char *p, *last;
1473                p = last = boot.file;
1474                while(*p) {
1475                     if (*p == '\\')
1476                          last = p;
1477                     p++;
1478                }
1479                if (p)
1480                     *(last) = 0;
1481                else
1482                     boot.file = "";
1483                if (strlen(boot.file))
1484                     strcat(boot.file, "\\");
1485           }
1486      }
1487      DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1488              boot.dev, boot.part, boot.file);
1489
1490      useconf = load_config_file(boot.dev, boot.file, boot.part);
1491
1492      prom_printf("Welcome to yaboot version " VERSION "\n");
1493      prom_printf("Enter \"help\" to get some basic usage information\n");
1494
1495      /* I am fed up with lusers using the wrong partition type and
1496         mailing me *when* it breaks */
1497
1498      if (_machine == _MACH_Pmac) {
1499           char *entry = cfg_get_strg(0, "ptypewarning");
1500           int warn = 1;
1501           if (entry)
1502                warn = strcmp(entry,
1503                              "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1504           if (warn) {
1505                ptype = get_part_type(boot.dev, boot.part);
1506                if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1507                     prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1508                                 "         type should be: \"Apple_Bootstrap\"\n\n", ptype);
1509           }
1510      }
1511
1512      yaboot_text_ui();
1513         
1514      prom_printf("Bye.\n");
1515      return 0;
1516 }
1517
1518 /* 
1519  * Local variables:
1520  * c-file-style: "k&r"
1521  * c-basic-offset: 5
1522  * End:
1523  */