]> git.ozlabs.org Git - yaboot.git/blob - second/yaboot.c
b7b9280b7577dc7ea8606ade10f002c64bc5d0fb
[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 int
171 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
172 {
173      int result;
174      void* malloc_base = NULL;
175      prom_handle root;
176
177      /* Initialize OF interface */
178      prom_init ((prom_entry) r5);
179
180      prom_print_available();
181
182      /* Allocate some memory for malloc'ator */
183      malloc_base = prom_claim_chunk_top(MALLOCSIZE, 0);
184      if (malloc_base == (void *)-1) {
185           prom_printf("Can't claim malloc buffer of %d bytes\n",
186                       MALLOCSIZE);
187           return -1;
188      }
189      malloc_init(malloc_base, MALLOCSIZE);
190      DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
191              malloc_base, MALLOCSIZE);
192
193      /* A few useless DEBUG_F's */
194      DEBUG_F("reloc_offset :  %ld         (should be 0)\n", reloc_offset());
195      DEBUG_F("linked at    :  0x%08x\n", TEXTADDR);
196
197      /* ask the OF info if we're a chrp or pmac */
198      /* we need to set _machine before calling finish_device_tree */
199      root = prom_finddevice("/");
200      if (root != 0) {
201           static char model[256];
202           if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
203               !strncmp("bplan", model, 5))
204                _machine = _MACH_bplan;
205           else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
206               !strncmp("chrp", model, 4))
207                _machine = _MACH_chrp;
208           else {
209                if (prom_getprop(root, "model", model, 256 ) > 0 &&
210                    !strncmp(model, "IBM", 3))
211                     _machine = _MACH_chrp;
212           }
213      }
214
215      DEBUG_F("Running on _machine = %d\n", _machine);
216      DEBUG_SLEEP;
217
218      /* Call out main */
219      result = yaboot_main();
220
221      /* Get rid of malloc pool */
222      malloc_dispose();
223      prom_release(malloc_base, MALLOCSIZE);
224      DEBUG_F("Malloc buffer released. Exiting with code %d\n",
225              result);
226
227      /* Return to OF */
228      prom_exit();
229
230      return result;
231
232 }
233
234 #ifdef CONFIG_COLOR_TEXT
235 /*
236  * Validify color for text ui
237  */
238 static int
239 check_color_text_ui(char *color)
240 {
241      int i = 0;
242      while(ansi_color_table[i].name) {
243           if (!strcmp(color, ansi_color_table[i].name))
244                return i;
245           i++;
246      }
247      return -1;
248 }
249 #endif /* CONFIG_COLOR_TEXT */
250
251
252 void print_message_file(char *filename)
253 {
254      char *msg = NULL;
255      char *p, *endp;
256      char *defdev = boot.dev;
257      int defpart = boot.part;
258      char msgpath[1024];
259      int opened = 0;
260      int result = 0;
261      int n;
262      struct boot_file_t file;
263      struct boot_fspec_t msgfile;
264
265      defdev = cfg_get_strg(0, "device");
266      if (!defdev)
267           defdev = boot.dev;
268      p = cfg_get_strg(0, "partition");
269           if (p) {
270                n = simple_strtol(p, &endp, 10);
271                if (endp != p && *endp == 0)
272                     defpart = n;
273           }
274
275      strncpy(msgpath, filename, sizeof(msgpath));
276      msgfile = boot; /* Copy all the original paramters */
277      if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
278           prom_printf("%s: Unable to parse\n", msgpath);
279           goto done;
280      }
281
282      result = open_file(&msgfile, &file);
283      if (result != FILE_ERR_OK) {
284           prom_printf("%s:%d,", msgfile.dev, msgfile.part);
285           prom_perror(result, msgfile.file);
286           goto done;
287      } else
288           opened = 1;
289
290      msg = malloc(MESSAGE_FILE_MAX + 1);
291      if (!msg)
292           goto done;
293      else
294           memset(msg, 0, MESSAGE_FILE_MAX + 1);
295
296      if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
297           goto done;
298      else
299           prom_printf("%s", msg);
300
301 done:
302      if (opened)
303           file.fs->close(&file);
304      if (msg)
305           free(msg);
306 }
307
308 /* Currently, the config file must be at the root of the filesystem.
309  * todo: recognize the full path to myself and use it to load the
310  * config file. Handle the "\\" (blessed system folder)
311  */
312 static int
313 load_config_file(struct boot_fspec_t *fspec)
314 {
315      char *conf_file = NULL, *p;
316      struct boot_file_t file;
317      int sz, opened = 0, result = 0;
318
319      /* Allocate a buffer for the config file */
320      conf_file = malloc(CONFIG_FILE_MAX);
321      if (!conf_file) {
322           prom_printf("Can't alloc config file buffer\n");
323           goto bail;
324      }
325
326      /* Open it */
327      result = open_file(fspec, &file);
328      if (result != FILE_ERR_OK) {
329           prom_printf("%s:%d,", fspec->dev, fspec->part);
330           prom_perror(result, fspec->file);
331           prom_printf("Can't open config file\n");
332           goto bail;
333      }
334      opened = 1;
335
336      /* Read it */
337      sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
338      if (sz <= 0) {
339           prom_printf("Error, can't read config file\n");
340           goto bail;
341      }
342      prom_printf("Config file read, %d bytes\n", sz);
343
344      /* Close the file */
345      if (opened)
346           file.fs->close(&file);
347      opened = 0;
348
349      /* Call the parsing code in cfg.c */
350      if (cfg_parse(fspec->file, conf_file, sz) < 0) {
351           prom_printf ("Syntax error or read error config\n");
352           goto bail;
353      }
354
355      /* 
356       * set the default cf_option to label that has the same MAC addr 
357       * it only works if there is a label with the MAC addr on yaboot.conf
358       */
359      if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
360          /* change the variable bellow to get the MAC dinamicaly */
361          char * macaddr = NULL;
362          int default_mac = 0;
363
364          macaddr = prom_get_mac(prom_get_netinfo());
365          default_mac = cfg_set_default_by_mac(macaddr);
366          if (default_mac >= 1) {
367             prom_printf("Default label was changed to macaddr label.\n");
368          }
369      }
370
371      DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
372
373      /* Now, we do the initialisations stored in the config file */
374      p = cfg_get_strg(0, "init-code");
375      if (p)
376           prom_interpret(p);
377
378      password = cfg_get_strg(0, "password");
379
380 #ifdef CONFIG_COLOR_TEXT
381      p = cfg_get_strg(0, "fgcolor");
382      if (p) {
383           DEBUG_F("fgcolor=%s\n", p);
384           fgcolor = check_color_text_ui(p);
385           if (fgcolor == -1) {
386                prom_printf("Invalid fgcolor: \"%s\".\n", p);
387           }
388      }
389      p = cfg_get_strg(0, "bgcolor");
390      if (p) {
391           DEBUG_F("bgcolor=%s\n", p);
392           bgcolor = check_color_text_ui(p);
393           if (bgcolor == -1)
394                prom_printf("Invalid bgcolor: \"%s\".\n", p);
395      }
396      if (bgcolor >= 0) {
397           char temp[64];
398           sprintf(temp, "%x to background-color", bgcolor);
399           prom_interpret(temp);
400 #if !DEBUG
401           prom_printf("\xc");
402 #endif /* !DEBUG */
403      }
404      if (fgcolor >= 0) {
405           char temp[64];
406           sprintf(temp, "%x to foreground-color", fgcolor);
407           prom_interpret(temp);
408      }
409 #endif /* CONFIG_COLOR_TEXT */
410
411      p = cfg_get_strg(0, "init-message");
412      if (p)
413           prom_printf("%s\n", p);
414
415      p = cfg_get_strg(0, "message");
416      if (p)
417           print_message_file(p);
418
419      result = 1;
420
421 bail:
422
423      if (opened)
424           file.fs->close(&file);
425
426      if (conf_file)
427           free(conf_file);
428
429      return result;
430 }
431
432 /*
433  * Search for config file by MAC address, then by IP address.
434  * Basically copying pxelinux's algorithm.
435  * http://syslinux.zytor.com/pxe.php#config
436  */
437 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
438 {
439      struct bootp_packet *packet;
440      int rc = 0;
441      struct boot_fspec_t fspec = *orig_fspec;
442      char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
443      int flen;
444      int minlen;
445
446      packet = prom_get_netinfo();
447      if (!packet)
448           goto out;
449
450      /*
451       * First, try to match on mac address with the hardware type
452       * prepended.
453       */
454
455      /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
456      fspec.file = malloc(packet->hlen * 3 + 2 + 6);
457      if (!fspec.file)
458           goto out;
459
460      sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
461      strcat(fspec.file, prom_get_mac(packet));
462
463      rc = load_config_file(&fspec);
464      if (rc)
465           goto out;
466
467      /*
468       * Now try to match on IP.
469       */
470      /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
471      sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
472
473      for (flen = strlen(fspec.file),
474           minlen = strlen(cfgpath); flen > minlen; flen--) {
475           rc = load_config_file(&fspec);
476           if (rc)
477                goto out;
478           /* Chop one digit off the end, try again */
479           fspec.file[flen - 1] = '\0';
480      }
481
482  out:
483      if (rc) /* modify original only on success */
484           orig_fspec->file = fspec.file;
485      else
486           free(fspec.file);
487      return rc;
488 }
489
490 void maintabfunc (void)
491 {
492      if (useconf) {
493           cfg_print_images();
494           prom_printf("boot: %s", cbuff);
495      }
496 }
497
498 void
499 word_split(char **linep, char **paramsp)
500 {
501      char *p;
502
503      *paramsp = 0;
504      p = *linep;
505      if (p == 0)
506           return;
507      while (*p == ' ')
508           ++p;
509      if (*p == 0) {
510           *linep = 0;
511           return;
512      }
513      *linep = p;
514      while (*p != 0 && *p != ' ')
515           ++p;
516      while (*p == ' ')
517           *p++ = 0;
518      if (*p != 0)
519           *paramsp = p;
520 }
521
522 char *
523 make_params(char *label, char *params)
524 {
525      char *p, *q;
526      static char buffer[2048];
527
528      q = buffer;
529      *q = 0;
530
531      p = cfg_get_strg(label, "literal");
532      if (p) {
533           strcpy(q, p);
534           q = strchr(q, 0);
535           if (params) {
536                if (*p)
537                     *q++ = ' ';
538                strcpy(q, params);
539           }
540           return buffer;
541      }
542
543      p = cfg_get_strg(label, "root");
544      if (p) {
545           strcpy (q, "root=");
546           strcpy (q + 5, p);
547           q = strchr (q, 0);
548           *q++ = ' ';
549      }
550      if (cfg_get_flag(label, "read-only")) {
551           strcpy (q, "ro ");
552           q += 3;
553      }
554      if (cfg_get_flag(label, "read-write")) {
555           strcpy (q, "rw ");
556           q += 3;
557      }
558      p = cfg_get_strg(label, "ramdisk");
559      if (p) {
560           strcpy (q, "ramdisk=");
561           strcpy (q + 8, p);
562           q = strchr (q, 0);
563           *q++ = ' ';
564      }
565      p = cfg_get_strg(label, "initrd-size");
566      if (p) {
567           strcpy (q, "ramdisk_size=");
568           strcpy (q + 13, p);
569           q = strchr (q, 0);
570           *q++ = ' ';
571      }
572      if (cfg_get_flag(label, "novideo")) {
573           strcpy (q, "video=ofonly");
574           q = strchr (q, 0);
575           *q++ = ' ';
576      }
577      p = cfg_get_strg (label, "append");
578      if (p) {
579           strcpy (q, p);
580           q = strchr (q, 0);
581           *q++ = ' ';
582      }
583      *q = 0;
584      pause_after = cfg_get_flag (label, "pause-after");
585      p = cfg_get_strg(label, "pause-message");
586      if (p)
587           pause_message = p;
588      if (params)
589           strcpy(q, params);
590
591      return buffer;
592 }
593
594 void check_password(char *str)
595 {
596      int i;
597
598      prom_printf("\n%s", str);
599      for (i = 0; i < 3; i++) {
600           prom_printf ("\nPassword: ");
601           passwdbuff[0] = 0;
602           cmdedit ((void (*)(void)) 0, 1);
603           prom_printf ("\n");
604 #ifdef USE_MD5_PASSWORDS
605           if (!strncmp (password, "$1$", 3)) {
606                if (!check_md5_password(passwdbuff, password))
607                     return;
608           }
609           else if (!strcmp (password, passwdbuff))
610                return;
611 #else /* !MD5 */
612           if (!strcmp (password, passwdbuff))
613                return;
614 #endif /* USE_MD5_PASSWORDS */
615           if (i < 2) {
616                prom_sleep(1);
617                prom_printf ("Incorrect password.  Try again.");
618           }
619      }
620      prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
621                  "        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n"
622                  "                ||----w |\n                ||     ||\n");
623      prom_sleep(4);
624      prom_interpret("reset-all");
625 }
626
627 int get_params(struct boot_param_t* params)
628 {
629      int defpart;
630      char *defdevice = 0;
631      char defdevice_bak[1024];
632      char *p, *q, *endp;
633      int c, n;
634      char *imagename = 0, *label;
635      int timeout = -1;
636      int beg = 0, end;
637      int singlekey = 0;
638      int restricted = 0;
639      static int first = 1;
640      static char imagepath[1024];
641      static char initrdpath[1024];
642      static char manualinitrd[1024];
643      static int definitrd = 1, hasarg = 0;
644
645      pause_after = 0;
646      memset(params, 0, sizeof(*params));
647      params->args = "";
648      params->kernel.part = -1;
649      params->rd.part = -1;
650      defpart = boot.part;
651
652      cmdinit();
653
654      if (first && !fw_reboot_cnt) {
655           first = 0;
656           imagename = bootargs;
657           word_split(&imagename, &params->args);
658           timeout = DEFAULT_TIMEOUT;
659           if (imagename) {
660                prom_printf("Default supplied on the command line: %s ", imagename);
661                if (params->args)
662                     prom_printf("%s", params->args);
663                prom_printf("\n");
664           }
665           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
666                timeout = simple_strtol(q, NULL, 0);
667      }
668
669      /* If this is a reboot due to FW detecting CAS changes then 
670       * set timeout to 1.  The last kernel booted will be booted 
671       * again automatically.  It should seem seamless to the user
672      */
673      if (fw_reboot_cnt) 
674           timeout = 1;
675
676      prom_printf("boot: ");
677      c = -1;
678      if (timeout != -1) {
679           beg = prom_getms();
680           if (timeout > 0) {
681                end = beg + 100 * timeout;
682                do {
683                     c = prom_nbgetchar();
684                } while (c == -1 && prom_getms() <= end);
685           }
686           if (c == -1)
687                c = '\n';
688           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
689                cbuff[0] = c;
690                cbuff[1] = 0;
691           }
692      }
693
694      if (c != -1 && c != '\n' && c != '\r') {
695           if (c == '\t') {
696                maintabfunc ();
697           }  else if (c >= ' ') {
698                cbuff[0] = c;
699                cbuff[1] = 0;
700                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
701                     imagename = cbuff;
702                     singlekey = 1;
703                     prom_printf("%s\n", cbuff);
704                }
705           }
706      }
707
708      if (c == '\n' || c == '\r') {
709           if (!imagename) {
710                if (bootoncelabel[0] != 0)
711                     imagename = bootoncelabel;
712                else if (bootlastlabel[0] != 0)
713                          imagename = bootlastlabel;
714                else
715                     imagename = cfg_get_default();
716           }
717           if (imagename)
718                prom_printf("%s", imagename);
719           if (params->args)
720                prom_printf(" %s", params->args);
721           prom_printf("\n");
722      } else if (!singlekey) {
723           cmdedit(maintabfunc, 0);
724           prom_printf("\n");
725           strcpy(given_bootargs, cbuff);
726           given_bootargs_by_user = 1;
727           imagename = cbuff;
728           word_split(&imagename, &params->args);
729      }
730
731      /* initrd setup via cmd console */
732      /* first, check if the user uses it with some label */
733      if (!strncmp(params->args, "initrd=", 7)) {
734          DEBUG_F("params->args: %s\n", params->args);
735          definitrd = 0;
736      }
737      /* after, check if there is the 'initrd=' in the imagename string */
738      if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
739
740          /* return the value of definitrd to 1 */
741          if (!definitrd)
742              definitrd = 1;
743
744          /* args = "initrd=blah" */
745          char *args = NULL;
746
747          if (params->args) {
748             args = params->args;
749             params->args = NULL;
750             hasarg = 1;
751          } else
752             args = imagename;
753
754          if (strlen(args)){
755              /* copy the string after the '=' to manualinitrd */
756              strcpy(manualinitrd, args+7);
757              definitrd = 0;
758              prom_printf("New initrd file specified: %s\n", manualinitrd);
759          } else {
760              prom_printf("ERROR: no initrd specified!\n");
761              return 0;
762          }
763
764          /* set imagename with the default values of the config file */
765          if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
766              imagename = cfg_get_default();
767          else
768              imagename = cfg_get_default();
769      }
770
771      /* chrp gets this wrong, force it -- Cort */
772      if ( useconf && (!imagename || imagename[0] == 0 ))
773           imagename = cfg_get_default();
774
775      /* write the imagename out so it can be reused on reboot if necessary */
776      prom_set_options("boot-last-label", imagename, strlen(imagename));
777
778      label = 0;
779      defdevice = boot.dev;
780
781      strcpy(defdevice_bak,defdevice);
782
783      if (useconf) {
784           defdevice = cfg_get_strg(0, "device");
785           p = cfg_get_strg(0, "partition");
786           if (p) {
787                n = simple_strtol(p, &endp, 10);
788                if (endp != p && *endp == 0)
789                     defpart = n;
790           }
791           p = cfg_get_strg(0, "pause-message");
792           if (p)
793                pause_message = p;
794           if (cfg_get_flag(0, "restricted"))
795                restricted = 1;
796           p = cfg_get_strg(imagename, "image");
797           if (p && *p) {
798                label = imagename;
799                imagename = p;
800                defdevice = cfg_get_strg(label, "device");
801                if(!defdevice) defdevice=boot.dev;
802                p = cfg_get_strg(label, "partition");
803                if (p) {
804                     n = simple_strtol(p, &endp, 10);
805                     if (endp != p && *endp == 0)
806                          defpart = n;
807                }
808                if (cfg_get_flag(label, "restricted"))
809                     restricted = 1;
810                if (label) {
811                     if (params->args && password && restricted)
812                          check_password ("To specify arguments for this image "
813                                          "you must enter the password.");
814                     else if (password && !restricted)
815                          check_password ("This image is restricted.");
816                }
817                params->args = make_params(label, params->args);
818           }
819      }
820
821      if (!strcmp (imagename, "help")) {
822           /* FIXME: defdevice shouldn't need to be reset all over the place */
823           if(!defdevice) defdevice = boot.dev;
824           prom_printf(
825                "\nPress the tab key for a list of defined images.\n"
826                "The label marked with a \"*\" is is the default image, "
827                "press <return> to boot it.\n\n"
828                "To boot any other label simply type its name and press <return>.\n\n"
829                "To boot a kernel image which is not defined in the yaboot configuration \n"
830                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
831                "\"device:\" is the OpenFirmware device path to the disk the image \n"
832                "resides on, and \"partno\" is the partition number the image resides on.\n"
833                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
834                "device, if you only specify a filename you should not start it with a \",\"\n\n"
835            "To boot a alternative initrd file rather than specified in the yaboot\n"
836            "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
837            "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
838            "kernel image. You can, also, specify a different initrd file to any other\n"
839            "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
840            "and the specified initrd file will be loaded.\n\n"
841                "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
842                "its device, partno and path, on Open Firmware Prompt:\n"
843                "boot conf=device:partno,/path/to/configfile\n."
844                "To reload the config file or load a new one, use the \"conf\" command\n"
845                "on Yaboot's prompt:\n"
846                "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
847                "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
848                "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
849
850           return 0;
851      }
852
853      if (!strcmp (imagename, "halt")) {
854           if (password)
855                check_password ("Restricted command.");
856           prom_pause();
857           return 0;
858      }
859      if (!strcmp (imagename, "bye")) {
860           if (password) {
861                check_password ("Restricted command.");
862                return 1;
863           }
864           return 1;
865      }
866
867      if (!strncmp (imagename, "conf", 4)) {
868
869          // imagename = "conf file=blah dev=bleh part=blih"
870          DEBUG_F("Loading user-specified config file: %s\n",imagename);
871          if (password) {
872              check_password ("Restricted command.");
873              return 1;
874          }
875
876          // args= "file=blah dev=bleh part=blih"
877          char *args = params->args;
878
879          if (strlen(args)){
880
881             // set a pointer to the first space in args
882             char *space = strchr(args,' ');
883
884             int loop = 3;
885             while (loop > 0){
886                 char temp[1024] = "0";
887
888                 // copy next argument to temp
889                 strncpy(temp, args, space-args);
890
891                 // parse temp and set boot arguments
892                 if (!strncmp (temp, "file=", 5)){
893                    DEBUG_F("conf file: %s\n", temp+5);
894                    strcpy(boot.file, temp+5);
895                 } else if (!strncmp (temp, "device=", 7)){
896                    DEBUG_F("conf device: %s\n", temp+7);
897                    strcpy(boot.dev, temp+7);
898                 } else if (!strncmp (temp, "partition=", 10)){
899                    DEBUG_F("conf partition: %s\n", temp+10);
900                    boot.part=simple_strtol(temp+10,NULL,10);
901                 } else
902                    space = NULL;
903
904                 // set the pointer to the next space in args;
905                 // set the loop control variable
906                 if (strlen(space)>1){
907                     // Go to the next argument
908                     args = space+1;
909
910                     loop--;
911                     if (strchr(args,' ') == NULL)
912                         space = &args[strlen(args)];
913                     else
914                         space = strchr(args,' ');
915                 } else {
916                     loop = -1;
917                     space = NULL;
918                 }
919             }
920
921             prom_printf("Loading config file...\n");
922             useconf = load_config_file(&boot);
923             if (useconf > 0){
924                 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
925                    timeout = simple_strtol(q, NULL, 0);
926             } else {
927                prom_printf("Restoring default values.\n");
928                strcpy(boot.file,"");
929                strcpy(boot.dev, defdevice_bak);
930                boot.part = defpart;
931             }
932
933          } else {
934              prom_printf("Current configuration:\n");
935              prom_printf("device: %s\n", boot.dev);
936              if (boot.part < 0)
937                  prom_printf("partition: auto\n");
938              else
939                  prom_printf("partition: %d\n", boot.part);
940              if (strlen(boot.file))
941                  prom_printf("file: %s\n", boot.file);
942              else
943                  prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
944          }
945
946          imagename = "\0";
947          params->args = "\0";
948
949          return 0;
950      }
951
952      if (imagename[0] == '$') {
953           /* forth command string */
954           if (password)
955                check_password ("OpenFirmware commands are restricted.");
956           prom_interpret(imagename+1);
957           return 0;
958      }
959
960      strncpy(imagepath, imagename, 1024);
961
962      if (!label && password)
963           check_password ("To boot a custom image you must enter the password.");
964
965      params->kernel = boot; /* Copy all the original paramters */
966      if (!parse_device_path(imagepath, defdevice, defpart,
967                             "/vmlinux", &params->kernel)) {
968           prom_printf("%s: Unable to parse\n", imagepath);
969           return 0;
970      }
971      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
972      if (useconf) {
973           p = cfg_get_strg(label, "initrd");
974           if (p && *p) {
975
976            /* check if user seted to use a initrd file from boot console */
977            if (!definitrd && p != manualinitrd) {
978                if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
979                    strcpy(initrdpath, "/");
980                    strcat(initrdpath, manualinitrd);
981                } else
982                    strncpy(initrdpath, manualinitrd, 1024);
983            } else
984                strncpy(initrdpath, p, 1024);
985
986                DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
987                params->rd = boot; /* Copy all the original paramters */
988                if (!parse_device_path(initrdpath, defdevice, defpart,
989                                       "/root.bin", &params->rd)) {
990                     prom_printf("%s: Unable to parse\n", imagepath);
991                     return 0;
992                }
993           }
994      }
995      return 0;
996 }
997
998 /* This is derived from quik core. To be changed to first parse the headers
999  * doing lazy-loading, and then claim the memory before loading the kernel
1000  * to it
1001  * We also need to add initrd support to this whole mecanism
1002  */
1003 void
1004 yaboot_text_ui(void)
1005 {
1006      struct boot_file_t file;
1007      int                        result;
1008      static struct boot_param_t params;
1009      void               *initrd_base;
1010      unsigned long      initrd_size;
1011      kernel_entry_t      kernel_entry;
1012      char*               loc=NULL;
1013      loadinfo_t          loadinfo;
1014      void                *initrd_more,*initrd_want;
1015      unsigned long       initrd_read;
1016
1017      loadinfo.load_loc = 0;
1018
1019      for (;;) {
1020           initrd_size = 0;
1021           initrd_base = 0;
1022
1023           if (get_params(&params))
1024                return;
1025           if (!params.kernel.file)
1026                continue;
1027
1028           prom_printf("Please wait, loading kernel...\n");
1029
1030           memset(&file, 0, sizeof(file));
1031
1032           if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1033               && params.kernel.file[0] != '\\') {
1034                loc=(char*)malloc(strlen(params.kernel.file)+3);
1035                if (!loc) {
1036                     prom_printf ("malloc error\n");
1037                     goto next;
1038                }
1039                strcpy(loc,boot.file);
1040                strcat(loc,params.kernel.file);
1041                free(params.kernel.file);
1042                params.kernel.file=loc;
1043           }
1044           result = open_file(&params.kernel, &file);
1045           if (result != FILE_ERR_OK) {
1046                prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1047                prom_perror(result, params.kernel.file);
1048                goto next;
1049           }
1050
1051           /* Read the Elf e_ident, e_type and e_machine fields to
1052            * determine Elf file type
1053            */
1054           if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1055                prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1056                file.fs->close(&file);
1057                memset(&file, 0, sizeof(file));
1058                goto next;
1059           }
1060
1061           if (is_elf32(&loadinfo)) {
1062                if (!load_elf32(&file, &loadinfo)) {
1063                     file.fs->close(&file);
1064                     memset(&file, 0, sizeof(file));
1065                     goto next;
1066                }
1067                prom_printf("   Elf32 kernel loaded...\n");
1068           } else if (is_elf64(&loadinfo)) {
1069                if (!load_elf64(&file, &loadinfo)) {
1070                     file.fs->close(&file);
1071                     memset(&file, 0, sizeof(file));
1072                     goto next;
1073                }
1074                prom_printf("   Elf64 kernel loaded...\n");
1075           } else {
1076                prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1077                file.fs->close(&file);
1078                memset(&file, 0, sizeof(file));
1079                goto next;
1080           }
1081           file.fs->close(&file);
1082           memset(&file, 0, sizeof(file));
1083
1084           /* If ramdisk, load it (only if booting a vmlinux).  For now, we
1085            * can't tell the size it will be so we claim an arbitrary amount
1086            * of 4Mb.
1087            */
1088           if (flat_vmlinux && params.rd.file) {
1089                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1090                   && params.kernel.file[0] != '\\')
1091                {
1092                     if (loc) free(loc);
1093                     loc=(char*)malloc(strlen(params.rd.file)+3);
1094                     if (!loc) {
1095                          prom_printf ("Malloc error\n");
1096                          goto next;
1097                     }
1098                     strcpy(loc,boot.file);
1099                     strcat(loc,params.rd.file);
1100                     free(params.rd.file);
1101                     params.rd.file=loc;
1102                }
1103                prom_printf("Loading ramdisk...\n");
1104                result = open_file(&params.rd, &file);
1105                if (result != FILE_ERR_OK) {
1106                     prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1107                     prom_perror(result, params.rd.file);
1108                }
1109                else {
1110 #define INITRD_CHUNKSIZE 0x100000
1111                     unsigned int len = INITRD_CHUNKSIZE;
1112
1113                     /* We add a bit to the actual size so the loop below doesn't think
1114                      * there is more to load.
1115                      */
1116                     if (file.fs->ino_size && file.fs->ino_size(&file) > 0)
1117                          len = file.fs->ino_size(&file) + 0x1000;
1118
1119                     initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0);
1120                     if (initrd_base == (void *)-1) {
1121                          prom_printf("Claim failed for initrd memory\n");
1122                          initrd_base = 0;
1123                     } else {
1124                          initrd_size = file.fs->read(&file, len, initrd_base);
1125                          if (initrd_size == 0)
1126                               initrd_base = 0;
1127                          initrd_read = initrd_size;
1128                          initrd_more = initrd_base;
1129                          while (initrd_read == len ) { /* need to read more? */
1130                               initrd_want = (void *)((unsigned long)initrd_more+len);
1131                               initrd_more = prom_claim(initrd_want, len, 0);
1132                               if (initrd_more != initrd_want) {
1133                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1134                                    prom_pause();
1135                                    break;
1136                               }
1137                               initrd_read = file.fs->read(&file, len, initrd_more);
1138                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
1139                               initrd_size += initrd_read;
1140                          }
1141                     }
1142                     file.fs->close(&file);
1143                     memset(&file, 0, sizeof(file));
1144                }
1145                if (initrd_base)
1146                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1147                                 initrd_base, initrd_size >> 10);
1148                else {
1149                     prom_printf("ramdisk load failed !\n");
1150                     prom_pause();
1151                }
1152           }
1153
1154           DEBUG_F("setting kernel args to: %s\n", params.args);
1155           prom_setargs(params.args);
1156           DEBUG_F("flushing icache...");
1157           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1158           DEBUG_F(" done\n");
1159
1160           /* compute the kernel's entry point. */
1161           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1162
1163           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1164           DEBUG_F("kernel: arg1 = %p,\n"
1165                   "        arg2 = 0x%08lx,\n"
1166                   "        prom = %p,\n"
1167                   "        arg4 = %d,\n"
1168                   "        arg5 = %d\n\n",
1169                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1170
1171           DEBUG_F("Entering kernel...\n");
1172
1173           prom_print_available();
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  */