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