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