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