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