6b31cb0af0797fa7ef0c2b373da040b58b851c6b
[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[BOOTDEVSZ];
115 char bootoncelabel[1024];
116 char bootargs[1024];
117 char *password = NULL;
118 struct boot_fspec_t boot;
119 int _machine = _MACH_Pmac;
120 int flat_vmlinux;
121
122 #ifdef CONFIG_COLOR_TEXT
123
124 /* Color values for text ui */
125 static struct ansi_color_t {
126      char*      name;
127      int        index;
128      int        value;
129 } ansi_color_table[] = {
130      { "black",         2, 30 },
131      { "blue",          0, 31 },
132      { "green",         0, 32 },
133      { "cyan",          0, 33 },
134      { "red",           0, 34 },
135      { "purple",                0, 35 },
136      { "brown",         0, 36 },
137      { "light-gray",    0, 37 },
138      { "dark-gray",             1, 30 },
139      { "light-blue",            1, 31 },
140      { "light-green",   1, 32 },
141      { "light-cyan",            1, 33 },
142      { "light-red",             1, 34 },
143      { "light-purple",  1, 35 },
144      { "yellow",                1, 36 },
145      { "white",         1, 37 },
146      { NULL,                    0, 0 },
147 };
148
149 /* Default colors for text ui */
150 int fgcolor = 15;
151 int bgcolor = 0;
152 #endif /* CONFIG_COLOR_TEXT */
153
154 #if DEBUG
155 static int test_bss;
156 static int test_data = 0;
157 #endif
158 static int pause_after;
159 static char *pause_message = "Type go<return> to continue.\n";
160 static char given_bootargs[1024];
161 static int given_bootargs_by_user = 0;
162
163 extern unsigned char linux_logo_red[];
164 extern unsigned char linux_logo_green[];
165 extern unsigned char linux_logo_blue[];
166
167 #define DEFAULT_TIMEOUT         -1
168
169 /* Entry, currently called directly by crt0 (bss not inited) */
170
171 extern char* __bss_start;
172 extern char* _end;
173
174 static struct first_info *quik_fip = NULL;
175
176 int
177 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
178 {
179      int result;
180      void* malloc_base = NULL;
181      prom_handle root;
182
183      /* OF seems to do it, but I'm not very confident */
184      memset(&__bss_start, 0, &_end - &__bss_start);
185
186      /* Check for quik first stage bootloader (but I don't think we are
187       * compatible with it anyway, I'll look into backporting to older OF
188       * versions later
189       */
190      if (r5 == 0xdeadbeef) {
191           r5 = r3;
192           quik_fip = (struct first_info *)r4;
193      }
194
195      /* Initialize OF interface */
196      prom_init ((prom_entry) r5);
197
198      /* Allocate some memory for malloc'ator */
199      malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
200      if (malloc_base == (void *)-1) {
201           prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
202                       MALLOCSIZE, MALLOCADDR);
203           return -1;
204      }
205      malloc_init(malloc_base, MALLOCSIZE);
206      DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
207              malloc_base, MALLOCSIZE);
208
209      /* A few useless DEBUG_F's */
210      DEBUG_F("reloc_offset :  %ld         (should be 0)\n", reloc_offset());
211      DEBUG_F("test_bss     :  %d         (should be 0)\n", test_bss);
212      DEBUG_F("test_data    :  %d         (should be 0)\n", test_data);
213      DEBUG_F("&test_data   :  %p\n", &test_data);
214      DEBUG_F("&test_bss    :  %p\n", &test_bss);
215      DEBUG_F("linked at    :  0x%08x\n", TEXTADDR);
216
217      /* ask the OF info if we're a chrp or pmac */
218      /* we need to set _machine before calling finish_device_tree */
219      root = prom_finddevice("/");
220      if (root != 0) {
221           static char model[256];
222           if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
223               !strncmp("chrp", model, 4))
224                _machine = _MACH_chrp;
225           else {
226                if (prom_getprop(root, "model", model, 256 ) > 0 &&
227                    !strncmp(model, "IBM", 3))
228                     _machine = _MACH_chrp;
229           }
230      }
231
232      DEBUG_F("Running on _machine = %d\n", _machine);
233      DEBUG_SLEEP;
234
235      /* Call out main */
236      result = yaboot_main();
237
238      /* Get rid of malloc pool */
239      malloc_dispose();
240      prom_release(malloc_base, MALLOCSIZE);
241      DEBUG_F("Malloc buffer released. Exiting with code %d\n",
242              result);
243
244      /* Return to OF */
245      prom_exit();
246
247      return result;
248
249 }
250
251 #ifdef CONFIG_COLOR_TEXT
252 /*
253  * Validify color for text ui
254  */
255 static int
256 check_color_text_ui(char *color)
257 {
258      int i = 0;
259      while(ansi_color_table[i].name) {
260           if (!strcmp(color, ansi_color_table[i].name))
261                return i;
262           i++;
263      }
264      return -1;
265 }
266 #endif /* CONFIG_COLOR_TEXT */
267
268
269 void print_message_file(char *filename)
270 {
271      char *msg = NULL;
272      char *p, *endp;
273      char *defdev = boot.dev;
274      int defpart = boot.part;
275      char msgpath[1024];
276      int opened = 0;
277      int result = 0;
278      int n;
279      struct boot_file_t file;
280      struct boot_fspec_t msgfile;
281
282      defdev = cfg_get_strg(0, "device");
283      if (!defdev)
284           defdev = boot.dev;
285      p = cfg_get_strg(0, "partition");
286           if (p) {
287                n = simple_strtol(p, &endp, 10);
288                if (endp != p && *endp == 0)
289                     defpart = n;
290           }
291
292      strncpy(msgpath, filename, sizeof(msgpath));
293      if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
294           prom_printf("%s: Unable to parse\n", msgpath);
295           goto done;
296      }
297
298      result = open_file(&msgfile, &file);
299      if (result != FILE_ERR_OK) {
300           prom_printf("%s:%d,", msgfile.dev, msgfile.part);
301           prom_perror(result, msgfile.file);
302           goto done;
303      } else
304           opened = 1;
305
306      msg = malloc(2001);
307      if (!msg)
308           goto done;
309      else
310           memset(msg, 0, 2001);
311
312      if (file.fs->read(&file, 2000, msg) <= 0)
313           goto done;
314      else
315           prom_printf("%s", msg);
316
317 done:
318      if (opened)
319           file.fs->close(&file);
320      if (msg)
321           free(msg);
322 }
323
324 /* Currently, the config file must be at the root of the filesystem.
325  * todo: recognize the full path to myself and use it to load the
326  * config file. Handle the "\\" (blessed system folder)
327  */
328 static int
329 load_config_file(struct boot_fspec_t *fspec)
330 {
331      char *conf_file = NULL, *p;
332      struct boot_file_t file;
333      int sz, opened = 0, result = 0;
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      /* Open it */
343      result = open_file(fspec, &file);
344      if (result != FILE_ERR_OK) {
345           prom_printf("%s:%d,", fspec->dev, fspec->part);
346           prom_perror(result, fspec->file);
347           prom_printf("Can't open config file\n");
348           goto bail;
349      }
350      opened = 1;
351
352      /* Read it */
353      sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
354      if (sz <= 0) {
355           prom_printf("Error, can't read config file\n");
356           goto bail;
357      }
358      prom_printf("Config file read, %d bytes\n", sz);
359
360      /* Close the file */
361      if (opened)
362           file.fs->close(&file);
363      opened = 0;
364
365      /* Call the parsing code in cfg.c */
366      if (cfg_parse(fspec->file, conf_file, sz) < 0) {
367           prom_printf ("Syntax error or read error config\n");
368           goto bail;
369      }
370
371      /* 
372       * set the default cf_option to label that has the same MAC addr 
373       * it only works if there is a label with the MAC addr on yaboot.conf
374       */
375      if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
376          /* change the variable bellow to get the MAC dinamicaly */
377          char * macaddr = NULL;
378          int default_mac = 0;
379
380          macaddr = prom_get_mac(prom_get_netinfo());
381          default_mac = cfg_set_default_by_mac(macaddr);
382          if (default_mac >= 1) {
383             prom_printf("Default label was changed to macaddr label.\n");
384          }
385      }
386
387      DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
388
389      /* Now, we do the initialisations stored in the config file */
390      p = cfg_get_strg(0, "init-code");
391      if (p)
392           prom_interpret(p);
393
394      password = cfg_get_strg(0, "password");
395
396 #ifdef CONFIG_COLOR_TEXT
397      p = cfg_get_strg(0, "fgcolor");
398      if (p) {
399           DEBUG_F("fgcolor=%s\n", p);
400           fgcolor = check_color_text_ui(p);
401           if (fgcolor == -1) {
402                prom_printf("Invalid fgcolor: \"%s\".\n", p);
403           }
404      }
405      p = cfg_get_strg(0, "bgcolor");
406      if (p) {
407           DEBUG_F("bgcolor=%s\n", p);
408           bgcolor = check_color_text_ui(p);
409           if (bgcolor == -1)
410                prom_printf("Invalid bgcolor: \"%s\".\n", p);
411      }
412      if (bgcolor >= 0) {
413           char temp[64];
414           sprintf(temp, "%x to background-color", bgcolor);
415           prom_interpret(temp);
416 #if !DEBUG
417           prom_printf("\xc");
418 #endif /* !DEBUG */
419      }
420      if (fgcolor >= 0) {
421           char temp[64];
422           sprintf(temp, "%x to foreground-color", fgcolor);
423           prom_interpret(temp);
424      }
425 #endif /* CONFIG_COLOR_TEXT */
426
427      p = cfg_get_strg(0, "init-message");
428      if (p)
429           prom_printf("%s\n", p);
430
431      p = cfg_get_strg(0, "message");
432      if (p)
433           print_message_file(p);
434
435      result = 1;
436
437 bail:
438
439      if (opened)
440           file.fs->close(&file);
441
442      if (conf_file)
443           free(conf_file);
444
445      return result;
446 }
447
448 /*
449  * Search for config file by MAC address, then by IP address.
450  * Basically copying pxelinux's algorithm.
451  * http://syslinux.zytor.com/pxe.php#config
452  */
453 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
454 {
455      struct bootp_packet *packet;
456      int rc = 0;
457      struct boot_fspec_t fspec = *orig_fspec;
458 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
459
460      packet = prom_get_netinfo();
461
462      /*
463       * First, try to match on mac address with the hardware type
464       * prepended.
465       */
466
467      /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
468      fspec.file = malloc(packet->hlen * 3 + 2 + 6);
469      if (!fspec.file)
470           goto out;
471
472      if (_machine == _MACH_chrp)
473          sprintf(fspec.file, "/etc/%02x-", packet->htype);
474      else
475          sprintf(fspec.file, "%02x-", packet->htype);
476      strcat(fspec.file, prom_get_mac(packet));
477
478      rc = load_config_file(&fspec);
479      if (rc)
480           goto out;
481
482
483      /*
484       * Now try to match on IP.
485       */
486      free(fspec.file);
487      /* 8 chars in yiaddr + \0 */
488      fspec.file = malloc(9);
489      if (!fspec.file)
490          goto out;
491
492      strcpy(fspec.file, "/etc/");
493      strcat(fspec.file, prom_get_ip(packet));
494
495      while (strlen(strrchr(fspec.file, '/')+1)) {
496           rc = load_config_file(&fspec);
497           if (rc)
498                goto out;
499           /* Chop one digit off the end, try again */
500           fspec.file[strlen(fspec.file) - 1] = '\0';
501      }
502
503  out:
504      if (rc) /* modify original only on success */
505           orig_fspec->file = fspec.file;
506      else
507           free(fspec.file);
508      return rc;
509 }
510
511 void maintabfunc (void)
512 {
513      if (useconf) {
514           cfg_print_images();
515           prom_printf("boot: %s", cbuff);
516      }
517 }
518
519 void
520 word_split(char **linep, char **paramsp)
521 {
522      char *p;
523
524      *paramsp = 0;
525      p = *linep;
526      if (p == 0)
527           return;
528      while (*p == ' ')
529           ++p;
530      if (*p == 0) {
531           *linep = 0;
532           return;
533      }
534      *linep = p;
535      while (*p != 0 && *p != ' ')
536           ++p;
537      while (*p == ' ')
538           *p++ = 0;
539      if (*p != 0)
540           *paramsp = p;
541 }
542
543 char *
544 make_params(char *label, char *params)
545 {
546      char *p, *q;
547      static char buffer[2048];
548
549      q = buffer;
550      *q = 0;
551
552      p = cfg_get_strg(label, "literal");
553      if (p) {
554           strcpy(q, p);
555           q = strchr(q, 0);
556           if (params) {
557                if (*p)
558                     *q++ = ' ';
559                strcpy(q, params);
560           }
561           return buffer;
562      }
563
564      p = cfg_get_strg(label, "root");
565      if (p) {
566           strcpy (q, "root=");
567           strcpy (q + 5, p);
568           q = strchr (q, 0);
569           *q++ = ' ';
570      }
571      if (cfg_get_flag(label, "read-only")) {
572           strcpy (q, "ro ");
573           q += 3;
574      }
575      if (cfg_get_flag(label, "read-write")) {
576           strcpy (q, "rw ");
577           q += 3;
578      }
579      p = cfg_get_strg(label, "ramdisk");
580      if (p) {
581           strcpy (q, "ramdisk=");
582           strcpy (q + 8, p);
583           q = strchr (q, 0);
584           *q++ = ' ';
585      }
586      p = cfg_get_strg(label, "initrd-size");
587      if (p) {
588           strcpy (q, "ramdisk_size=");
589           strcpy (q + 13, p);
590           q = strchr (q, 0);
591           *q++ = ' ';
592      }
593      if (cfg_get_flag(label, "novideo")) {
594           strcpy (q, "video=ofonly");
595           q = strchr (q, 0);
596           *q++ = ' ';
597      }
598      p = cfg_get_strg (label, "append");
599      if (p) {
600           strcpy (q, p);
601           q = strchr (q, 0);
602           *q++ = ' ';
603      }
604      *q = 0;
605      pause_after = cfg_get_flag (label, "pause-after");
606      p = cfg_get_strg(label, "pause-message");
607      if (p)
608           pause_message = p;
609      if (params)
610           strcpy(q, params);
611
612      return buffer;
613 }
614
615 void check_password(char *str)
616 {
617      int i;
618
619      prom_printf("\n%s", str);
620      for (i = 0; i < 3; i++) {
621           prom_printf ("\nPassword: ");
622           passwdbuff[0] = 0;
623           cmdedit ((void (*)(void)) 0, 1);
624           prom_printf ("\n");
625 #ifdef USE_MD5_PASSWORDS
626           if (!strncmp (password, "$1$", 3)) {
627                if (!check_md5_password(passwdbuff, password))
628                     return;
629           }
630           else if (!strcmp (password, passwdbuff))
631                return;
632 #else /* !MD5 */
633           if (!strcmp (password, passwdbuff))
634                return;
635 #endif /* USE_MD5_PASSWORDS */
636           if (i < 2) {
637                prom_sleep(1);
638                prom_printf ("Incorrect password.  Try again.");
639           }
640      }
641      prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
642                  "        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n"
643                  "                ||----w |\n                ||     ||\n");
644      prom_sleep(4);
645      prom_interpret("reset-all");
646 }
647
648 int get_params(struct boot_param_t* params)
649 {
650      int defpart;
651      char *defdevice = 0;
652      char defdevice_bak[1024];
653      char *p, *q, *endp;
654      int c, n;
655      char *imagename = 0, *label;
656      int timeout = -1;
657      int beg = 0, end;
658      int singlekey = 0;
659      int restricted = 0;
660      static int first = 1;
661      static char imagepath[1024];
662      static char initrdpath[1024];
663      static char sysmappath[1024];
664
665      pause_after = 0;
666      memset(params, 0, sizeof(*params));
667      params->args = "";
668      params->kernel.part = -1;
669      params->rd.part = -1;
670      params->sysmap.part = -1;
671      defpart = boot.part;
672
673      cmdinit();
674
675      if (first) {
676           first = 0;
677           imagename = bootargs;
678           word_split(&imagename, &params->args);
679           timeout = DEFAULT_TIMEOUT;
680           if (imagename) {
681                prom_printf("Default supplied on the command line: %s ", imagename);
682                if (params->args)
683                     prom_printf("%s", params->args);
684                prom_printf("\n");
685           }
686           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
687                timeout = simple_strtol(q, NULL, 0);
688      }
689
690      prom_printf("boot: ");
691      c = -1;
692      if (timeout != -1) {
693           beg = prom_getms();
694           if (timeout > 0) {
695                end = beg + 100 * timeout;
696                do {
697                     c = prom_nbgetchar();
698                } while (c == -1 && prom_getms() <= end);
699           }
700           if (c == -1)
701                c = '\n';
702           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
703                cbuff[0] = c;
704                cbuff[1] = 0;
705           }
706      }
707
708      if (c != -1 && c != '\n' && c != '\r') {
709           if (c == '\t') {
710                maintabfunc ();
711           }  else if (c >= ' ') {
712                cbuff[0] = c;
713                cbuff[1] = 0;
714                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
715                     imagename = cbuff;
716                     singlekey = 1;
717                     prom_printf("%s\n", cbuff);
718                }
719           }
720      }
721
722      if (c == '\n' || c == '\r') {
723           if (!imagename) {
724                if (bootoncelabel[0] != 0)
725                     imagename = bootoncelabel;
726                else
727                     imagename = cfg_get_default();
728           }
729           if (imagename)
730                prom_printf("%s", imagename);
731           if (params->args)
732                prom_printf(" %s", params->args);
733           prom_printf("\n");
734      } else if (!singlekey) {
735           cmdedit(maintabfunc, 0);
736           prom_printf("\n");
737           strcpy(given_bootargs, cbuff);
738           given_bootargs_by_user = 1;
739           imagename = cbuff;
740           word_split(&imagename, &params->args);
741      }
742
743      /* chrp gets this wrong, force it -- Cort */
744      if ( useconf && (!imagename || imagename[0] == 0 ))
745           imagename = cfg_get_default();
746
747      label = 0;
748      defdevice = boot.dev;
749
750      strcpy(defdevice_bak,defdevice);
751
752      if (useconf) {
753           defdevice = cfg_get_strg(0, "device");
754           p = cfg_get_strg(0, "partition");
755           if (p) {
756                n = simple_strtol(p, &endp, 10);
757                if (endp != p && *endp == 0)
758                     defpart = n;
759           }
760           p = cfg_get_strg(0, "pause-message");
761           if (p)
762                pause_message = p;
763           if (cfg_get_flag(0, "restricted"))
764                restricted = 1;
765           p = cfg_get_strg(imagename, "image");
766           if (p && *p) {
767                label = imagename;
768                imagename = p;
769                defdevice = cfg_get_strg(label, "device");
770                if(!defdevice) defdevice=boot.dev;
771                p = cfg_get_strg(label, "partition");
772                if (p) {
773                     n = simple_strtol(p, &endp, 10);
774                     if (endp != p && *endp == 0)
775                          defpart = n;
776                }
777                if (cfg_get_flag(label, "restricted"))
778                     restricted = 1;
779                if (label) {
780                     if (params->args && password && restricted)
781                          check_password ("To specify arguments for this image "
782                                          "you must enter the password.");
783                     else if (password && !restricted)
784                          check_password ("This image is restricted.");
785                }
786                params->args = make_params(label, params->args);
787           }
788      }
789
790      if (!strcmp (imagename, "help")) {
791           /* FIXME: defdevice shouldn't need to be reset all over the place */
792           if(!defdevice) defdevice = boot.dev;
793           prom_printf(
794                "\nPress the tab key for a list of defined images.\n"
795                "The label marked with a \"*\" is is the default image, "
796                "press <return> to boot it.\n\n"
797                "To boot any other label simply type its name and press <return>.\n\n"
798                "To boot a kernel image which is not defined in the yaboot configuration \n"
799                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
800                "\"device:\" is the OpenFirmware device path to the disk the image \n"
801                "resides on, and \"partno\" is the partition number the image resides on.\n"
802                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
803                "device, if you only specify a filename you should not start it with a \",\"\n\n"
804                "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
805                "its device, partno and path, on Open Firmware Prompt:\n"
806                "boot conf=device:partno,/path/to/configfile\n."
807                "To reload the config file or load a new one, use the \"conf\" command\n"
808                "on Yaboot's prompt:\n"
809                "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
810                "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
811                "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
812
813           return 0;
814      }
815
816      if (!strcmp (imagename, "halt")) {
817           if (password)
818                check_password ("Restricted command.");
819           prom_pause();
820           return 0;
821      }
822      if (!strcmp (imagename, "bye")) {
823           if (password) {
824                check_password ("Restricted command.");
825                return 1;
826           }
827           return 1;
828      }
829
830      if (!strncmp (imagename, "conf", 4)) {
831
832          // imagename = "conf file=blah dev=bleh part=blih"
833          DEBUG_F("Loading user-specified config file: %s\n",imagename);
834          if (password) {
835              check_password ("Restricted command.");
836              return 1;
837          }
838
839          // args= "file=blah dev=bleh part=blih"
840          char *args = params->args;
841
842          if (strlen(args)){
843
844             // set a pointer to the first space in args
845             char *space = strchr(args,' ');
846
847             int loop = 3;
848             while (loop > 0){
849                 char temp[1024] = "0";
850
851                 // copy next argument to temp
852                 strncpy(temp, args, space-args);
853
854                 // parse temp and set boot arguments
855                 if (!strncmp (temp, "file=", 5)){
856                    DEBUG_F("conf file: %s\n", temp+5);
857                    strcpy(boot.file, temp+5);
858                 } else if (!strncmp (temp, "device=", 7)){
859                    DEBUG_F("conf device: %s\n", temp+7);
860                    strcpy(boot.dev, temp+7);
861                 } else if (!strncmp (temp, "partition=", 10)){
862                    DEBUG_F("conf partition: %s\n", temp+10);
863                    boot.part=simple_strtol(temp+10,NULL,10);
864                 } else
865                    space = NULL;
866
867                 // set the pointer to the next space in args;
868                 // set the loop control variable
869                 if (strlen(space)>1){
870                     // Go to the next argument
871                     args = space+1;
872
873                     loop--;
874                     if (strchr(args,' ') == NULL)
875                         space = &args[strlen(args)];
876                     else
877                         space = strchr(args,' ');
878                 } else {
879                     loop = -1;
880                     space = NULL;
881                 }
882             }
883
884             prom_printf("Loading config file...\n");
885             useconf = load_config_file(&boot);
886             if (useconf > 0){
887                 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
888                    timeout = simple_strtol(q, NULL, 0);
889             } else {
890                prom_printf("Restoring default values.\n");
891                strcpy(boot.file,"");
892                strcpy(boot.dev, defdevice_bak);
893                boot.part = defpart;
894             }
895
896          } else {
897              prom_printf("Current configuration:\n");
898              prom_printf("device: %s\n", boot.dev);
899              if (boot.part < 0)
900                  prom_printf("partition: auto\n");
901              else
902                  prom_printf("partition: %d\n", boot.part);
903              if (strlen(boot.file))
904                  prom_printf("file: %s\n", boot.file);
905              else
906                  prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
907          }
908
909          imagename = "\0";
910          params->args = "\0";
911
912          return 0;
913      }
914
915      if (imagename[0] == '$') {
916           /* forth command string */
917           if (password)
918                check_password ("OpenFirmware commands are restricted.");
919           prom_interpret(imagename+1);
920           return 0;
921      }
922
923      strncpy(imagepath, imagename, 1024);
924
925      if (!label && password)
926           check_password ("To boot a custom image you must enter the password.");
927
928      if (!parse_device_path(imagepath, defdevice, defpart,
929                             "/vmlinux", &params->kernel)) {
930           prom_printf("%s: Unable to parse\n", imagepath);
931           return 0;
932      }
933      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
934              params->kernel.part, params->kernel.file);
935
936      if (useconf) {
937           p = cfg_get_strg(label, "initrd");
938           if (p && *p) {
939                DEBUG_F("Parsing initrd path <%s>\n", p);
940                strncpy(initrdpath, p, 1024);
941                if (!parse_device_path(initrdpath, defdevice, defpart,
942                                       "/root.bin", &params->rd)) {
943                     prom_printf("%s: Unable to parse\n", imagepath);
944                     return 0;
945                }
946           }
947           p = cfg_get_strg(label, "sysmap");
948           if (p && *p) {
949                DEBUG_F("Parsing sysmap path <%s>\n", p);
950                strncpy(sysmappath, p, 1024);
951                if (!parse_device_path(sysmappath, defdevice, defpart,
952                                       "/boot/System.map", &params->sysmap)) {
953                     prom_printf("%s: Unable to parse\n", imagepath);
954                     return 0;
955                }
956           }
957      }
958      return 0;
959 }
960
961 /* This is derived from quik core. To be changed to first parse the headers
962  * doing lazy-loading, and then claim the memory before loading the kernel
963  * to it
964  * We also need to add initrd support to this whole mecanism
965  */
966 void
967 yaboot_text_ui(void)
968 {
969 #define MAX_HEADERS     32
970
971      struct boot_file_t file;
972      int                        result;
973      static struct boot_param_t params;
974      void               *initrd_base;
975      unsigned long      initrd_size;
976      void                *sysmap_base;
977      unsigned long      sysmap_size;
978      kernel_entry_t      kernel_entry;
979      struct bi_record*  birec;
980      char*               loc=NULL;
981      loadinfo_t          loadinfo;
982      void                *initrd_more,*initrd_want;
983      unsigned long       initrd_read;
984
985      loadinfo.load_loc = 0;
986
987      for (;;) {
988           initrd_size = 0;
989           initrd_base = 0;
990           sysmap_base = 0;
991           sysmap_size = 0;
992
993           if (get_params(&params))
994                return;
995           if (!params.kernel.file)
996                continue;
997
998           prom_printf("Please wait, loading kernel...\n");
999
1000           memset(&file, 0, sizeof(file));
1001
1002           if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1003               && params.kernel.file[0] != '\\') {
1004                loc=(char*)malloc(strlen(params.kernel.file)+3);
1005                if (!loc) {
1006                     prom_printf ("malloc error\n");
1007                     goto next;
1008                }
1009                strcpy(loc,boot.file);
1010                strcat(loc,params.kernel.file);
1011                free(params.kernel.file);
1012                params.kernel.file=loc;
1013           }
1014           result = open_file(&params.kernel, &file);
1015           if (result != FILE_ERR_OK) {
1016                prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1017                prom_perror(result, params.kernel.file);
1018                goto next;
1019           }
1020
1021           /* Read the Elf e_ident, e_type and e_machine fields to
1022            * determine Elf file type
1023            */
1024           if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1025                prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1026                file.fs->close(&file);
1027                memset(&file, 0, sizeof(file));
1028                goto next;
1029           }
1030
1031           if (is_elf32(&loadinfo)) {
1032                if (!load_elf32(&file, &loadinfo)) {
1033                     file.fs->close(&file);
1034                     memset(&file, 0, sizeof(file));
1035                     goto next;
1036                }
1037                prom_printf("   Elf32 kernel loaded...\n");
1038           } else if (is_elf64(&loadinfo)) {
1039                if (!load_elf64(&file, &loadinfo)) {
1040                     file.fs->close(&file);
1041                     memset(&file, 0, sizeof(file));
1042                     goto next;
1043                }
1044                prom_printf("   Elf64 kernel loaded...\n");
1045           } else {
1046                prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1047                file.fs->close(&file);
1048                memset(&file, 0, sizeof(file));
1049                goto next;
1050           }
1051           file.fs->close(&file);
1052           memset(&file, 0, sizeof(file));
1053
1054           /* If sysmap, load it (only if booting a vmlinux).
1055            */
1056           if (flat_vmlinux && params.sysmap.file) {
1057                prom_printf("Loading System.map ...\n");
1058                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1059                   && params.sysmap.file[0] != '\\') {
1060                     if (loc) free(loc);
1061                     loc=(char*)malloc(strlen(params.sysmap.file)+3);
1062                     if (!loc) {
1063                          prom_printf ("malloc error\n");
1064                          goto next;
1065                     }
1066                     strcpy(loc,boot.file);
1067                     strcat(loc,params.sysmap.file);
1068                     free(params.sysmap.file);
1069                     params.sysmap.file=loc;
1070                }
1071
1072                result = open_file(&params.sysmap, &file);
1073                if (result != FILE_ERR_OK) {
1074                     prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1075                     prom_perror(result, params.sysmap.file);
1076                }
1077                else {
1078                     sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1079                     if (sysmap_base == (void *)-1) {
1080                          prom_printf("Claim failed for sysmap memory\n");
1081                          prom_pause();
1082                          sysmap_base = 0;
1083                     } else {
1084                          sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1085                          if (sysmap_size == 0)
1086                               sysmap_base = 0;
1087                          else
1088                               ((char *)sysmap_base)[sysmap_size++] = 0;
1089                     }
1090                     file.fs->close(&file);
1091                     memset(&file, 0, sizeof(file));
1092                }
1093                if (sysmap_base) {
1094                     prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1095                                 sysmap_base, sysmap_size >> 10);
1096                     loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1097                } else {
1098                     prom_printf("System.map load failed !\n");
1099                     prom_pause();
1100                }
1101           }
1102
1103           /* If ramdisk, load it (only if booting a vmlinux).  For now, we
1104            * can't tell the size it will be so we claim an arbitrary amount
1105            * of 4Mb.
1106            */
1107           if (flat_vmlinux && params.rd.file) {
1108                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1109                   && params.kernel.file[0] != '\\')
1110                {
1111                     if (loc) free(loc);
1112                     loc=(char*)malloc(strlen(params.rd.file)+3);
1113                     if (!loc) {
1114                          prom_printf ("Malloc error\n");
1115                          goto next;
1116                     }
1117                     strcpy(loc,boot.file);
1118                     strcat(loc,params.rd.file);
1119                     free(params.rd.file);
1120                     params.rd.file=loc;
1121                }
1122                prom_printf("Loading ramdisk...\n");
1123                result = open_file(&params.rd, &file);
1124                if (result != FILE_ERR_OK) {
1125                     prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1126                     prom_perror(result, params.rd.file);
1127                }
1128                else {
1129 #define INITRD_CHUNKSIZE 0x100000
1130                     initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1131                     if (initrd_base == (void *)-1) {
1132                          prom_printf("Claim failed for initrd memory\n");
1133                          initrd_base = 0;
1134                     } else {
1135                          initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1136                          if (initrd_size == 0)
1137                               initrd_base = 0;
1138                          initrd_read = initrd_size;
1139                          initrd_more = initrd_base;
1140                          while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1141                               initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1142                               initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1143                               if (initrd_more != initrd_want) {
1144                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1145                                    prom_pause();
1146                                    break;
1147                               }
1148                               initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1149                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
1150                               initrd_size += initrd_read;
1151                          }
1152                     }
1153                     file.fs->close(&file);
1154                     memset(&file, 0, sizeof(file));
1155                }
1156                if (initrd_base)
1157                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1158                                 initrd_base, initrd_size >> 10);
1159                else {
1160                     prom_printf("ramdisk load failed !\n");
1161                     prom_pause();
1162                }
1163           }
1164
1165           DEBUG_F("setting kernel args to: %s\n", params.args);
1166           prom_setargs(params.args);
1167           DEBUG_F("flushing icache...");
1168           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1169           DEBUG_F(" done\n");
1170
1171           if (flat_vmlinux) {
1172                /*
1173                 * Fill new boot infos (only if booting a vmlinux).
1174                 *
1175                 * The birec is low on memory, probably inside the malloc pool,
1176                 * so we don't write it earlier. At this point, we should not
1177                 * use anything coming from the malloc pool.
1178                 */
1179                birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1180
1181                /* We make sure it's mapped. We map only 64k for now, it's
1182                 * plenty enough we don't claim since this precise memory
1183                 * range may already be claimed by the malloc pool.
1184                 */
1185                prom_map (birec, birec, 0x10000);
1186                DEBUG_F("birec at %p\n", birec);
1187                DEBUG_SLEEP;
1188
1189                birec->tag = BI_FIRST;
1190                birec->size = sizeof(struct bi_record);
1191                birec = (struct bi_record *)((ulong)birec + birec->size);
1192
1193                birec->tag = BI_BOOTLOADER_ID;
1194                sprintf( (char *)birec->data, "yaboot");
1195                birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1196                birec = (struct bi_record *)((ulong)birec + birec->size);
1197
1198                birec->tag = BI_MACHTYPE;
1199                birec->data[0] = _machine;
1200                birec->size = sizeof(struct bi_record) + sizeof(ulong);
1201                birec = (struct bi_record *)((ulong)birec + birec->size);
1202
1203                if (sysmap_base) {
1204                     birec->tag = BI_SYSMAP;
1205                     birec->data[0] = (ulong)sysmap_base;
1206                     birec->data[1] = sysmap_size;
1207                     birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1208                     birec = (struct bi_record *)((ulong)birec + birec->size);
1209                }
1210                birec->tag = BI_LAST;
1211                birec->size = sizeof(struct bi_record);
1212                birec = (struct bi_record *)((ulong)birec + birec->size);
1213           }
1214
1215           /* compute the kernel's entry point. */
1216           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1217
1218           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1219           DEBUG_F("kernel: arg1 = %p,\n"
1220                   "        arg2 = 0x%08lx,\n"
1221                   "        prom = %p,\n"
1222                   "        arg4 = %d,\n"
1223                   "        arg5 = %d\n\n",
1224                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1225
1226           DEBUG_F("Entering kernel...\n");
1227
1228           /* call the kernel with our stack. */
1229           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1230           continue;
1231      next:
1232           ; /* do nothing */
1233      }
1234 }
1235
1236 static int
1237 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1238 {
1239      int                        i;
1240      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1241      Elf32_Phdr         *p, *ph;
1242      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1243      unsigned long      addr, loadaddr;
1244
1245      /* Read the rest of the Elf header... */
1246      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1247           prom_printf("\nCan't read Elf32 image header\n");
1248           goto bail;
1249      }
1250
1251      DEBUG_F("Elf32 header:\n");
1252      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1253      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1254      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1255      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1256      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1257      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1258      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1259      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1260      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1261      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1262
1263      loadinfo->entry = e->e_entry;
1264
1265      if (e->e_phnum > MAX_HEADERS) {
1266           prom_printf ("Can only load kernels with one program header\n");
1267           goto bail;
1268      }
1269
1270      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1271      if (!ph) {
1272           prom_printf ("Malloc error\n");
1273           goto bail;
1274      }
1275
1276      /* Now, we read the section header */
1277      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1278           prom_printf ("seek error\n");
1279           goto bail;
1280      }
1281      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1282          sizeof(Elf32_Phdr) * e->e_phnum) {
1283           prom_printf ("read error\n");
1284           goto bail;
1285      }
1286
1287      /* Scan through the program header
1288       * HACK:  We must return the _memory size of the kernel image, not the
1289       *        file size (because we have to leave room before other boot
1290       *   infos. This code works as a side effect of the fact that
1291       *   we have one section and vaddr == p_paddr
1292       */
1293      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1294      p = ph;
1295      for (i = 0; i < e->e_phnum; ++i, ++p) {
1296           if (p->p_type != PT_LOAD || p->p_offset == 0)
1297                continue;
1298           if (loadinfo->memsize == 0) {
1299                loadinfo->offset = p->p_offset;
1300                loadinfo->memsize = p->p_memsz;
1301                loadinfo->filesize = p->p_filesz;
1302                loadinfo->load_loc = p->p_vaddr;
1303           } else {
1304                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1305                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1306           }
1307      }
1308
1309      if (loadinfo->memsize == 0) {
1310           prom_printf("Can't find a loadable segment !\n");
1311           goto bail;
1312      }
1313
1314      /* leave some room (1Mb) for boot infos */
1315      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1316      /* Claim OF memory */
1317      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1318
1319      /* Determine whether we are trying to boot a vmlinux or some
1320       * other binary image (eg, zImage).  We load vmlinux's at
1321       * KERNELADDR and all other binaries at their e_entry value.
1322       */
1323      if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1324           flat_vmlinux = 1;
1325           loadaddr = KERNELADDR;
1326      } else {
1327           flat_vmlinux = 0;
1328           loadaddr = loadinfo->load_loc;
1329      }
1330
1331      /* On some systems, loadaddr may already be claimed, so try some
1332       * other nearby addresses before giving up.
1333       */
1334      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1335           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1336           if (loadinfo->base != (void *)-1) break;
1337      }
1338      if (loadinfo->base == (void *)-1) {
1339           prom_printf("Claim error, can't allocate kernel memory\n");
1340           goto bail;
1341      }
1342
1343      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1344              loadinfo->base, loadinfo->memsize);
1345      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1346              loadaddr, loadinfo->memsize);
1347
1348      /* Load the program segments... */
1349      p = ph;
1350      for (i = 0; i < e->e_phnum; ++i, ++p) {
1351           unsigned long offset;
1352           if (p->p_type != PT_LOAD || p->p_offset == 0)
1353                continue;
1354
1355           /* Now, we skip to the image itself */
1356           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1357                prom_printf ("Seek error\n");
1358                prom_release(loadinfo->base, loadinfo->memsize);
1359                goto bail;
1360           }
1361           offset = p->p_vaddr - loadinfo->load_loc;
1362           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1363                prom_printf ("Read failed\n");
1364                prom_release(loadinfo->base, loadinfo->memsize);
1365                goto bail;
1366           }
1367      }
1368
1369      free(ph);
1370
1371      /* Return success at loading the Elf32 kernel */
1372      return 1;
1373
1374 bail:
1375      if (ph)
1376        free(ph);
1377      return 0;
1378 }
1379
1380 static int
1381 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1382 {
1383      int                        i;
1384      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1385      Elf64_Phdr         *p, *ph;
1386      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1387      unsigned long      addr, loadaddr;
1388
1389      /* Read the rest of the Elf header... */
1390      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1391           prom_printf("\nCan't read Elf64 image header\n");
1392           goto bail;
1393      }
1394
1395      DEBUG_F("Elf64 header:\n");
1396      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1397      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1398      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1399      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1400      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1401      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1402      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1403      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1404      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1405      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1406
1407      loadinfo->entry = e->e_entry;
1408
1409      if (e->e_phnum > MAX_HEADERS) {
1410           prom_printf ("Can only load kernels with one program header\n");
1411           goto bail;
1412      }
1413
1414      ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1415      if (!ph) {
1416           prom_printf ("Malloc error\n");
1417           goto bail;
1418      }
1419
1420      /* Now, we read the section header */
1421      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1422           prom_printf ("Seek error\n");
1423           goto bail;
1424      }
1425      if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1426          sizeof(Elf64_Phdr) * e->e_phnum) {
1427           prom_printf ("Read error\n");
1428           goto bail;
1429      }
1430
1431      /* Scan through the program header
1432       * HACK:  We must return the _memory size of the kernel image, not the
1433       *        file size (because we have to leave room before other boot
1434       *   infos. This code works as a side effect of the fact that
1435       *   we have one section and vaddr == p_paddr
1436       */
1437      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1438      p = ph;
1439      for (i = 0; i < e->e_phnum; ++i, ++p) {
1440           if (p->p_type != PT_LOAD || p->p_offset == 0)
1441                continue;
1442           if (loadinfo->memsize == 0) {
1443                loadinfo->offset = p->p_offset;
1444                loadinfo->memsize = p->p_memsz;
1445                loadinfo->filesize = p->p_filesz;
1446                loadinfo->load_loc = p->p_vaddr;
1447           } else {
1448                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1449                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1450           }
1451      }
1452
1453      if (loadinfo->memsize == 0) {
1454           prom_printf("Can't find a loadable segment !\n");
1455           goto bail;
1456      }
1457
1458      /* leave some room (1Mb) for boot infos */
1459      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1460      /* Claim OF memory */
1461      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1462
1463      /* Determine whether we are trying to boot a vmlinux or some
1464       * other binary image (eg, zImage).  We load vmlinux's at
1465       * KERNELADDR and all other binaries at their e_entry value.
1466       */
1467      if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1468           flat_vmlinux = 1;
1469           loadaddr = KERNELADDR;
1470      } else {
1471           flat_vmlinux = 0;
1472           loadaddr = e->e_entry;
1473      }
1474
1475      /* On some systems, loadaddr may already be claimed, so try some
1476       * other nearby addresses before giving up.
1477       */
1478      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1479           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1480           if (loadinfo->base != (void *)-1) break;
1481      }
1482      if (loadinfo->base == (void *)-1) {
1483           prom_printf("Claim error, can't allocate kernel memory\n");
1484           goto bail;
1485      }
1486
1487      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1488              loadinfo->base, loadinfo->memsize);
1489      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1490              loadaddr, loadinfo->memsize);
1491
1492      /* Load the program segments... */
1493      p = ph;
1494      for (i = 0; i < e->e_phnum; ++i, ++p) {
1495           unsigned long offset;
1496           if (p->p_type != PT_LOAD || p->p_offset == 0)
1497                continue;
1498
1499           /* Now, we skip to the image itself */
1500           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1501                prom_printf ("Seek error\n");
1502                prom_release(loadinfo->base, loadinfo->memsize);
1503                goto bail;
1504           }
1505           offset = p->p_vaddr - loadinfo->load_loc;
1506           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1507                prom_printf ("Read failed\n");
1508                prom_release(loadinfo->base, loadinfo->memsize);
1509                goto bail;
1510           }
1511      }
1512
1513      free(ph);
1514
1515      /* Return success at loading the Elf64 kernel */
1516      return 1;
1517
1518 bail:
1519      if (ph)
1520        free(ph);
1521      return 0;
1522 }
1523
1524 static int
1525 is_elf32(loadinfo_t *loadinfo)
1526 {
1527      Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1528
1529      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1530              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1531              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1532              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1533              e->e_ident[EI_CLASS] == ELFCLASS32  &&
1534              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1535              e->e_type            == ET_EXEC        &&
1536              e->e_machine         == EM_PPC);
1537 }
1538
1539 static int
1540 is_elf64(loadinfo_t *loadinfo)
1541 {
1542      Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1543
1544      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1545              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1546              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1547              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1548              e->e_ident[EI_CLASS] == ELFCLASS64  &&
1549              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1550              e->e_type            == ET_EXEC        &&
1551              e->e_machine         == EM_PPC64);
1552 }
1553
1554 static void
1555 setup_display(void)
1556 {
1557 #ifdef CONFIG_SET_COLORMAP
1558      static unsigned char default_colors[] = {
1559           0x00, 0x00, 0x00,
1560           0x00, 0x00, 0xaa,
1561           0x00, 0xaa, 0x00,
1562           0x00, 0xaa, 0xaa,
1563           0xaa, 0x00, 0x00,
1564           0xaa, 0x00, 0xaa,
1565           0xaa, 0x55, 0x00,
1566           0xaa, 0xaa, 0xaa,
1567           0x55, 0x55, 0x55,
1568           0x55, 0x55, 0xff,
1569           0x55, 0xff, 0x55,
1570           0x55, 0xff, 0xff,
1571           0xff, 0x55, 0x55,
1572           0xff, 0x55, 0xff,
1573           0xff, 0xff, 0x55,
1574           0xff, 0xff, 0xff
1575      };
1576      int i, result;
1577      prom_handle scrn = PROM_INVALID_HANDLE;
1578
1579      /* Try Apple's mac-boot screen ihandle */
1580      result = (int)call_prom_return("interpret", 1, 2,
1581                                     "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1582      DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1583
1584      if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1585           char type[32];
1586           /* Hrm... check to see if stdout is a display */
1587           scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1588           DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1589           if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1590                DEBUG_F("got it ! stdout is a screen\n");
1591                scrn = prom_stdout;
1592           } else {
1593                /* Else, we try to open the package */
1594                scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1595                DEBUG_F("Open screen result: %p\n", scrn);
1596           }
1597      }
1598
1599      if (scrn == PROM_INVALID_HANDLE) {
1600           prom_printf("No screen device found !/n");
1601           return;
1602      }
1603      for(i=0;i<16;i++) {
1604           prom_set_color(scrn, i, default_colors[i*3],
1605                          default_colors[i*3+1], default_colors[i*3+2]);
1606      }
1607      prom_printf("\x1b[1;37m\x1b[2;40m");
1608 #ifdef COLOR_TEST
1609      for (i=0;i<16; i++) {
1610           prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1611                       ansi_color_table[i].index,
1612                       ansi_color_table[i].value,
1613                       ansi_color_table[i].name,
1614                       ansi_color_table[i].name);
1615           prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1616                       ansi_color_table[i].index,
1617                       ansi_color_table[i].value+10,
1618                       ansi_color_table[i].name,
1619                       ansi_color_table[i].name);
1620      }
1621      prom_printf("\x1b[1;37m\x1b[2;40m");
1622 #endif /* COLOR_TEST */
1623
1624 #if !DEBUG
1625      prom_printf("\xc");
1626 #endif /* !DEBUG */
1627
1628 #endif /* CONFIG_SET_COLORMAP */
1629 }
1630
1631 int
1632 yaboot_main(void)
1633 {
1634      char *ptype;
1635      int conf_given = 0;
1636      char conf_path[1024];
1637
1638      if (_machine == _MACH_Pmac)
1639           setup_display();
1640
1641      prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1642      DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1643      prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1644      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1645
1646      /* If conf= specified on command line, it overrides
1647         Usage: conf=device:partition,/path/to/conffile
1648         Example: On Open Firmware Prompt, type
1649                  boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1650
1651      if (!strncmp(bootargs, "conf=", 5)) {
1652         DEBUG_F("Using conf argument in Open Firmware\n");
1653         char *end = strchr(bootargs,' ');
1654         if (end)
1655             *end = 0;
1656
1657         strcpy(bootdevice, bootargs + 5);
1658         conf_given = 1;
1659         DEBUG_F("Using conf=%s\n", bootdevice);
1660
1661         /* Remove conf=xxx from bootargs */
1662         if (end)
1663             memmove(bootargs, end+1, strlen(end+1)+1);
1664         else
1665             bootargs[0] = 0;
1666      }
1667      if (bootdevice[0] == 0) {
1668           prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1669           DEBUG_F("boot-device = %s\n", bootdevice);
1670      }
1671      if (bootdevice[0] == 0) {
1672           prom_printf("Couldn't determine boot device\n");
1673           return -1;
1674      }
1675
1676      if (bootoncelabel[0] == 0) {
1677           prom_get_options("boot-once", bootoncelabel, 
1678                            sizeof(bootoncelabel));
1679           if (bootoncelabel[0] != 0)
1680                 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1681      }
1682      prom_set_options("boot-once", NULL, 0);
1683
1684      if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1685           prom_printf("%s: Unable to parse\n", bootdevice);
1686           return -1;
1687      }
1688      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1689              boot.dev, boot.part, boot.file);
1690
1691      if (!conf_given) {
1692          if (_machine == _MACH_chrp)
1693              boot.file = "/etc/";
1694          else if (strlen(boot.file)) {
1695              if (!strncmp(boot.file, "\\\\", 2))
1696                  boot.file = "\\\\";
1697              else {
1698                  char *p, *last;
1699                  p = last = boot.file;
1700                  while(*p) {
1701                      if (*p == '\\')
1702                          last = p;
1703                      p++;
1704                  }
1705                  if (p)
1706                      *(last) = 0;
1707                  else
1708                      boot.file = "";
1709                  if (strlen(boot.file))
1710                      strcat(boot.file, "\\");
1711              }
1712          }
1713          strcpy(conf_path, boot.file);
1714          strcat(conf_path, CONFIG_FILE_NAME);
1715          boot.file = conf_path;
1716          DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1717             boot.dev, boot.part, boot.file);
1718      }
1719
1720      /*
1721       * If we're doing a netboot, first look for one which matches our
1722       * MAC address.
1723       */
1724      if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1725           prom_printf("Try to netboot\n");
1726           useconf = load_my_config_file(&boot);
1727      }
1728
1729      if (!useconf)
1730          useconf = load_config_file(&boot);
1731
1732      prom_printf("Welcome to yaboot version " VERSION "\n");
1733      prom_printf("Enter \"help\" to get some basic usage information\n");
1734
1735      /* I am fed up with lusers using the wrong partition type and
1736         mailing me *when* it breaks */
1737
1738      if (_machine == _MACH_Pmac) {
1739           char *entry = cfg_get_strg(0, "ptypewarning");
1740           int warn = 1;
1741           if (entry)
1742                warn = strcmp(entry,
1743                              "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1744           if (warn) {
1745                ptype = get_part_type(boot.dev, boot.part);
1746                if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1747                     prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1748                                 "         type should be: \"Apple_Bootstrap\"\n\n", ptype);
1749                if (ptype)
1750                     free(ptype);
1751           }
1752      }
1753
1754      yaboot_text_ui();
1755
1756      prom_printf("Bye.\n");
1757      return 0;
1758 }
1759
1760 /*
1761  * Local variables:
1762  * c-file-style: "k&r"
1763  * c-basic-offset: 5
1764  * End:
1765  */