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