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