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