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