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