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