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