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