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