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