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