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