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