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