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