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