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