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