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