]> git.ozlabs.org Git - yaboot.git/blob - second/yaboot.c
ybin userland interface for specifying bootonce
[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 + \0 */
516      fspec.file = malloc(packet->hlen * 3 + 2 + 1);
517      if (!fspec.file)
518           goto out;
519
520      sprintf(fspec.file, "%02x", packet->htype);
521
522      for (i = 0; i < packet->hlen; i++) {
523           char tmp[4];
524           sprintf(tmp, "-%02x", packet->chaddr[i]);
525           strcat(fspec.file, tmp);
526      }
527
528      rc = load_config_file(&fspec);
529      if (rc)
530           goto out;
531
532
533      /*
534       * Now try to match on IP.
535       */
536      free(fspec.file);
537      fspec.file = malloc(9);
538      sprintf(fspec.file, "%08X", packet->yiaddr);
539
540      while (strlen(fspec.file)) {
541           rc = load_config_file(&fspec);
542           if (rc)
543                goto out;
544           /* Chop one digit off the end, try again */
545           fspec.file[strlen(fspec.file) - 1] = '\0';
546      }
547
548  out:
549      if (rc) /* modify original only on success */
550           orig_fspec->file = fspec.file;
551      else
552           free(fspec.file);
553      free(bootp_response);
554      return rc;
555 }
556
557 void maintabfunc (void)
558 {
559      if (useconf) {
560           cfg_print_images();
561           prom_printf("boot: %s", cbuff);
562      }
563 }
564
565 void
566 word_split(char **linep, char **paramsp)
567 {
568      char *p;
569
570      *paramsp = 0;
571      p = *linep;
572      if (p == 0)
573           return;
574      while (*p == ' ')
575           ++p;
576      if (*p == 0) {
577           *linep = 0;
578           return;
579      }
580      *linep = p;
581      while (*p != 0 && *p != ' ')
582           ++p;
583      while (*p == ' ')
584           *p++ = 0;
585      if (*p != 0)
586           *paramsp = p;
587 }
588
589 char *
590 make_params(char *label, char *params)
591 {
592      char *p, *q;
593      static char buffer[2048];
594
595      q = buffer;
596      *q = 0;
597
598      p = cfg_get_strg(label, "literal");
599      if (p) {
600           strcpy(q, p);
601           q = strchr(q, 0);
602           if (params) {
603                if (*p)
604                     *q++ = ' ';
605                strcpy(q, params);
606           }
607           return buffer;
608      }
609
610      p = cfg_get_strg(label, "root");
611      if (p) {
612           strcpy (q, "root=");
613           strcpy (q + 5, p);
614           q = strchr (q, 0);
615           *q++ = ' ';
616      }
617      if (cfg_get_flag(label, "read-only")) {
618           strcpy (q, "ro ");
619           q += 3;
620      }
621      if (cfg_get_flag(label, "read-write")) {
622           strcpy (q, "rw ");
623           q += 3;
624      }
625      p = cfg_get_strg(label, "ramdisk");
626      if (p) {
627           strcpy (q, "ramdisk=");
628           strcpy (q + 8, p);
629           q = strchr (q, 0);
630           *q++ = ' ';
631      }
632      p = cfg_get_strg(label, "initrd-size");
633      if (p) {
634           strcpy (q, "ramdisk_size=");
635           strcpy (q + 13, p);
636           q = strchr (q, 0);
637           *q++ = ' ';
638      }
639      if (cfg_get_flag(label, "novideo")) {
640           strcpy (q, "video=ofonly");
641           q = strchr (q, 0);
642           *q++ = ' ';
643      }
644      p = cfg_get_strg (label, "append");
645      if (p) {
646           strcpy (q, p);
647           q = strchr (q, 0);
648           *q++ = ' ';
649      }
650      *q = 0;
651      pause_after = cfg_get_flag (label, "pause-after");
652      p = cfg_get_strg(label, "pause-message");
653      if (p)
654           pause_message = p;
655      if (params)
656           strcpy(q, params);
657
658      return buffer;
659 }
660
661 void check_password(char *str)
662 {
663      int i;
664
665      prom_printf("\n%s", str);
666      for (i = 0; i < 3; i++) {
667           prom_printf ("\nPassword: ");
668           passwdbuff[0] = 0;
669           cmdedit ((void (*)(void)) 0, 1);
670           prom_printf ("\n");
671 #ifdef USE_MD5_PASSWORDS
672           if (!strncmp (password, "$1$", 3)) {
673                if (!check_md5_password(passwdbuff, password))
674                     return;
675           }
676           else if (!strcmp (password, passwdbuff))
677                return;
678 #else /* !MD5 */
679           if (!strcmp (password, passwdbuff))
680                return;
681 #endif /* USE_MD5_PASSWORDS */
682           if (i < 2) {
683                prom_sleep(1);
684                prom_printf ("Incorrect password.  Try again.");
685           }
686      }
687      prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
688                  "        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n"
689                  "                ||----w |\n                ||     ||\n");
690      prom_sleep(4);
691      prom_interpret("reset-all");
692 }
693
694 int get_params(struct boot_param_t* params)
695 {
696      int defpart;
697      char *defdevice = 0;
698      char *p, *q, *endp;
699      int c, n;
700      char *imagename = 0, *label;
701      int timeout = -1;
702      int beg = 0, end;
703      int singlekey = 0;
704      int restricted = 0;
705      static int first = 1;
706      static char imagepath[1024];
707      static char initrdpath[1024];
708      static char sysmappath[1024];
709
710      pause_after = 0;
711      memset(params, 0, sizeof(*params));
712      params->args = "";
713      params->kernel.part = -1;
714      params->rd.part = -1;
715      params->sysmap.part = -1;
716      defpart = boot.part;
717
718      cmdinit();
719
720      if (first) {
721           first = 0;
722           imagename = bootargs;
723           word_split(&imagename, &params->args);
724           timeout = DEFAULT_TIMEOUT;
725           if (imagename) {
726                prom_printf("Default supplied on the command line: %s ", imagename);
727                if (params->args)
728                     prom_printf("%s", params->args);
729                prom_printf("\n");
730           }
731           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
732                timeout = simple_strtol(q, NULL, 0);
733      }
734
735      prom_printf("boot: ");
736      c = -1;
737      if (timeout != -1) {
738           beg = prom_getms();
739           if (timeout > 0) {
740                end = beg + 100 * timeout;
741                do {
742                     c = prom_nbgetchar();
743                } while (c == -1 && prom_getms() <= end);
744           }
745           if (c == -1)
746                c = '\n';
747           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
748                cbuff[0] = c;
749                cbuff[1] = 0;
750           }
751      }
752
753      if (c != -1 && c != '\n' && c != '\r') {
754           if (c == '\t') {
755                maintabfunc ();
756           }  else if (c >= ' ') {
757                cbuff[0] = c;
758                cbuff[1] = 0;
759                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
760                     imagename = cbuff;
761                     singlekey = 1;
762                     prom_printf("%s\n", cbuff);
763                }
764           }
765      }
766
767      if (c == '\n' || c == '\r') {
768           if (!imagename) {
769                if (bootoncelabel[0] != 0)
770                     imagename = bootoncelabel;
771                else
772                     imagename = cfg_get_default();
773           }
774           if (imagename)
775                prom_printf("%s", imagename);
776           if (params->args)
777                prom_printf(" %s", params->args);
778           prom_printf("\n");
779      } else if (!singlekey) {
780           cmdedit(maintabfunc, 0);
781           prom_printf("\n");
782           strcpy(given_bootargs, cbuff);
783           given_bootargs_by_user = 1;
784           imagename = cbuff;
785           word_split(&imagename, &params->args);
786      }
787
788      /* chrp gets this wrong, force it -- Cort */
789      if ( useconf && (!imagename || imagename[0] == 0 ))
790           imagename = cfg_get_default();
791
792      label = 0;
793      defdevice = boot.dev;
794
795      if (useconf) {
796           defdevice = cfg_get_strg(0, "device");
797           p = cfg_get_strg(0, "partition");
798           if (p) {
799                n = simple_strtol(p, &endp, 10);
800                if (endp != p && *endp == 0)
801                     defpart = n;
802           }
803           p = cfg_get_strg(0, "pause-message");
804           if (p)
805                pause_message = p;
806           if (cfg_get_flag(0, "restricted"))
807                restricted = 1;
808           p = cfg_get_strg(imagename, "image");
809           if (p && *p) {
810                label = imagename;
811                imagename = p;
812                defdevice = cfg_get_strg(label, "device");
813                if(!defdevice) defdevice=boot.dev;
814                p = cfg_get_strg(label, "partition");
815                if (p) {
816                     n = simple_strtol(p, &endp, 10);
817                     if (endp != p && *endp == 0)
818                          defpart = n;
819                }
820                if (cfg_get_flag(label, "restricted"))
821                     restricted = 1;
822                if (label) {
823                     if (params->args && password && restricted)
824                          check_password ("To specify arguments for this image "
825                                          "you must enter the password.");
826                     else if (password && !restricted)
827                          check_password ("This image is restricted.");
828                }
829                params->args = make_params(label, params->args);
830           }
831      }
832
833      if (!strcmp (imagename, "help")) {
834           /* FIXME: defdevice shouldn't need to be reset all over the place */
835           if(!defdevice) defdevice = boot.dev;
836           prom_printf(
837                "\nPress the tab key for a list of defined images.\n"
838                "The label marked with a \"*\" is is the default image, "
839                "press <return> to boot it.\n\n"
840                "To boot any other label simply type its name and press <return>.\n\n"
841                "To boot a kernel image which is not defined in the yaboot configuration \n"
842                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
843                "\"device:\" is the OpenFirmware device path to the disk the image \n"
844                "resides on, and \"partno\" is the partition number the image resides on.\n"
845                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
846                "device, if you only specify a filename you should not start it with a \",\"\n\n"
847                "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
848                "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
849                "device=%s\n"
850                "partition=%d\n\n"
851                "To use an alternative config file rather than /etc/yaboot.conf, type on\n"
852                " Open FirmWare Prompt: \"boot conf=device:partition,/path/to/configfile\"\n"
853                "where \"device\" and \"partition\" are defined like above.\n\n", defdevice, defpart);
854
855           return 0;
856      }
857
858      if (!strcmp (imagename, "halt")) {
859           if (password)
860                check_password ("Restricted command.");
861           prom_pause();
862           return 0;
863      }
864      if (!strcmp (imagename, "bye")) {
865           if (password) {
866                check_password ("Restricted command.");
867                return 1;
868           }
869           return 1;
870      }
871
872      if (imagename[0] == '$') {
873           /* forth command string */
874           if (password)
875                check_password ("OpenFirmware commands are restricted.");
876           prom_interpret(imagename+1);
877           return 0;
878      }
879
880      strncpy(imagepath, imagename, 1024);
881
882      if (!label && password)
883           check_password ("To boot a custom image you must enter the password.");
884
885      if (!parse_device_path(imagepath, defdevice, defpart,
886                             "/vmlinux", &params->kernel)) {
887           prom_printf("%s: Unable to parse\n", imagepath);
888           return 0;
889      }
890      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
891              params->kernel.part, params->kernel.file);
892
893      if (useconf) {
894           p = cfg_get_strg(label, "initrd");
895           if (p && *p) {
896                DEBUG_F("Parsing initrd path <%s>\n", p);
897                strncpy(initrdpath, p, 1024);
898                if (!parse_device_path(initrdpath, defdevice, defpart,
899                                       "/root.bin", &params->rd)) {
900                     prom_printf("%s: Unable to parse\n", imagepath);
901                     return 0;
902                }
903           }
904           p = cfg_get_strg(label, "sysmap");
905           if (p && *p) {
906                DEBUG_F("Parsing sysmap path <%s>\n", p);
907                strncpy(sysmappath, p, 1024);
908                if (!parse_device_path(sysmappath, defdevice, defpart,
909                                       "/boot/System.map", &params->sysmap)) {
910                     prom_printf("%s: Unable to parse\n", imagepath);
911                     return 0;
912                }
913           }
914      }
915      return 0;
916 }
917
918 /* This is derived from quik core. To be changed to first parse the headers
919  * doing lazy-loading, and then claim the memory before loading the kernel
920  * to it
921  * We also need to add initrd support to this whole mecanism
922  */
923 void
924 yaboot_text_ui(void)
925 {
926 #define MAX_HEADERS     32
927
928      struct boot_file_t file;
929      int                        result;
930      static struct boot_param_t params;
931      void               *initrd_base;
932      unsigned long      initrd_size;
933      void                *sysmap_base;
934      unsigned long      sysmap_size;
935      kernel_entry_t      kernel_entry;
936      struct bi_record*  birec;
937      char*               loc=NULL;
938      loadinfo_t          loadinfo;
939      void                *initrd_more,*initrd_want;
940      unsigned long       initrd_read;
941
942      loadinfo.load_loc = 0;
943
944      for (;;) {
945           initrd_size = 0;
946           initrd_base = 0;
947           sysmap_base = 0;
948           sysmap_size = 0;
949
950           if (get_params(&params))
951                return;
952           if (!params.kernel.file)
953                continue;
954
955           prom_printf("Please wait, loading kernel...\n");
956
957           memset(&file, 0, sizeof(file));
958
959           if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
960               && params.kernel.file[0] != '\\') {
961                loc=(char*)malloc(strlen(params.kernel.file)+3);
962                if (!loc) {
963                     prom_printf ("malloc error\n");
964                     goto next;
965                }
966                strcpy(loc,boot.file);
967                strcat(loc,params.kernel.file);
968                free(params.kernel.file);
969                params.kernel.file=loc;
970           }
971           result = open_file(&params.kernel, &file);
972           if (result != FILE_ERR_OK) {
973                prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
974                prom_perror(result, params.kernel.file);
975                goto next;
976           }
977
978           /* Read the Elf e_ident, e_type and e_machine fields to
979            * determine Elf file type
980            */
981           if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
982                prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
983                file.fs->close(&file);
984                memset(&file, 0, sizeof(file));
985                goto next;
986           }
987
988           if (is_elf32(&loadinfo)) {
989                if (!load_elf32(&file, &loadinfo)) {
990                     file.fs->close(&file);
991                     memset(&file, 0, sizeof(file));
992                     goto next;
993                }
994                prom_printf("   Elf32 kernel loaded...\n");
995           } else if (is_elf64(&loadinfo)) {
996                if (!load_elf64(&file, &loadinfo)) {
997                     file.fs->close(&file);
998                     memset(&file, 0, sizeof(file));
999                     goto next;
1000                }
1001                prom_printf("   Elf64 kernel loaded...\n");
1002           } else {
1003                prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1004                file.fs->close(&file);
1005                memset(&file, 0, sizeof(file));
1006                goto next;
1007           }
1008           file.fs->close(&file);
1009           memset(&file, 0, sizeof(file));
1010
1011           /* If sysmap, load it (only if booting a vmlinux).
1012            */
1013           if (flat_vmlinux && params.sysmap.file) {
1014                prom_printf("Loading System.map ...\n");
1015                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1016                   && params.sysmap.file[0] != '\\') {
1017                     if (loc) free(loc);
1018                     loc=(char*)malloc(strlen(params.sysmap.file)+3);
1019                     if (!loc) {
1020                          prom_printf ("malloc error\n");
1021                          goto next;
1022                     }
1023                     strcpy(loc,boot.file);
1024                     strcat(loc,params.sysmap.file);
1025                     free(params.sysmap.file);
1026                     params.sysmap.file=loc;
1027                }
1028
1029                result = open_file(&params.sysmap, &file);
1030                if (result != FILE_ERR_OK) {
1031                     prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1032                     prom_perror(result, params.sysmap.file);
1033                }
1034                else {
1035                     sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1036                     if (sysmap_base == (void *)-1) {
1037                          prom_printf("Claim failed for sysmap memory\n");
1038                          prom_pause();
1039                          sysmap_base = 0;
1040                     } else {
1041                          sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1042                          if (sysmap_size == 0)
1043                               sysmap_base = 0;
1044                          else
1045                               ((char *)sysmap_base)[sysmap_size++] = 0;
1046                     }
1047                     file.fs->close(&file);
1048                     memset(&file, 0, sizeof(file));
1049                }
1050                if (sysmap_base) {
1051                     prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1052                                 sysmap_base, sysmap_size >> 10);
1053                     loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1054                } else {
1055                     prom_printf("System.map load failed !\n");
1056                     prom_pause();
1057                }
1058           }
1059
1060           /* If ramdisk, load it (only if booting a vmlinux).  For now, we
1061            * can't tell the size it will be so we claim an arbitrary amount
1062            * of 4Mb.
1063            */
1064           if (flat_vmlinux && params.rd.file) {
1065                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1066                   && params.kernel.file[0] != '\\')
1067                {
1068                     if (loc) free(loc);
1069                     loc=(char*)malloc(strlen(params.rd.file)+3);
1070                     if (!loc) {
1071                          prom_printf ("Malloc error\n");
1072                          goto next;
1073                     }
1074                     strcpy(loc,boot.file);
1075                     strcat(loc,params.rd.file);
1076                     free(params.rd.file);
1077                     params.rd.file=loc;
1078                }
1079                prom_printf("Loading ramdisk...\n");
1080                result = open_file(&params.rd, &file);
1081                if (result != FILE_ERR_OK) {
1082                     prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1083                     prom_perror(result, params.rd.file);
1084                }
1085                else {
1086 #define INITRD_CHUNKSIZE 0x100000
1087                     initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1088                     if (initrd_base == (void *)-1) {
1089                          prom_printf("Claim failed for initrd memory\n");
1090                          initrd_base = 0;
1091                     } else {
1092                          initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1093                          if (initrd_size == 0)
1094                               initrd_base = 0;
1095                          initrd_read = initrd_size;
1096                          initrd_more = initrd_base;
1097                          while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1098                               initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1099                               initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1100                               if (initrd_more != initrd_want) {
1101                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1102                                    prom_pause();
1103                                    break;
1104                               }
1105                               initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1106                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
1107                               initrd_size += initrd_read;
1108                          }
1109                     }
1110                     file.fs->close(&file);
1111                     memset(&file, 0, sizeof(file));
1112                }
1113                if (initrd_base)
1114                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1115                                 initrd_base, initrd_size >> 10);
1116                else {
1117                     prom_printf("ramdisk load failed !\n");
1118                     prom_pause();
1119                }
1120           }
1121
1122           DEBUG_F("setting kernel args to: %s\n", params.args);
1123           prom_setargs(params.args);
1124           DEBUG_F("flushing icache...");
1125           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1126           DEBUG_F(" done\n");
1127
1128           if (flat_vmlinux) {
1129                /*
1130                 * Fill new boot infos (only if booting a vmlinux).
1131                 *
1132                 * The birec is low on memory, probably inside the malloc pool,
1133                 * so we don't write it earlier. At this point, we should not
1134                 * use anything coming from the malloc pool.
1135                 */
1136                birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1137
1138                /* We make sure it's mapped. We map only 64k for now, it's
1139                 * plenty enough we don't claim since this precise memory
1140                 * range may already be claimed by the malloc pool.
1141                 */
1142                prom_map (birec, birec, 0x10000);
1143                DEBUG_F("birec at %p\n", birec);
1144                DEBUG_SLEEP;
1145
1146                birec->tag = BI_FIRST;
1147                birec->size = sizeof(struct bi_record);
1148                birec = (struct bi_record *)((ulong)birec + birec->size);
1149
1150                birec->tag = BI_BOOTLOADER_ID;
1151                sprintf( (char *)birec->data, "yaboot");
1152                birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1153                birec = (struct bi_record *)((ulong)birec + birec->size);
1154
1155                birec->tag = BI_MACHTYPE;
1156                birec->data[0] = _machine;
1157                birec->size = sizeof(struct bi_record) + sizeof(ulong);
1158                birec = (struct bi_record *)((ulong)birec + birec->size);
1159
1160                if (sysmap_base) {
1161                     birec->tag = BI_SYSMAP;
1162                     birec->data[0] = (ulong)sysmap_base;
1163                     birec->data[1] = sysmap_size;
1164                     birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1165                     birec = (struct bi_record *)((ulong)birec + birec->size);
1166                }
1167                birec->tag = BI_LAST;
1168                birec->size = sizeof(struct bi_record);
1169                birec = (struct bi_record *)((ulong)birec + birec->size);
1170           }
1171
1172           /* compute the kernel's entry point. */
1173           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1174
1175           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1176           DEBUG_F("kernel: arg1 = %p,\n"
1177                   "        arg2 = 0x%08lx,\n"
1178                   "        prom = %p,\n"
1179                   "        arg4 = %d,\n"
1180                   "        arg5 = %d\n\n",
1181                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1182
1183           DEBUG_F("Entering kernel...\n");
1184
1185           /* call the kernel with our stack. */
1186           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1187           continue;
1188      next:
1189           ; /* do nothing */
1190      }
1191 }
1192
1193 static int
1194 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1195 {
1196      int                        i;
1197      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1198      Elf32_Phdr         *p, *ph;
1199      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1200      unsigned long      addr, loadaddr;
1201
1202      /* Read the rest of the Elf header... */
1203      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1204           prom_printf("\nCan't read Elf32 image header\n");
1205           goto bail;
1206      }
1207
1208      DEBUG_F("Elf32 header:\n");
1209      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1210      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1211      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1212      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1213      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1214      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1215      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1216      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1217      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1218      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1219
1220      loadinfo->entry = e->e_entry;
1221
1222      if (e->e_phnum > MAX_HEADERS) {
1223           prom_printf ("Can only load kernels with one program header\n");
1224           goto bail;
1225      }
1226
1227      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1228      if (!ph) {
1229           prom_printf ("Malloc error\n");
1230           goto bail;
1231      }
1232
1233      /* Now, we read the section header */
1234      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1235           prom_printf ("seek error\n");
1236           goto bail;
1237      }
1238      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1239          sizeof(Elf32_Phdr) * e->e_phnum) {
1240           prom_printf ("read error\n");
1241           goto bail;
1242      }
1243
1244      /* Scan through the program header
1245       * HACK:  We must return the _memory size of the kernel image, not the
1246       *        file size (because we have to leave room before other boot
1247       *   infos. This code works as a side effect of the fact that
1248       *   we have one section and vaddr == p_paddr
1249       */
1250      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1251      p = ph;
1252      for (i = 0; i < e->e_phnum; ++i, ++p) {
1253           if (p->p_type != PT_LOAD || p->p_offset == 0)
1254                continue;
1255           if (loadinfo->memsize == 0) {
1256                loadinfo->offset = p->p_offset;
1257                loadinfo->memsize = p->p_memsz;
1258                loadinfo->filesize = p->p_filesz;
1259                loadinfo->load_loc = p->p_vaddr;
1260           } else {
1261                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1262                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1263           }
1264      }
1265
1266      if (loadinfo->memsize == 0) {
1267           prom_printf("Can't find a loadable segment !\n");
1268           goto bail;
1269      }
1270
1271      /* leave some room (1Mb) for boot infos */
1272      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1273      /* Claim OF memory */
1274      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1275
1276      /* Determine whether we are trying to boot a vmlinux or some
1277       * other binary image (eg, zImage).  We load vmlinux's at
1278       * KERNELADDR and all other binaries at their e_entry value.
1279       */
1280      if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1281           flat_vmlinux = 1;
1282           loadaddr = KERNELADDR;
1283      } else {
1284           flat_vmlinux = 0;
1285           loadaddr = loadinfo->load_loc;
1286      }
1287
1288      /* On some systems, loadaddr may already be claimed, so try some
1289       * other nearby addresses before giving up.
1290       */
1291      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1292           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1293           if (loadinfo->base != (void *)-1) break;
1294      }
1295      if (loadinfo->base == (void *)-1) {
1296           prom_printf("Claim error, can't allocate kernel memory\n");
1297           goto bail;
1298      }
1299
1300      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1301              loadinfo->base, loadinfo->memsize);
1302      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1303              loadaddr, loadinfo->memsize);
1304
1305      /* Load the program segments... */
1306      p = ph;
1307      for (i = 0; i < e->e_phnum; ++i, ++p) {
1308           unsigned long offset;
1309           if (p->p_type != PT_LOAD || p->p_offset == 0)
1310                continue;
1311
1312           /* Now, we skip to the image itself */
1313           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1314                prom_printf ("Seek error\n");
1315                prom_release(loadinfo->base, loadinfo->memsize);
1316                goto bail;
1317           }
1318           offset = p->p_vaddr - loadinfo->load_loc;
1319           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1320                prom_printf ("Read failed\n");
1321                prom_release(loadinfo->base, loadinfo->memsize);
1322                goto bail;
1323           }
1324      }
1325
1326      free(ph);
1327
1328      /* Return success at loading the Elf32 kernel */
1329      return 1;
1330
1331 bail:
1332      if (ph)
1333        free(ph);
1334      return 0;
1335 }
1336
1337 static int
1338 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1339 {
1340      int                        i;
1341      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1342      Elf64_Phdr         *p, *ph;
1343      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1344      unsigned long      addr, loadaddr;
1345
1346      /* Read the rest of the Elf header... */
1347      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1348           prom_printf("\nCan't read Elf64 image header\n");
1349           goto bail;
1350      }
1351
1352      DEBUG_F("Elf64 header:\n");
1353      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1354      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1355      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1356      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1357      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1358      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1359      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1360      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1361      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1362      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1363
1364      loadinfo->entry = e->e_entry;
1365
1366      if (e->e_phnum > MAX_HEADERS) {
1367           prom_printf ("Can only load kernels with one program header\n");
1368           goto bail;
1369      }
1370
1371      ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1372      if (!ph) {
1373           prom_printf ("Malloc error\n");
1374           goto bail;
1375      }
1376
1377      /* Now, we read the section header */
1378      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1379           prom_printf ("Seek error\n");
1380           goto bail;
1381      }
1382      if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1383          sizeof(Elf64_Phdr) * e->e_phnum) {
1384           prom_printf ("Read error\n");
1385           goto bail;
1386      }
1387
1388      /* Scan through the program header
1389       * HACK:  We must return the _memory size of the kernel image, not the
1390       *        file size (because we have to leave room before other boot
1391       *   infos. This code works as a side effect of the fact that
1392       *   we have one section and vaddr == p_paddr
1393       */
1394      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1395      p = ph;
1396      for (i = 0; i < e->e_phnum; ++i, ++p) {
1397           if (p->p_type != PT_LOAD || p->p_offset == 0)
1398                continue;
1399           if (loadinfo->memsize == 0) {
1400                loadinfo->offset = p->p_offset;
1401                loadinfo->memsize = p->p_memsz;
1402                loadinfo->filesize = p->p_filesz;
1403                loadinfo->load_loc = p->p_vaddr;
1404           } else {
1405                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1406                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1407           }
1408      }
1409
1410      if (loadinfo->memsize == 0) {
1411           prom_printf("Can't find a loadable segment !\n");
1412           goto bail;
1413      }
1414
1415      /* leave some room (1Mb) for boot infos */
1416      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1417      /* Claim OF memory */
1418      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1419
1420      /* Determine whether we are trying to boot a vmlinux or some
1421       * other binary image (eg, zImage).  We load vmlinux's at
1422       * KERNELADDR and all other binaries at their e_entry value.
1423       */
1424      if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1425           flat_vmlinux = 1;
1426           loadaddr = KERNELADDR;
1427      } else {
1428           flat_vmlinux = 0;
1429           loadaddr = e->e_entry;
1430      }
1431
1432      /* On some systems, loadaddr may already be claimed, so try some
1433       * other nearby addresses before giving up.
1434       */
1435      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1436           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1437           if (loadinfo->base != (void *)-1) break;
1438      }
1439      if (loadinfo->base == (void *)-1) {
1440           prom_printf("Claim error, can't allocate kernel memory\n");
1441           goto bail;
1442      }
1443
1444      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1445              loadinfo->base, loadinfo->memsize);
1446      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1447              loadaddr, loadinfo->memsize);
1448
1449      /* Load the program segments... */
1450      p = ph;
1451      for (i = 0; i < e->e_phnum; ++i, ++p) {
1452           unsigned long offset;
1453           if (p->p_type != PT_LOAD || p->p_offset == 0)
1454                continue;
1455
1456           /* Now, we skip to the image itself */
1457           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1458                prom_printf ("Seek error\n");
1459                prom_release(loadinfo->base, loadinfo->memsize);
1460                goto bail;
1461           }
1462           offset = p->p_vaddr - loadinfo->load_loc;
1463           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1464                prom_printf ("Read failed\n");
1465                prom_release(loadinfo->base, loadinfo->memsize);
1466                goto bail;
1467           }
1468      }
1469
1470      free(ph);
1471
1472      /* Return success at loading the Elf64 kernel */
1473      return 1;
1474
1475 bail:
1476      if (ph)
1477        free(ph);
1478      return 0;
1479 }
1480
1481 static int
1482 is_elf32(loadinfo_t *loadinfo)
1483 {
1484      Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1485
1486      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1487              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1488              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1489              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1490              e->e_ident[EI_CLASS] == ELFCLASS32  &&
1491              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1492              e->e_type            == ET_EXEC        &&
1493              e->e_machine         == EM_PPC);
1494 }
1495
1496 static int
1497 is_elf64(loadinfo_t *loadinfo)
1498 {
1499      Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1500
1501      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1502              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1503              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1504              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1505              e->e_ident[EI_CLASS] == ELFCLASS64  &&
1506              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1507              e->e_type            == ET_EXEC        &&
1508              e->e_machine         == EM_PPC64);
1509 }
1510
1511 static void
1512 setup_display(void)
1513 {
1514 #ifdef CONFIG_SET_COLORMAP
1515      static unsigned char default_colors[] = {
1516           0x00, 0x00, 0x00,
1517           0x00, 0x00, 0xaa,
1518           0x00, 0xaa, 0x00,
1519           0x00, 0xaa, 0xaa,
1520           0xaa, 0x00, 0x00,
1521           0xaa, 0x00, 0xaa,
1522           0xaa, 0x55, 0x00,
1523           0xaa, 0xaa, 0xaa,
1524           0x55, 0x55, 0x55,
1525           0x55, 0x55, 0xff,
1526           0x55, 0xff, 0x55,
1527           0x55, 0xff, 0xff,
1528           0xff, 0x55, 0x55,
1529           0xff, 0x55, 0xff,
1530           0xff, 0xff, 0x55,
1531           0xff, 0xff, 0xff
1532      };
1533      int i, result;
1534      prom_handle scrn = PROM_INVALID_HANDLE;
1535
1536      /* Try Apple's mac-boot screen ihandle */
1537      result = (int)call_prom_return("interpret", 1, 2,
1538                                     "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1539      DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1540
1541      if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1542           char type[32];
1543           /* Hrm... check to see if stdout is a display */
1544           scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1545           DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1546           if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1547                DEBUG_F("got it ! stdout is a screen\n");
1548                scrn = prom_stdout;
1549           } else {
1550                /* Else, we try to open the package */
1551                scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1552                DEBUG_F("Open screen result: %p\n", scrn);
1553           }
1554      }
1555
1556      if (scrn == PROM_INVALID_HANDLE) {
1557           prom_printf("No screen device found !/n");
1558           return;
1559      }
1560      for(i=0;i<16;i++) {
1561           prom_set_color(scrn, i, default_colors[i*3],
1562                          default_colors[i*3+1], default_colors[i*3+2]);
1563      }
1564      prom_printf("\x1b[1;37m\x1b[2;40m");
1565 #ifdef COLOR_TEST
1566      for (i=0;i<16; i++) {
1567           prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1568                       ansi_color_table[i].index,
1569                       ansi_color_table[i].value,
1570                       ansi_color_table[i].name,
1571                       ansi_color_table[i].name);
1572           prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1573                       ansi_color_table[i].index,
1574                       ansi_color_table[i].value+10,
1575                       ansi_color_table[i].name,
1576                       ansi_color_table[i].name);
1577      }
1578      prom_printf("\x1b[1;37m\x1b[2;40m");
1579 #endif /* COLOR_TEST */
1580
1581 #if !DEBUG
1582      prom_printf("\xc");
1583 #endif /* !DEBUG */
1584
1585 #endif /* CONFIG_SET_COLORMAP */
1586 }
1587
1588 int
1589 yaboot_main(void)
1590 {
1591      char *ptype;
1592      int conf_given = 0;
1593      char conf_path[1024];
1594
1595      if (_machine == _MACH_Pmac)
1596           setup_display();
1597
1598      prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1599      DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1600      prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1601      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1602
1603      /* If conf= specified on command line, it overrides
1604         Usage: conf=device:partition,/path/to/conffile
1605         Example: On Open Firmware Prompt, type
1606                  boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1607
1608      if (!strncmp(bootargs, "conf=", 5)) {
1609         DEBUG_F("Using conf argument in Open Firmware\n");
1610         char *end = strchr(bootargs,' ');
1611         if (end)
1612             *end = 0;
1613
1614         strcpy(bootdevice, bootargs + 5);
1615         conf_given = 1;
1616         DEBUG_F("Using conf=%s\n", bootdevice);
1617
1618         /* Remove conf=xxx from bootargs */
1619         if (end)
1620             memmove(bootargs, end+1, strlen(end+1)+1);
1621         else
1622             bootargs[0] = 0;
1623      }
1624      if (bootdevice[0] == 0) {
1625           prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1626           DEBUG_F("boot-device = %s\n", bootdevice);
1627      }
1628      if (bootdevice[0] == 0) {
1629           prom_printf("Couldn't determine boot device\n");
1630           return -1;
1631      }
1632
1633      if (bootoncelabel[0] == 0) {
1634           prom_get_options("boot-once", bootoncelabel, 
1635                            sizeof(bootoncelabel));
1636           if (bootoncelabel[0] != 0)
1637                 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1638      }
1639      prom_set_options("boot-once", NULL, 0);
1640
1641      if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1642           prom_printf("%s: Unable to parse\n", bootdevice);
1643           return -1;
1644      }
1645      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1646              boot.dev, boot.part, boot.file);
1647
1648      if (!conf_given) {
1649          if (_machine == _MACH_chrp)
1650              boot.file = "/etc/";
1651          else if (strlen(boot.file)) {
1652              if (!strncmp(boot.file, "\\\\", 2))
1653                  boot.file = "\\\\";
1654              else {
1655                  char *p, *last;
1656                  p = last = boot.file;
1657                  while(*p) {
1658                      if (*p == '\\')
1659                          last = p;
1660                      p++;
1661                  }
1662                  if (p)
1663                      *(last) = 0;
1664                  else
1665                      boot.file = "";
1666                  if (strlen(boot.file))
1667                      strcat(boot.file, "\\");
1668              }
1669          }
1670          strcpy(conf_path, boot.file);
1671          strcat(conf_path, CONFIG_FILE_NAME);
1672          boot.file = conf_path;
1673          DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1674             boot.dev, boot.part, boot.file);
1675      }
1676
1677      /*
1678       * If we're doing a netboot, first look for one which matches our
1679       * MAC address.
1680       */
1681      if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1682           prom_printf("Try to netboot\n");
1683           useconf = load_my_config_file(&boot);
1684      }
1685
1686      if (!useconf)
1687          useconf = load_config_file(&boot);
1688
1689      prom_printf("Welcome to yaboot version " VERSION "\n");
1690      prom_printf("Enter \"help\" to get some basic usage information\n");
1691
1692      /* I am fed up with lusers using the wrong partition type and
1693         mailing me *when* it breaks */
1694
1695      if (_machine == _MACH_Pmac) {
1696           char *entry = cfg_get_strg(0, "ptypewarning");
1697           int warn = 1;
1698           if (entry)
1699                warn = strcmp(entry,
1700                              "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1701           if (warn) {
1702                ptype = get_part_type(boot.dev, boot.part);
1703                if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1704                     prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1705                                 "         type should be: \"Apple_Bootstrap\"\n\n", ptype);
1706                if (ptype)
1707                     free(ptype);
1708           }
1709      }
1710
1711      yaboot_text_ui();
1712
1713      prom_printf("Bye.\n");
1714      return 0;
1715 }
1716
1717 /*
1718  * Local variables:
1719  * c-file-style: "k&r"
1720  * c-basic-offset: 5
1721  * End:
1722  */