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