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