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