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