yaboot-1.3.17
[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 #define MESSAGE_FILE_MAX        2048
62
63 #ifdef USE_MD5_PASSWORDS
64 #include "md5.h"
65 #endif /* USE_MD5_PASSWORDS */
66
67 /* align addr on a size boundry - adjust address up if needed -- Cort */
68 #define _ALIGN(addr,size)       (((addr)+size-1)&(~(size-1)))
69
70 /* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at.
71  * These are used to determine whether we are booting a vmlinux, in
72  * which case, it will be loaded at KERNELADDR.  Otherwise (eg zImage),
73  * we load the binary where it was linked at (ie, e_entry field in
74  * the ELF header).
75  */
76 #define KERNEL_LINK_ADDR_PPC32  0xC0000000UL
77 #define KERNEL_LINK_ADDR_PPC64  0xC000000000000000ULL
78
79 typedef struct {
80      union {
81           Elf32_Ehdr  elf32hdr;
82           Elf64_Ehdr  elf64hdr;
83      } elf;
84      void*          base;
85      unsigned long   memsize;
86      unsigned long   filesize;
87      unsigned long   offset;
88      unsigned long   load_loc;
89      unsigned long   entry;
90 } loadinfo_t;
91
92 typedef void (*kernel_entry_t)( void *,
93                                 unsigned long,
94                                 prom_entry,
95                                 unsigned long,
96                                 unsigned long );
97
98 /* Imported functions */
99 extern unsigned long reloc_offset(void);
100 extern long flush_icache_range(unsigned long start, unsigned long stop);
101
102 /* Exported functions */
103 int     yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
104
105 /* Local functions */
106 static int      yaboot_main(void);
107 static int      is_elf32(loadinfo_t *loadinfo);
108 static int      is_elf64(loadinfo_t *loadinfo);
109 static int      load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
110 static int      load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
111 static void     setup_display(void);
112
113 /* Locals & globals */
114
115 int useconf = 0;
116 char bootdevice[BOOTDEVSZ];
117 char bootoncelabel[1024];
118 char bootargs[1024];
119 char bootlastlabel[BOOTLASTSZ] = {0};
120 char fw_nbr_reboots[FW_NBR_REBOOTSZ] = {0};
121 long  fw_reboot_cnt = 0;
122 char *password = NULL;
123 struct boot_fspec_t boot;
124 int _machine = _MACH_Pmac;
125 int flat_vmlinux;
126
127 #ifdef CONFIG_COLOR_TEXT
128
129 /* Color values for text ui */
130 static struct ansi_color_t {
131      char*      name;
132      int        index;
133      int        value;
134 } ansi_color_table[] = {
135      { "black",         2, 30 },
136      { "blue",          0, 31 },
137      { "green",         0, 32 },
138      { "cyan",          0, 33 },
139      { "red",           0, 34 },
140      { "purple",                0, 35 },
141      { "brown",         0, 36 },
142      { "light-gray",    0, 37 },
143      { "dark-gray",             1, 30 },
144      { "light-blue",            1, 31 },
145      { "light-green",   1, 32 },
146      { "light-cyan",            1, 33 },
147      { "light-red",             1, 34 },
148      { "light-purple",  1, 35 },
149      { "yellow",                1, 36 },
150      { "white",         1, 37 },
151      { NULL,                    0, 0 },
152 };
153
154 /* Default colors for text ui */
155 int fgcolor = 15;
156 int bgcolor = 0;
157 #endif /* CONFIG_COLOR_TEXT */
158
159 static int pause_after;
160 static char *pause_message = "Type go<return> to continue.\n";
161 static char given_bootargs[1024];
162 static int given_bootargs_by_user = 0;
163
164 extern unsigned char linux_logo_red[];
165 extern unsigned char linux_logo_green[];
166 extern unsigned char linux_logo_blue[];
167
168 #define DEFAULT_TIMEOUT         -1
169
170 int
171 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
172 {
173      int result;
174      void* malloc_base = NULL;
175      prom_handle root;
176
177      /* Initialize OF interface */
178      prom_init ((prom_entry) r5);
179
180      prom_print_available();
181
182      /* Allocate some memory for malloc'ator */
183      malloc_base = prom_claim_chunk_top(MALLOCSIZE, 0);
184      if (malloc_base == (void *)-1) {
185           prom_printf("Can't claim malloc buffer of %d bytes\n",
186                       MALLOCSIZE);
187           return -1;
188      }
189      malloc_init(malloc_base, MALLOCSIZE);
190      DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
191              malloc_base, MALLOCSIZE);
192
193      /* A few useless DEBUG_F's */
194      DEBUG_F("reloc_offset :  %ld         (should be 0)\n", reloc_offset());
195      DEBUG_F("linked at    :  0x%08x\n", TEXTADDR);
196
197      /* ask the OF info if we're a chrp or pmac */
198      /* we need to set _machine before calling finish_device_tree */
199      root = prom_finddevice("/");
200      if (root != 0) {
201           static char model[256];
202           if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
203               !strncmp("bplan", model, 5))
204                _machine = _MACH_bplan;
205           else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
206               !strncmp("chrp", model, 4))
207                _machine = _MACH_chrp;
208           else if (prom_getprop(root, "compatible", model, 256 ) > 0 &&
209                    strstr(model, "ibm,powernv"))
210                _machine = _MACH_chrp;
211           else {
212                if (prom_getprop(root, "model", model, 256 ) > 0 &&
213                    !strncmp(model, "IBM", 3))
214                     _machine = _MACH_chrp;
215           }
216      }
217
218      DEBUG_F("Running on _machine = %d\n", _machine);
219      DEBUG_SLEEP;
220
221      /* Call out main */
222      result = yaboot_main();
223
224      /* Get rid of malloc pool */
225      malloc_dispose();
226      prom_release(malloc_base, MALLOCSIZE);
227      DEBUG_F("Malloc buffer released. Exiting with code %d\n",
228              result);
229
230      /* Return to OF */
231      prom_exit();
232
233      return result;
234
235 }
236
237 #ifdef CONFIG_COLOR_TEXT
238 /*
239  * Validify color for text ui
240  */
241 static int
242 check_color_text_ui(char *color)
243 {
244      int i = 0;
245      while(ansi_color_table[i].name) {
246           if (!strcmp(color, ansi_color_table[i].name))
247                return i;
248           i++;
249      }
250      return -1;
251 }
252 #endif /* CONFIG_COLOR_TEXT */
253
254
255 void print_message_file(char *filename)
256 {
257      char *msg = NULL;
258      char *p, *endp;
259      char *defdev = boot.dev;
260      int defpart = boot.part;
261      char msgpath[1024];
262      int opened = 0;
263      int result = 0;
264      int n;
265      struct boot_file_t file;
266      struct boot_fspec_t msgfile;
267
268      defdev = cfg_get_strg(0, "device");
269      if (!defdev)
270           defdev = boot.dev;
271      p = cfg_get_strg(0, "partition");
272           if (p) {
273                n = simple_strtol(p, &endp, 10);
274                if (endp != p && *endp == 0)
275                     defpart = n;
276           }
277
278      strncpy(msgpath, filename, sizeof(msgpath));
279      msgfile = boot; /* Copy all the original paramters */
280      if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
281           prom_printf("%s: Unable to parse\n", msgpath);
282           goto done;
283      }
284
285      result = open_file(&msgfile, &file);
286      if (result != FILE_ERR_OK) {
287           prom_printf("%s:%d,", msgfile.dev, msgfile.part);
288           prom_perror(result, msgfile.file);
289           goto done;
290      } else
291           opened = 1;
292
293      msg = malloc(MESSAGE_FILE_MAX + 1);
294      if (!msg)
295           goto done;
296      else
297           memset(msg, 0, MESSAGE_FILE_MAX + 1);
298
299      if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
300           goto done;
301      else
302           prom_printf("%s", msg);
303
304 done:
305      if (opened)
306           file.fs->close(&file);
307      if (msg)
308           free(msg);
309 }
310
311 /* Currently, the config file must be at the root of the filesystem.
312  * todo: recognize the full path to myself and use it to load the
313  * config file. Handle the "\\" (blessed system folder)
314  */
315 static int
316 load_config_file(struct boot_fspec_t *fspec)
317 {
318      char *conf_file = NULL, *p;
319      struct boot_file_t file;
320      int sz, opened = 0, result = 0;
321
322      /* Allocate a buffer for the config file */
323      conf_file = malloc(CONFIG_FILE_MAX);
324      if (!conf_file) {
325           prom_printf("Can't alloc config file buffer\n");
326           goto bail;
327      }
328
329      /* Open it */
330      result = open_file(fspec, &file);
331      if (result != FILE_ERR_OK) {
332           prom_printf("%s:%d,", fspec->dev, fspec->part);
333           prom_perror(result, fspec->file);
334           prom_printf("Can't open config file\n");
335           goto bail;
336      }
337      opened = 1;
338
339      /* Read it */
340      sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
341      if (sz <= 0) {
342           prom_printf("Error, can't read config file\n");
343           goto bail;
344      }
345      prom_printf("Config file read, %d bytes\n", sz);
346
347      /* Close the file */
348      if (opened)
349           file.fs->close(&file);
350      opened = 0;
351
352      /* Call the parsing code in cfg.c */
353      if (cfg_parse(fspec->file, conf_file, sz) < 0) {
354           prom_printf ("Syntax error or read error config\n");
355           goto bail;
356      }
357
358      /* 
359       * set the default cf_option to label that has the same MAC addr 
360       * it only works if there is a label with the MAC addr on yaboot.conf
361       */
362      if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
363          /* change the variable bellow to get the MAC dinamicaly */
364          char * macaddr = NULL;
365          int default_mac = 0;
366
367          macaddr = prom_get_mac(prom_get_netinfo());
368          default_mac = cfg_set_default_by_mac(macaddr);
369          if (default_mac >= 1) {
370             prom_printf("Default label was changed to macaddr label.\n");
371          }
372      }
373
374      DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
375
376      /* Now, we do the initialisations stored in the config file */
377      p = cfg_get_strg(0, "init-code");
378      if (p)
379           prom_interpret(p);
380
381      password = cfg_get_strg(0, "password");
382
383 #ifdef CONFIG_COLOR_TEXT
384      p = cfg_get_strg(0, "fgcolor");
385      if (p) {
386           DEBUG_F("fgcolor=%s\n", p);
387           fgcolor = check_color_text_ui(p);
388           if (fgcolor == -1) {
389                prom_printf("Invalid fgcolor: \"%s\".\n", p);
390           }
391      }
392      p = cfg_get_strg(0, "bgcolor");
393      if (p) {
394           DEBUG_F("bgcolor=%s\n", p);
395           bgcolor = check_color_text_ui(p);
396           if (bgcolor == -1)
397                prom_printf("Invalid bgcolor: \"%s\".\n", p);
398      }
399      if (bgcolor >= 0) {
400           char temp[64];
401           sprintf(temp, "%x to background-color", bgcolor);
402           prom_interpret(temp);
403 #if !DEBUG
404           prom_printf("\xc");
405 #endif /* !DEBUG */
406      }
407      if (fgcolor >= 0) {
408           char temp[64];
409           sprintf(temp, "%x to foreground-color", fgcolor);
410           prom_interpret(temp);
411      }
412 #endif /* CONFIG_COLOR_TEXT */
413
414      p = cfg_get_strg(0, "init-message");
415      if (p)
416           prom_printf("%s\n", p);
417
418      p = cfg_get_strg(0, "message");
419      if (p)
420           print_message_file(p);
421
422      result = 1;
423
424 bail:
425
426      if (opened)
427           file.fs->close(&file);
428
429      if (conf_file)
430           free(conf_file);
431
432      return result;
433 }
434
435 /*
436  * Search for config file by MAC address, then by IP address.
437  * Basically copying pxelinux's algorithm.
438  * http://syslinux.zytor.com/pxe.php#config
439  */
440 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
441 {
442      struct bootp_packet *packet;
443      int rc = 0;
444      struct boot_fspec_t fspec = *orig_fspec;
445      char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
446      int flen;
447      int minlen;
448
449      packet = prom_get_netinfo();
450      if (!packet)
451           goto out;
452
453      /*
454       * First, try to match on mac address with the hardware type
455       * prepended.
456       */
457
458      /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
459      fspec.file = malloc(packet->hlen * 3 + 2 + 6);
460      if (!fspec.file)
461           goto out;
462
463      sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
464      strcat(fspec.file, prom_get_mac(packet));
465
466      rc = load_config_file(&fspec);
467      if (rc)
468           goto out;
469
470      /*
471       * Now try to match on IP.
472       */
473      /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
474      sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
475
476      for (flen = strlen(fspec.file),
477           minlen = strlen(cfgpath); flen > minlen; flen--) {
478           rc = load_config_file(&fspec);
479           if (rc)
480                goto out;
481           /* Chop one digit off the end, try again */
482           fspec.file[flen - 1] = '\0';
483      }
484
485  out:
486      if (rc) /* modify original only on success */
487           orig_fspec->file = fspec.file;
488      else
489           free(fspec.file);
490      return rc;
491 }
492
493 void maintabfunc (void)
494 {
495      if (useconf) {
496           cfg_print_images();
497           prom_printf("boot: %s", cbuff);
498      }
499 }
500
501 void
502 word_split(char **linep, char **paramsp)
503 {
504      char *p;
505
506      *paramsp = 0;
507      p = *linep;
508      if (p == 0)
509           return;
510      while (*p == ' ')
511           ++p;
512      if (*p == 0) {
513           *linep = 0;
514           return;
515      }
516      *linep = p;
517      while (*p != 0 && *p != ' ')
518           ++p;
519      while (*p == ' ')
520           *p++ = 0;
521      if (*p != 0)
522           *paramsp = p;
523 }
524
525 char *
526 make_params(char *label, char *params)
527 {
528      char *p, *q;
529      static char buffer[2048];
530
531      q = buffer;
532      *q = 0;
533
534      p = cfg_get_strg(label, "literal");
535      if (p) {
536           strcpy(q, p);
537           q = strchr(q, 0);
538           if (params) {
539                if (*p)
540                     *q++ = ' ';
541                strcpy(q, params);
542           }
543           return buffer;
544      }
545
546      p = cfg_get_strg(label, "root");
547      if (p) {
548           strcpy (q, "root=");
549           strcpy (q + 5, p);
550           q = strchr (q, 0);
551           *q++ = ' ';
552      }
553      if (cfg_get_flag(label, "read-only")) {
554           strcpy (q, "ro ");
555           q += 3;
556      }
557      if (cfg_get_flag(label, "read-write")) {
558           strcpy (q, "rw ");
559           q += 3;
560      }
561      p = cfg_get_strg(label, "ramdisk");
562      if (p) {
563           strcpy (q, "ramdisk=");
564           strcpy (q + 8, p);
565           q = strchr (q, 0);
566           *q++ = ' ';
567      }
568      p = cfg_get_strg(label, "initrd-size");
569      if (p) {
570           strcpy (q, "ramdisk_size=");
571           strcpy (q + 13, p);
572           q = strchr (q, 0);
573           *q++ = ' ';
574      }
575      if (cfg_get_flag(label, "novideo")) {
576           strcpy (q, "video=ofonly");
577           q = strchr (q, 0);
578           *q++ = ' ';
579      }
580      p = cfg_get_strg (label, "append");
581      if (p) {
582           strcpy (q, p);
583           q = strchr (q, 0);
584           *q++ = ' ';
585      }
586      *q = 0;
587      pause_after = cfg_get_flag (label, "pause-after");
588      p = cfg_get_strg(label, "pause-message");
589      if (p)
590           pause_message = p;
591      if (params)
592           strcpy(q, params);
593
594      return buffer;
595 }
596
597 void check_password(char *str)
598 {
599      int i;
600
601      prom_printf("\n%s", str);
602      for (i = 0; i < 3; i++) {
603           prom_printf ("\nPassword: ");
604           passwdbuff[0] = 0;
605           cmdedit ((void (*)(void)) 0, 1);
606           prom_printf ("\n");
607 #ifdef USE_MD5_PASSWORDS
608           if (!strncmp (password, "$1$", 3)) {
609                if (!check_md5_password((unsigned char*)passwdbuff, (unsigned char*)password))
610                     return;
611           }
612           else if (!strcmp (password, passwdbuff))
613                return;
614 #else /* !MD5 */
615           if (!strcmp (password, passwdbuff))
616                return;
617 #endif /* USE_MD5_PASSWORDS */
618           if (i < 2) {
619                prom_sleep(1);
620                prom_printf ("Incorrect password.  Try again.");
621           }
622      }
623      prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
624                  "        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n"
625                  "                ||----w |\n                ||     ||\n");
626      prom_sleep(4);
627      prom_interpret("reset-all");
628 }
629
630 int get_params(struct boot_param_t* params)
631 {
632      int defpart;
633      char *defdevice = 0;
634      char defdevice_bak[1024];
635      char *p, *q, *endp;
636      int c, n;
637      char *imagename = 0, *label;
638      int timeout = -1;
639      int beg = 0, end;
640      int singlekey = 0;
641      int restricted = 0;
642      static int first = 1;
643      static char imagepath[1024];
644      static char initrdpath[1024];
645      static char manualinitrd[1024];
646      static int definitrd = 1, hasarg = 0;
647
648      pause_after = 0;
649      memset(params, 0, sizeof(*params));
650      params->args = "";
651      params->kernel.part = -1;
652      params->rd.part = -1;
653      defpart = boot.part;
654
655      cmdinit();
656
657      if (first && !fw_reboot_cnt) {
658           first = 0;
659           imagename = bootargs;
660           word_split(&imagename, &params->args);
661           timeout = DEFAULT_TIMEOUT;
662           if (imagename) {
663                prom_printf("Default supplied on the command line: %s ", imagename);
664                if (params->args)
665                     prom_printf("%s", params->args);
666                prom_printf("\n");
667           }
668           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
669                timeout = simple_strtol(q, NULL, 0);
670      }
671
672      /* If this is a reboot due to FW detecting CAS changes then 
673       * set timeout to 1.  The last kernel booted will be booted 
674       * again automatically.  It should seem seamless to the user
675      */
676      if (fw_reboot_cnt) 
677           timeout = 1;
678
679      prom_printf("boot: ");
680      c = -1;
681      if (timeout != -1) {
682           beg = prom_getms();
683           if (timeout > 0) {
684                end = beg + 100 * timeout;
685                do {
686                     c = prom_nbgetchar();
687                } while (c == -1 && prom_getms() <= end);
688           }
689           if (c == -1)
690                c = '\n';
691           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
692                cbuff[0] = c;
693                cbuff[1] = 0;
694           }
695      }
696
697      if (c != -1 && c != '\n' && c != '\r') {
698           if (c == '\t') {
699                maintabfunc ();
700           }  else if (c >= ' ') {
701                cbuff[0] = c;
702                cbuff[1] = 0;
703                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
704                     imagename = cbuff;
705                     singlekey = 1;
706                     prom_printf("%s\n", cbuff);
707                }
708           }
709      }
710
711      if (c == '\n' || c == '\r') {
712           if (!imagename) {
713                if (bootoncelabel[0] != 0)
714                     imagename = bootoncelabel;
715                else if (bootlastlabel[0] != 0) {
716                     imagename = bootlastlabel;
717                     word_split(&imagename, &params->args);
718                } else
719                     imagename = cfg_get_default();
720           }
721           if (imagename)
722                prom_printf("%s", imagename);
723           if (params->args)
724                prom_printf(" %s", params->args);
725           prom_printf("\n");
726      } else if (!singlekey) {
727           cmdedit(maintabfunc, 0);
728           prom_printf("\n");
729           strcpy(given_bootargs, cbuff);
730           given_bootargs_by_user = 1;
731           imagename = cbuff;
732           word_split(&imagename, &params->args);
733      }
734
735      /* initrd setup via cmd console */
736      /* first, check if the user uses it with some label */
737      if (!strncmp(params->args, "initrd=", 7)) {
738          DEBUG_F("params->args: %s\n", params->args);
739          definitrd = 0;
740      }
741      /* after, check if there is the 'initrd=' in the imagename string */
742      if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
743
744          /* return the value of definitrd to 1 */
745          if (!definitrd)
746              definitrd = 1;
747
748          /* args = "initrd=blah" */
749          char *args = NULL;
750
751          if (params->args) {
752             args = params->args;
753             params->args = NULL;
754             hasarg = 1;
755          } else
756             args = imagename;
757
758          if (strlen(args)){
759              /* copy the string after the '=' to manualinitrd */
760              strcpy(manualinitrd, args+7);
761              definitrd = 0;
762              prom_printf("New initrd file specified: %s\n", manualinitrd);
763          } else {
764              prom_printf("ERROR: no initrd specified!\n");
765              return 0;
766          }
767
768          /* set imagename with the default values of the config file */
769          if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
770              imagename = cfg_get_default();
771          else
772              imagename = cfg_get_default();
773      }
774
775      /* chrp gets this wrong, force it -- Cort */
776      if ( useconf && (!imagename || imagename[0] == 0 ))
777           imagename = cfg_get_default();
778
779      /* write the imagename out so it can be reused on reboot if necessary */
780      strcpy(bootlastlabel, imagename);
781      if (params->args && params->args[0]) {
782           strcat(bootlastlabel, " ");
783           strcat(bootlastlabel, params->args);
784      }
785      prom_set_options("boot-last-label", bootlastlabel,
786                       strlen(bootlastlabel) + 1);
787
788      label = 0;
789      defdevice = boot.dev;
790
791      strcpy(defdevice_bak,defdevice);
792
793      if (useconf) {
794           defdevice = cfg_get_strg(0, "device");
795           p = cfg_get_strg(0, "partition");
796           if (p) {
797                n = simple_strtol(p, &endp, 10);
798                if (endp != p && *endp == 0)
799                     defpart = n;
800           }
801           p = cfg_get_strg(0, "pause-message");
802           if (p)
803                pause_message = p;
804           if (cfg_get_flag(0, "restricted"))
805                restricted = 1;
806           p = cfg_get_strg(imagename, "image");
807           if (p && *p) {
808                label = imagename;
809                imagename = p;
810                defdevice = cfg_get_strg(label, "device");
811                if(!defdevice) defdevice=boot.dev;
812                p = cfg_get_strg(label, "partition");
813                if (p) {
814                     n = simple_strtol(p, &endp, 10);
815                     if (endp != p && *endp == 0)
816                          defpart = n;
817                }
818                if (cfg_get_flag(label, "restricted"))
819                     restricted = 1;
820                if (label) {
821                     if (params->args && password && restricted)
822                          check_password ("To specify arguments for this image "
823                                          "you must enter the password.");
824                     else if (password && !restricted)
825                          check_password ("This image is restricted.");
826                }
827                params->args = make_params(label, params->args);
828           }
829      }
830
831      if (!strcmp (imagename, "help")) {
832           /* FIXME: defdevice shouldn't need to be reset all over the place */
833           if(!defdevice) defdevice = boot.dev;
834           prom_printf(
835                "\nPress the tab key for a list of defined images.\n"
836                "The label marked with a \"*\" is is the default image, "
837                "press <return> to boot it.\n\n"
838                "To boot any other label simply type its name and press <return>.\n\n"
839                "To boot a kernel image which is not defined in the yaboot configuration \n"
840                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
841                "\"device:\" is the OpenFirmware device path to the disk the image \n"
842                "resides on, and \"partno\" is the partition number the image resides on.\n"
843                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
844                "device, if you only specify a filename you should not start it with a \",\"\n\n"
845            "To boot a alternative initrd file rather than specified in the yaboot\n"
846            "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
847            "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
848            "kernel image. You can, also, specify a different initrd file to any other\n"
849            "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
850            "and the specified initrd file will be loaded.\n\n"
851                "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
852                "its device, partno and path, on Open Firmware Prompt:\n"
853                "boot conf=device:partno,/path/to/configfile\n."
854                "To reload the config file or load a new one, use the \"conf\" command\n"
855                "on Yaboot's prompt:\n"
856                "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
857                "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
858                "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
859
860           return 0;
861      }
862
863      if (!strcmp (imagename, "halt")) {
864           if (password)
865                check_password ("Restricted command.");
866           prom_pause();
867           return 0;
868      }
869      if (!strcmp (imagename, "bye")) {
870           if (password) {
871                check_password ("Restricted command.");
872                return 1;
873           }
874           return 1;
875      }
876
877      if (!strncmp (imagename, "conf", 4)) {
878
879          // imagename = "conf file=blah dev=bleh part=blih"
880          DEBUG_F("Loading user-specified config file: %s\n",imagename);
881          if (password) {
882              check_password ("Restricted command.");
883              return 1;
884          }
885
886          // args= "file=blah dev=bleh part=blih"
887          char *args = params->args;
888
889          if (strlen(args)){
890
891             // set a pointer to the first space in args
892             char *space = strchr(args,' ');
893
894             int loop = 3;
895             while (loop > 0){
896                 char temp[1024] = "0";
897
898                 // copy next argument to temp
899                 strncpy(temp, args, space-args);
900
901                 // parse temp and set boot arguments
902                 if (!strncmp (temp, "file=", 5)){
903                    DEBUG_F("conf file: %s\n", temp+5);
904                    strcpy(boot.file, temp+5);
905                 } else if (!strncmp (temp, "device=", 7)){
906                    DEBUG_F("conf device: %s\n", temp+7);
907                    strcpy(boot.dev, temp+7);
908                 } else if (!strncmp (temp, "partition=", 10)){
909                    DEBUG_F("conf partition: %s\n", temp+10);
910                    boot.part=simple_strtol(temp+10,NULL,10);
911                 } else
912                    space = NULL;
913
914                 // set the pointer to the next space in args;
915                 // set the loop control variable
916                 if (strlen(space)>1){
917                     // Go to the next argument
918                     args = space+1;
919
920                     loop--;
921                     if (strchr(args,' ') == NULL)
922                         space = &args[strlen(args)];
923                     else
924                         space = strchr(args,' ');
925                 } else {
926                     loop = -1;
927                     space = NULL;
928                 }
929             }
930
931             prom_printf("Loading config file...\n");
932             useconf = load_config_file(&boot);
933             if (useconf > 0){
934                 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
935                    timeout = simple_strtol(q, NULL, 0);
936             } else {
937                prom_printf("Restoring default values.\n");
938                strcpy(boot.file,"");
939                strcpy(boot.dev, defdevice_bak);
940                boot.part = defpart;
941             }
942
943          } else {
944              prom_printf("Current configuration:\n");
945              prom_printf("device: %s\n", boot.dev);
946              if (boot.part < 0)
947                  prom_printf("partition: auto\n");
948              else
949                  prom_printf("partition: %d\n", boot.part);
950              if (strlen(boot.file))
951                  prom_printf("file: %s\n", boot.file);
952              else
953                  prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
954          }
955
956          imagename = "\0";
957          params->args = "\0";
958
959          return 0;
960      }
961
962      if (imagename[0] == '$') {
963           /* forth command string */
964           if (password)
965                check_password ("OpenFirmware commands are restricted.");
966           prom_interpret(imagename+1);
967           return 0;
968      }
969
970      strncpy(imagepath, imagename, 1024);
971
972      if (!label && password)
973           check_password ("To boot a custom image you must enter the password.");
974
975      params->kernel = boot; /* Copy all the original paramters */
976      if (!parse_device_path(imagepath, defdevice, defpart,
977                             "/vmlinux", &params->kernel)) {
978           prom_printf("%s: Unable to parse\n", imagepath);
979           return 0;
980      }
981      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
982      if (useconf) {
983           p = cfg_get_strg(label, "initrd");
984           if (p && *p) {
985
986            /* check if user seted to use a initrd file from boot console */
987            if (!definitrd && p != manualinitrd) {
988                if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
989                    strcpy(initrdpath, "/");
990                    strcat(initrdpath, manualinitrd);
991                } else
992                    strncpy(initrdpath, manualinitrd, 1024);
993            } else
994                strncpy(initrdpath, p, 1024);
995
996                DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
997                params->rd = boot; /* Copy all the original paramters */
998                if (!parse_device_path(initrdpath, defdevice, defpart,
999                                       "/root.bin", &params->rd)) {
1000                     prom_printf("%s: Unable to parse\n", imagepath);
1001                     return 0;
1002                }
1003           }
1004      }
1005      return 0;
1006 }
1007
1008 /* This is derived from quik core. To be changed to first parse the headers
1009  * doing lazy-loading, and then claim the memory before loading the kernel
1010  * to it
1011  * We also need to add initrd support to this whole mecanism
1012  */
1013 void
1014 yaboot_text_ui(void)
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                     unsigned int len = INITRD_CHUNKSIZE;
1122
1123                     /* We add a bit to the actual size so the loop below doesn't think
1124                      * there is more to load.
1125                      */
1126                     if (file.fs->ino_size && file.fs->ino_size(&file) > 0)
1127                          len = file.fs->ino_size(&file) + 0x1000;
1128
1129                     initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0);
1130                     if (initrd_base == (void *)-1) {
1131                          prom_printf("Claim failed for initrd memory\n");
1132                          initrd_base = 0;
1133                     } else {
1134                          initrd_size = file.fs->read(&file, len, initrd_base);
1135                          if (initrd_size == 0)
1136                               initrd_base = 0;
1137                          initrd_read = initrd_size;
1138                          initrd_more = initrd_base;
1139                          while (initrd_read == len ) { /* need to read more? */
1140                               initrd_want = (void *)((unsigned long)initrd_more+len);
1141                               initrd_more = prom_claim(initrd_want, len, 0);
1142                               if (initrd_more != initrd_want) {
1143                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1144                                    prom_pause();
1145                                    break;
1146                               }
1147                               initrd_read = file.fs->read(&file, len, initrd_more);
1148                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
1149                               initrd_size += initrd_read;
1150                          }
1151                     }
1152                     file.fs->close(&file);
1153                     memset(&file, 0, sizeof(file));
1154                }
1155                if (initrd_base)
1156                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1157                                 initrd_base, initrd_size >> 10);
1158                else {
1159                     prom_printf("ramdisk load failed !\n");
1160                     prom_pause();
1161                }
1162           }
1163
1164           DEBUG_F("setting kernel args to: %s\n", params.args);
1165           prom_setargs(params.args);
1166           DEBUG_F("flushing icache...");
1167           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1168           DEBUG_F(" done\n");
1169
1170           /* compute the kernel's entry point. */
1171           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1172
1173           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1174           DEBUG_F("kernel: arg1 = %p,\n"
1175                   "        arg2 = 0x%08lx,\n"
1176                   "        prom = %p,\n"
1177                   "        arg4 = %d,\n"
1178                   "        arg5 = %d\n\n",
1179                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1180
1181           DEBUG_F("Entering kernel...\n");
1182
1183           prom_print_available();
1184
1185           /* call the kernel with our stack. */
1186           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1187           continue;
1188      next:
1189           ; /* do nothing */
1190      }
1191 }
1192
1193 static int
1194 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1195 {
1196      int                        i;
1197      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1198      Elf32_Phdr         *p, *ph;
1199      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1200      unsigned long      loadaddr;
1201
1202      /* Read the rest of the Elf header... */
1203      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1204           prom_printf("\nCan't read Elf32 image header\n");
1205           goto bail;
1206      }
1207
1208      DEBUG_F("Elf32 header:\n");
1209      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1210      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1211      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1212      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1213      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1214      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1215      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1216      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1217      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1218      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1219
1220      loadinfo->entry = e->e_entry;
1221
1222      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1223      if (!ph) {
1224           prom_printf ("Malloc error\n");
1225           goto bail;
1226      }
1227
1228      /* Now, we read the section header */
1229      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1230           prom_printf ("seek error\n");
1231           goto bail;
1232      }
1233      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1234          sizeof(Elf32_Phdr) * e->e_phnum) {
1235           prom_printf ("read error\n");
1236           goto bail;
1237      }
1238
1239      /* Scan through the program header
1240       * HACK:  We must return the _memory size of the kernel image, not the
1241       *        file size (because we have to leave room before other boot
1242       *   infos. This code works as a side effect of the fact that
1243       *   we have one section and vaddr == p_paddr
1244       */
1245      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1246      p = ph;
1247      for (i = 0; i < e->e_phnum; ++i, ++p) {
1248           if (p->p_type != PT_LOAD || p->p_offset == 0)
1249                continue;
1250           if (loadinfo->memsize == 0) {
1251                loadinfo->offset = p->p_offset;
1252                loadinfo->memsize = p->p_memsz;
1253                loadinfo->filesize = p->p_filesz;
1254                loadinfo->load_loc = p->p_vaddr;
1255           } else {
1256                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1257                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1258           }
1259      }
1260
1261      if (loadinfo->memsize == 0) {
1262           prom_printf("Can't find a loadable segment !\n");
1263           goto bail;
1264      }
1265
1266      /* leave some room (1Mb) for boot infos */
1267      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1268      /* Claim OF memory */
1269      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1270
1271      /* Determine whether we are trying to boot a vmlinux or some
1272       * other binary image (eg, zImage).  We load vmlinux's at
1273       * KERNELADDR and all other binaries at their e_entry value.
1274       */
1275      if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1276           flat_vmlinux = 1;
1277           loadaddr = KERNELADDR;
1278      } else {
1279           flat_vmlinux = 0;
1280           loadaddr = loadinfo->load_loc;
1281      }
1282
1283      loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1284      if (loadinfo->base == (void *)-1) {
1285           prom_printf("Claim error, can't allocate kernel memory\n");
1286           goto bail;
1287      }
1288
1289      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1290              loadinfo->base, loadinfo->memsize);
1291      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1292              loadaddr, loadinfo->memsize);
1293
1294      /* Load the program segments... */
1295      p = ph;
1296      for (i = 0; i < e->e_phnum; ++i, ++p) {
1297           unsigned long offset;
1298           if (p->p_type != PT_LOAD || p->p_offset == 0)
1299                continue;
1300
1301           /* Now, we skip to the image itself */
1302           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1303                prom_printf ("Seek error\n");
1304                prom_release(loadinfo->base, loadinfo->memsize);
1305                goto bail;
1306           }
1307           offset = p->p_vaddr - loadinfo->load_loc;
1308           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1309                prom_printf ("Read failed\n");
1310                prom_release(loadinfo->base, loadinfo->memsize);
1311                goto bail;
1312           }
1313      }
1314
1315      free(ph);
1316
1317      /* Return success at loading the Elf32 kernel */
1318      return 1;
1319
1320 bail:
1321      if (ph)
1322        free(ph);
1323      return 0;
1324 }
1325
1326 static int
1327 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1328 {
1329      int                        i;
1330      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1331      Elf64_Phdr         *p, *ph;
1332      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1333      unsigned long      loadaddr;
1334
1335      /* Read the rest of the Elf header... */
1336      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1337           prom_printf("\nCan't read Elf64 image header\n");
1338           goto bail;
1339      }
1340
1341      DEBUG_F("Elf64 header:\n");
1342      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1343      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1344      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1345      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1346      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1347      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1348      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1349      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1350      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1351      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1352
1353      loadinfo->entry = e->e_entry;
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  */