Commit yaboot 1.3.5-pre2
[yaboot.git] / second / yaboot.c
1 /* Yaboot - secondary boot loader for Linux on ppc.
2
3    Copyright (C) 1999 Benjamin Herrenschmidt
4
5    portions based on poof
6
7    Copyright (C) 1999 Marius Vollmer
8
9    portions based on quik
10    
11    Copyright (C) 1996 Paul Mackerras.
12
13    Because this program is derived from the corresponding file in the
14    silo-0.64 distribution, it is also
15
16    Copyright (C) 1996 Pete A. Zaitcev
17                  1996 Maurizio Plaza
18                  1996 David S. Miller
19                  1996 Miguel de Icaza
20                  1996 Jakub Jelinek
21
22    This program is free software; you can redistribute it and/or modify
23    it under the terms of the GNU General Public License as published by
24    the Free Software Foundation; either version 2 of the License, or
25    (at your option) any later version.
26
27    This program is distributed in the hope that it will be useful,
28    but WITHOUT ANY WARRANTY; without even the implied warranty of
29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30    GNU General Public License for more details.
31
32    You should have received a copy of the GNU General Public License
33    along with this program; if not, write to the Free Software
34    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
35 */
36
37 #include "stdarg.h"
38 #include "string.h"
39 #include "ctype.h"
40 #include "stdlib.h"
41 #include "prom.h"
42 #include "file.h"
43 #include "errors.h"
44 #include "cfg.h"
45 #include "cmdline.h"
46 #include "yaboot.h"
47 #include "linux/elf.h"
48 #include "bootinfo.h"
49 #include "debug.h"
50
51 #define CONFIG_FILE_NAME        "yaboot.conf"
52 #define CONFIG_FILE_MAX         0x8000          /* 32k */
53
54 #ifdef USE_MD5_PASSWORDS
55 #include "md5.h"
56 #endif /* USE_MD5_PASSWORDS */
57
58 /* align addr on a size boundry - adjust address up if needed -- Cort */
59 #define _ALIGN(addr,size)       (((addr)+size-1)&(~(size-1)))
60
61 /* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at.
62  * These are used to determine whether we are booting a vmlinux, in
63  * which case, it will be loaded at KERNELADDR.  Otherwise (eg zImage),
64  * we load the binary where it was linked at (ie, e_entry field in
65  * the ELF header).
66  */
67 #define KERNEL_LINK_ADDR_PPC32  0xC0000000UL
68 #define KERNEL_LINK_ADDR_PPC64  0xC000000000000000ULL
69
70 typedef struct {
71      union {
72           Elf32_Ehdr  elf32hdr;
73           Elf64_Ehdr  elf64hdr;
74      } elf;
75      void*          base;
76      unsigned long   memsize;
77      unsigned long   filesize;
78      unsigned long   offset;
79      unsigned long   load_loc;
80      unsigned long   entry;
81 } loadinfo_t;
82
83 typedef void (*kernel_entry_t)( void *,
84                                 unsigned long,
85                                 prom_entry,
86                                 unsigned long,
87                                 unsigned long );
88
89 /* Imported functions */
90 extern unsigned long reloc_offset(void);
91 extern long flush_icache_range(unsigned long start, unsigned long stop);
92
93 /* Exported functions */
94 int     yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
95
96 /* Local functions */
97 static int      yaboot_main(void);
98 static int      is_elf32(loadinfo_t *loadinfo);
99 static int      is_elf64(loadinfo_t *loadinfo);
100 static int      load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
101 static int      load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
102 static void     setup_display(void);
103
104 /* Locals & globals */
105
106 int useconf = 0;
107 char bootdevice[1024];
108 char *password = NULL;
109 struct boot_fspec_t boot;
110 int _machine = _MACH_Pmac;
111
112 #ifdef CONFIG_COLOR_TEXT
113
114 /* Color values for text ui */
115 static struct ansi_color_t {
116      char*      name;
117      int        index;
118      int        value;
119 } ansi_color_table[] = {
120      { "black",         2, 30 },
121      { "blue",          0, 31 },
122      { "green",         0, 32 },
123      { "cyan",          0, 33 },
124      { "red",           0, 34 },
125      { "purple",                0, 35 },
126      { "brown",         0, 36 },
127      { "light-gray",    0, 37 },
128      { "dark-gray",             1, 30 },
129      { "light-blue",            1, 31 },
130      { "light-green",   1, 32 },
131      { "light-cyan",            1, 33 },
132      { "light-red",             1, 34 },
133      { "light-purple",  1, 35 },
134      { "yellow",                1, 36 },
135      { "white",         1, 37 },
136      { NULL,                    0, 0 },
137 };
138
139 /* Default colors for text ui */
140 int fgcolor = 15;
141 int bgcolor = 0;
142 #endif /* CONFIG_COLOR_TEXT */
143
144 #if DEBUG
145 static int test_bss;
146 static int test_data = 0;
147 #endif
148 static int pause_after;
149 static char *pause_message = "Type go<return> to continue.\n";
150 static char given_bootargs[1024];
151 static int given_bootargs_by_user = 0;
152
153 extern unsigned char linux_logo_red[];
154 extern unsigned char linux_logo_green[];
155 extern unsigned char linux_logo_blue[];
156
157 #define DEFAULT_TIMEOUT         -1
158
159 /* Entry, currently called directly by crt0 (bss not inited) */
160
161 extern char* __bss_start;
162 extern char* _end;
163
164 static struct first_info *quik_fip = NULL;
165
166 int
167 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
168 {
169      int result;
170      void* malloc_base = NULL;
171      prom_handle root;
172
173      /* OF seems to do it, but I'm not very confident */
174      memset(&__bss_start, 0, &_end - &__bss_start);
175         
176      /* Check for quik first stage bootloader (but I don't think we are
177       * compatible with it anyway, I'll look into backporting to older OF
178       * versions later
179       */
180      if (r5 == 0xdeadbeef) {
181           r5 = r3;
182           quik_fip = (struct first_info *)r4;
183      }
184
185      /* Initialize OF interface */
186      prom_init ((prom_entry) r5);
187         
188      /* Allocate some memory for malloc'ator */
189      malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
190      if (malloc_base == (void *)-1) {
191           prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
192                       MALLOCSIZE, MALLOCADDR);
193           return -1;
194      }
195      malloc_init(malloc_base, MALLOCSIZE);
196      DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
197              malloc_base, MALLOCSIZE);
198                 
199      /* A few useless DEBUG_F's */
200      DEBUG_F("reloc_offset :  %ld         (should be 0)\n", reloc_offset());
201      DEBUG_F("test_bss     :  %d         (should be 0)\n", test_bss);
202      DEBUG_F("test_data    :  %d         (should be 0)\n", test_data);
203      DEBUG_F("&test_data   :  %p\n", &test_data);
204      DEBUG_F("&test_bss    :  %p\n", &test_bss);
205      DEBUG_F("linked at    :  0x%08x\n", TEXTADDR);
206
207      /* ask the OF info if we're a chrp or pmac */
208      /* we need to set _machine before calling finish_device_tree */
209      root = prom_finddevice("/");
210      if (root != 0) {
211           static char model[256];
212           if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
213               !strncmp("chrp", model, 4))
214                _machine = _MACH_chrp;
215           else {
216                if (prom_getprop(root, "model", model, 256 ) > 0 &&
217                    !strncmp(model, "IBM", 3))
218                     _machine = _MACH_chrp;
219           }
220      }
221         
222      DEBUG_F("Running on _machine = %d\n", _machine);
223      DEBUG_SLEEP;
224
225      /* Call out main */
226      result = yaboot_main();
227
228      /* Get rid of malloc pool */
229      malloc_dispose();
230      prom_release(malloc_base, MALLOCSIZE);
231      DEBUG_F("Malloc buffer released. Exiting with code %d\n",
232              result);
233
234      /* Return to OF */
235      prom_exit();
236         
237      return result;
238         
239 }
240
241 #ifdef CONFIG_COLOR_TEXT
242 /*
243  * Validify color for text ui
244  */
245 static int
246 check_color_text_ui(char *color)
247 {
248      int i = 0;
249      while(ansi_color_table[i].name) {
250           if (!strcmp(color, ansi_color_table[i].name))
251                return i;
252           i++;
253      }
254      return -1;
255 }      
256 #endif /* CONFIG_COLOR_TEXT */
257
258
259 void print_message_file(char *filename)
260 {
261      char *msg = NULL; 
262      char *p, *endp;
263      char *defdev = boot.dev;
264      int defpart = boot.part;
265      char msgpath[1024];
266      int opened = 0;
267      int result = 0;
268      int n;
269      struct boot_file_t file;
270      struct boot_fspec_t msgfile;
271
272      defdev = cfg_get_strg(0, "device");
273      if (!defdev)
274           defdev = boot.dev;
275      p = cfg_get_strg(0, "partition");
276           if (p) {
277                n = simple_strtol(p, &endp, 10);
278                if (endp != p && *endp == 0)
279                     defpart = n;               
280           }
281
282      strncpy(msgpath, filename, sizeof(msgpath));
283      if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
284           prom_printf("%s: Unable to parse\n", msgpath);
285           goto done;
286      }
287
288      result = open_file(&msgfile, &file);
289      if (result != FILE_ERR_OK) {
290           prom_printf("%s:%d,", msgfile.dev, msgfile.part);
291           prom_perror(result, msgfile.file);
292           goto done;
293      } else
294           opened = 1;
295
296      msg = malloc(2001);
297      if (!msg)
298           goto done;
299      else
300           memset(msg, 0, sizeof(*msg));
301
302      if (file.fs->read(&file, 2000, msg) <= 0)
303           goto done;
304      else
305           prom_printf("%s", msg);
306
307 done:
308      if (opened)
309           file.fs->close(&file);
310      if (msg)
311           free(msg);
312      if (p)
313           free(p);
314      if (endp)
315           free(endp);
316 }
317
318 /* Currently, the config file must be at the root of the filesystem.
319  * todo: recognize the full path to myself and use it to load the
320  * config file. Handle the "\\" (blessed system folder)
321  */
322 static int
323 load_config_file(char *device, char* path, int partition)
324 {
325      char *conf_file = NULL, *p;
326      struct boot_file_t file;
327      int sz, opened = 0, result = 0;
328      char conf_path[512];
329      struct boot_fspec_t fspec;
330
331      /* Allocate a buffer for the config file */
332      conf_file = malloc(CONFIG_FILE_MAX);
333      if (!conf_file) {
334           prom_printf("Can't alloc config file buffer\n");
335           goto bail;
336      }
337
338      /* Build the path to the file */
339      if (path)
340           strcpy(conf_path, path);
341      else if ( _machine == _MACH_chrp )
342           strcpy(conf_path, "/etc/");
343      else
344           conf_path[0] = 0;
345      strcat(conf_path, CONFIG_FILE_NAME);
346
347      /* Open it */
348      fspec.dev = device;
349      fspec.file = conf_path;
350      fspec.part = partition;
351      result = open_file(&fspec, &file);
352      if (result != FILE_ERR_OK) {
353           prom_printf("%s:%d,", fspec.dev, fspec.part);
354           prom_perror(result, fspec.file);
355           prom_printf("Can't open config file\n");
356           goto bail;
357      }
358      opened = 1;
359
360      /* Read it */
361      sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
362      if (sz <= 0) {
363           prom_printf("Error, can't read config file\n");
364           goto bail;
365      }
366      prom_printf("Config file read, %d bytes\n", sz);
367
368      /* Close the file */
369      if (opened)
370           file.fs->close(&file);
371      opened = 0;
372
373      /* Call the parsing code in cfg.c */
374      if (cfg_parse(conf_path, conf_file, sz) < 0) {
375           prom_printf ("Syntax error or read error config\n");
376           goto bail;
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 (result != 1 && conf_file)
435           free(conf_file);
436         
437      return result;
438 }
439
440 void maintabfunc (void)
441 {
442      if (useconf) {
443           cfg_print_images();
444           prom_printf("boot: %s", cbuff);
445      }
446 }
447
448 void
449 word_split(char **linep, char **paramsp)
450 {
451      char *p;
452
453      *paramsp = 0;
454      p = *linep;
455      if (p == 0)
456           return;
457      while (*p == ' ')
458           ++p;
459      if (*p == 0) {
460           *linep = 0;
461           return;
462      }
463      *linep = p;
464      while (*p != 0 && *p != ' ')
465           ++p;
466      while (*p == ' ')
467           *p++ = 0;
468      if (*p != 0)
469           *paramsp = p;
470 }
471
472 char *
473 make_params(char *label, char *params)
474 {
475      char *p, *q;
476      static char buffer[2048];
477
478      q = buffer;
479      *q = 0;
480
481      p = cfg_get_strg(label, "literal");
482      if (p) {
483           strcpy(q, p);
484           q = strchr(q, 0);
485           if (params) {
486                if (*p)
487                     *q++ = ' ';
488                strcpy(q, params);
489           }
490           return buffer;
491      }
492
493      p = cfg_get_strg(label, "root");
494      if (p) {
495           strcpy (q, "root=");
496           strcpy (q + 5, p);
497           q = strchr (q, 0);
498           *q++ = ' ';
499      }
500      if (cfg_get_flag(label, "read-only")) {
501           strcpy (q, "ro ");
502           q += 3;
503      }
504      if (cfg_get_flag(label, "read-write")) {
505           strcpy (q, "rw ");
506           q += 3;
507      }
508      p = cfg_get_strg(label, "ramdisk");
509      if (p) {
510           strcpy (q, "ramdisk=");
511           strcpy (q + 8, p);
512           q = strchr (q, 0);
513           *q++ = ' ';
514      }
515      p = cfg_get_strg(label, "initrd-size");
516      if (p) {
517           strcpy (q, "ramdisk_size=");
518           strcpy (q + 13, p);
519           q = strchr (q, 0);
520           *q++ = ' ';
521      }
522      if (cfg_get_flag(label, "novideo")) {
523           strcpy (q, "video=ofonly");
524           q = strchr (q, 0);
525           *q++ = ' ';
526      }
527      p = cfg_get_strg (label, "append");
528      if (p) {
529           strcpy (q, p);
530           q = strchr (q, 0);
531           *q++ = ' ';
532      }
533      *q = 0;
534      pause_after = cfg_get_flag (label, "pause-after");
535      p = cfg_get_strg(label, "pause-message");
536      if (p)
537           pause_message = p;
538      if (params)
539           strcpy(q, params);
540
541      return buffer;
542 }
543
544 void check_password(char *str)
545 {
546      int i;
547
548      for (i = 0; i < 3; i++) {
549           prom_printf ("\n%sassword: ", str);
550           passwdbuff[0] = 0;
551           cmdedit ((void (*)(void)) 0, 1);
552           prom_printf ("\n");
553 #ifdef USE_MD5_PASSWORDS
554           if (!strncmp (password, "$1$", 3)) {
555                if (!check_md5_password(passwdbuff, password))
556                     return;
557           } 
558           else if (!strcmp (password, passwdbuff))
559                return;
560 #else /* !MD5 */
561           if (!strcmp (password, passwdbuff))
562                return;
563 #endif /* USE_MD5_PASSWORDS */
564           if (i < 2)
565                prom_printf ("Password incorrect. Please try again...");
566      }
567      prom_printf ("Seems like you don't know the access password.  Go away!\n");
568      prom_sleep(3);
569      prom_interpret("reset-all");
570 }
571
572 int get_params(struct boot_param_t* params)
573 {
574      int defpart;
575      char *defdevice = 0;
576      char *p, *q, *endp;
577      int c, n;
578      char *imagename = 0, *label;
579      int timeout = -1;
580      int beg = 0, end;
581      int singlekey = 0;
582      int restricted = 0;
583      static int first = 1;
584      static char bootargs[1024];
585      static char imagepath[1024];
586      static char initrdpath[1024];
587      static char sysmappath[1024];
588
589      pause_after = 0;
590      memset(params, 0, sizeof(*params));
591      params->args = "";
592      params->kernel.part = -1;
593      params->rd.part = -1;
594      params->sysmap.part = -1;
595      defpart = boot.part;
596     
597      cmdinit();
598
599      if (first) {
600           first = 0;
601           prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
602           imagename = bootargs;
603           word_split(&imagename, &params->args);
604           timeout = DEFAULT_TIMEOUT;
605           if (imagename) {
606                prom_printf("Default supplied on the command line: %s ", imagename);
607                if (params->args)
608                     prom_printf("%s", params->args);
609                prom_printf("\n");
610           }
611           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
612                timeout = simple_strtol(q, NULL, 0);
613      }
614
615      prom_printf("boot: ");
616      c = -1;
617      if (timeout != -1) {
618           beg = prom_getms();
619           if (timeout > 0) {
620                end = beg + 100 * timeout;
621                do {
622                     c = prom_nbgetchar();
623                } while (c == -1 && prom_getms() <= end);
624           }
625           if (c == -1)
626                c = '\n';
627           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
628                cbuff[0] = c;
629                cbuff[1] = 0;
630           }
631      }
632
633      if (c != -1 && c != '\n' && c != '\r') {
634           if (c == '\t') {
635                maintabfunc ();
636           }  else if (c >= ' ') {
637                cbuff[0] = c;
638                cbuff[1] = 0;
639                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
640                     imagename = cbuff;
641                     singlekey = 1;
642                     prom_printf("%s\n", cbuff);
643                }
644           }
645      }
646
647      if (c == '\n' || c == '\r') {
648           if (!imagename)
649                imagename = cfg_get_default();
650           if (imagename)
651                prom_printf("%s", imagename);
652           if (params->args)
653                prom_printf(" %s", params->args);
654           prom_printf("\n");
655      } else if (!singlekey) {
656           cmdedit(maintabfunc, 0);
657           prom_printf("\n");
658           strcpy(given_bootargs, cbuff);
659           given_bootargs_by_user = 1;
660           imagename = cbuff;
661           word_split(&imagename, &params->args);
662      }
663
664      /* chrp gets this wrong, force it -- Cort */
665      if ( useconf && (!imagename || imagename[0] == 0 ))
666           imagename = cfg_get_default();
667
668      label = 0;
669      defdevice = boot.dev;
670
671      if (useconf) {
672           defdevice = cfg_get_strg(0, "device");
673           p = cfg_get_strg(0, "partition");
674           if (p) {
675                n = simple_strtol(p, &endp, 10);
676                if (endp != p && *endp == 0)
677                     defpart = n;
678           }
679           p = cfg_get_strg(0, "pause-message");
680           if (p)
681                pause_message = p;
682           if (cfg_get_flag(0, "restricted"))
683                restricted = 1;
684           p = cfg_get_strg(imagename, "image");
685           if (p && *p) {
686                label = imagename;
687                imagename = p;
688                defdevice = cfg_get_strg(label, "device");
689                if(!defdevice) defdevice=boot.dev;
690                p = cfg_get_strg(label, "partition");
691                if (p) {
692                     n = simple_strtol(p, &endp, 10);
693                     if (endp != p && *endp == 0)
694                          defpart = n;
695                }
696                if (cfg_get_flag(label, "restricted"))
697                     restricted = 1;
698                if (label) {
699                     if (params->args && password && restricted)
700                          check_password ("To specify image arguments you must enter the p");
701                     else if (password && !restricted)
702                          check_password ("P");
703                }
704                params->args = make_params(label, params->args);
705           }
706      }
707
708      if (!strcmp (imagename, "help")) {
709           prom_printf(
710                "\nPress the tab key for a list of defined images.\n"
711                "The label marked with a \"*\" is is the default image, "
712                "press <return> to boot it.\n\n"
713                "To boot any other label simply type its name and press <return>.\n\n"
714                "To boot a kernel image which is not defined in the yaboot configuration \n"
715                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
716                "\"device:\" is the OpenFirmware device path to the disk the image \n"
717                "resides on, and \"partno\" is the partition number the image resides on.\n"
718                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
719                "device, if you only specify a filename you should not start it with a \",\"\n\n"
720                "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
721                "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
722                "device=%s\n"
723                "partition=%d\n\n", defdevice, defpart);
724           return 0;
725      }
726
727      if (!strcmp (imagename, "halt")) {
728           if (password)
729                check_password ("P");
730           prom_pause();
731           return 0;
732      }
733      if (!strcmp (imagename, "bye")) {
734           if (password) {
735                check_password ("P");
736                return 1;
737           }
738           return 1; 
739      }
740
741      if (imagename[0] == '$') {
742           /* forth command string */
743           if (password)
744                check_password ("P");
745           prom_interpret(imagename+1);
746           return 0;
747      }
748
749      strncpy(imagepath, imagename, 1024);
750
751      if (!label && password)
752           check_password ("To boot a custom image you must enter the p");
753
754      if (!parse_device_path(imagepath, defdevice, defpart,
755                             "/vmlinux", &params->kernel)) {
756           prom_printf("%s: Unable to parse\n", imagepath);
757           return 0;
758      }
759      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
760              params->kernel.part, params->kernel.file);
761
762      if (useconf) {
763           p = cfg_get_strg(label, "initrd");
764           if (p && *p) {
765                DEBUG_F("Parsing initrd path <%s>\n", p);
766                strncpy(initrdpath, p, 1024);
767                if (!parse_device_path(initrdpath, defdevice, defpart,
768                                       "/root.bin", &params->rd)) {
769                     prom_printf("%s: Unable to parse\n", imagepath);
770                     return 0;
771                }
772           }
773           p = cfg_get_strg(label, "sysmap");
774           if (p && *p) {
775                DEBUG_F("Parsing sysmap path <%s>\n", p);
776                strncpy(sysmappath, p, 1024);
777                if (!parse_device_path(sysmappath, defdevice, defpart,
778                                       "/boot/System.map", &params->sysmap)) {
779                     prom_printf("%s: Unable to parse\n", imagepath);
780                     return 0;
781                }
782           }
783      }
784      return 0;
785 }
786
787 /* This is derived from quik core. To be changed to first parse the headers
788  * doing lazy-loading, and then claim the memory before loading the kernel
789  * to it
790  * We also need to add initrd support to this whole mecanism
791  */
792 void
793 yaboot_text_ui(void)
794 {
795 #define MAX_HEADERS     32
796
797      struct boot_file_t file;
798      int                        result;
799      static struct boot_param_t params;
800      void               *initrd_base;
801      unsigned long      initrd_size;
802      void                *sysmap_base;
803      unsigned long      sysmap_size;
804      kernel_entry_t      kernel_entry;
805      struct bi_record*  birec;
806      char*               loc=NULL;
807      loadinfo_t          loadinfo;
808      void                *initrd_more,*initrd_want;
809      unsigned long       initrd_read;
810     
811      loadinfo.load_loc = 0;
812
813      for (;;) {
814           initrd_size = 0;
815           initrd_base = 0;
816           sysmap_base = 0;
817           sysmap_size = 0;
818         
819           if (get_params(&params))
820                return;
821           if (!params.kernel.file)
822                continue;
823         
824           prom_printf("Please wait, loading kernel...\n");
825
826           memset(&file, 0, sizeof(file));
827
828           if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
829               && params.kernel.file[0] != '\\') {
830                loc=(char*)malloc(strlen(params.kernel.file)+3);
831                if (!loc) {
832                     prom_printf ("malloc error\n");
833                     goto next;
834                }
835                strcpy(loc,boot.file);
836                strcat(loc,params.kernel.file);
837                free(params.kernel.file);
838                params.kernel.file=loc;
839           }
840           result = open_file(&params.kernel, &file);
841           if (result != FILE_ERR_OK) {
842                prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
843                prom_perror(result, params.kernel.file);
844                goto next;
845           }
846
847           /* Read the Elf e_ident, e_type and e_machine fields to
848            * determine Elf file type
849            */
850           if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
851                prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
852                file.fs->close(&file);
853                memset(&file, 0, sizeof(file));
854                goto next;
855           }
856
857           if (is_elf32(&loadinfo)) {
858                if (!load_elf32(&file, &loadinfo)) {
859                     file.fs->close(&file);
860                     memset(&file, 0, sizeof(file));
861                     goto next;
862                }
863                prom_printf("   Elf32 kernel loaded...\n");
864           } else if (is_elf64(&loadinfo)) {
865                if (!load_elf64(&file, &loadinfo)) {
866                     file.fs->close(&file);
867                     memset(&file, 0, sizeof(file));
868                     goto next;
869                }
870                prom_printf("   Elf64 kernel loaded...\n");
871           } else {
872                prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
873                file.fs->close(&file);
874                memset(&file, 0, sizeof(file));
875                goto next;
876           }
877           file.fs->close(&file);
878           memset(&file, 0, sizeof(file));
879
880           /* If sysmap, load it. 
881            */
882           if (params.sysmap.file) {
883                prom_printf("Loading System.map ...\n");
884                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
885                   && params.sysmap.file[0] != '\\') {
886                     if (loc) free(loc);
887                     loc=(char*)malloc(strlen(params.sysmap.file)+3);
888                     if (!loc) {
889                          prom_printf ("malloc error\n");
890                          goto next;
891                     }
892                     strcpy(loc,boot.file);
893                     strcat(loc,params.sysmap.file);
894                     free(params.sysmap.file);
895                     params.sysmap.file=loc;
896                }
897              
898                result = open_file(&params.sysmap, &file);
899                if (result != FILE_ERR_OK) {
900                     prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
901                     prom_perror(result, params.sysmap.file);
902                }
903                else {
904                     sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
905                     if (sysmap_base == (void *)-1) {
906                          prom_printf("Claim failed for sysmap memory\n");
907                          sysmap_base = 0;
908                     } else {
909                          sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
910                          if (sysmap_size == 0)
911                               sysmap_base = 0;
912                          else
913                               ((char *)sysmap_base)[sysmap_size++] = 0;
914                     }
915                     file.fs->close(&file);
916                     memset(&file, 0, sizeof(file));
917                }
918                if (sysmap_base) {
919                     prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
920                                 sysmap_base, sysmap_size >> 10);
921                     loadinfo.memsize += _ALIGN(0x100000, 0x1000);
922                } else {
923                     prom_printf("System.map load failed !\n");
924                     prom_pause();
925                }
926           }
927
928           /* If ramdisk, load it. For now, we can't tell the size it will be
929            * so we claim an arbitrary amount of 4Mb
930            */
931           if (params.rd.file) {
932                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
933                   && params.kernel.file[0] != '\\')
934                {
935                     if (loc) free(loc);
936                     loc=(char*)malloc(strlen(params.rd.file)+3);
937                     if (!loc) {
938                          prom_printf ("Malloc error\n");
939                          goto next;
940                     }
941                     strcpy(loc,boot.file);
942                     strcat(loc,params.rd.file);
943                     free(params.rd.file);
944                     params.rd.file=loc;
945                }
946                prom_printf("Loading ramdisk...\n");
947                result = open_file(&params.rd, &file);
948                if (result != FILE_ERR_OK) {
949                     prom_printf("%s:%d,", params.rd.dev, params.rd.part);
950                     prom_perror(result, params.rd.file);
951                }
952                else {
953 #define INITRD_CHUNKSIZE 0x400000
954                     initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
955                     if (initrd_base == (void *)-1) {
956                          prom_printf("Claim failed for initrd memory\n");
957                          initrd_base = 0;
958                     } else {
959                          initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
960                          if (initrd_size == 0)
961                               initrd_base = 0;
962                          initrd_read = initrd_size;
963                          initrd_more = initrd_base;
964                          while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
965                               initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
966                               initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
967                               if (initrd_more != initrd_want) {
968                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
969                                    break;
970                               }
971                               initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
972                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
973                               initrd_size += initrd_read;
974                          }
975                     }
976                     file.fs->close(&file);
977                     memset(&file, 0, sizeof(file));
978                }
979                if (initrd_base)
980                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
981                                 initrd_base, initrd_size >> 10);
982                else {
983                     prom_printf("ramdisk load failed !\n");
984                     prom_pause();
985                }
986           }
987
988           DEBUG_F("setting kernel args to: %s\n", params.args);
989           prom_setargs(params.args);
990           DEBUG_F("flushing icache...");
991           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
992           DEBUG_F(" done\n");
993
994 /* 
995  * Fill mew boot infos
996  *
997  * The birec is low on memory, probably inside the malloc pool, so
998  * we don't write it earlier. At this point, we should not use anything
999  * coming from the malloc pool
1000  */
1001           birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1002
1003 /* We make sure it's mapped. We map only 64k for now, it's plenty enough
1004  * we don't claim since this precise memory range may already be claimed
1005  * by the malloc pool
1006  */
1007           prom_map (birec, birec, 0x10000);
1008           DEBUG_F("birec at %p\n", birec);
1009           DEBUG_SLEEP;
1010
1011           birec->tag = BI_FIRST;
1012           birec->size = sizeof(struct bi_record);
1013           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1014         
1015           birec->tag = BI_BOOTLOADER_ID;
1016           sprintf( (char *)birec->data, "yaboot");
1017           birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1018           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1019         
1020           birec->tag = BI_MACHTYPE;
1021           birec->data[0] = _machine;
1022           birec->size = sizeof(struct bi_record) + sizeof(unsigned long);
1023           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1024
1025           if (sysmap_base) {
1026                birec->tag = BI_SYSMAP;
1027                birec->data[0] = (unsigned long)sysmap_base;
1028                birec->data[1] = sysmap_size;
1029                birec->size = sizeof(struct bi_record) + sizeof(unsigned long)*2;
1030                birec = (struct bi_record *)((unsigned long)birec + birec->size);
1031           }
1032           birec->tag = BI_LAST;
1033           birec->size = sizeof(struct bi_record);
1034           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1035
1036           /* compute the kernel's entry point. */
1037           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1038
1039           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1040           DEBUG_F("kernel: arg1 = %p,\n"
1041                   "        arg2 = 0x%08lx,\n"
1042                   "        prom = %p,\n"
1043                   "        arg4 = %d,\n"
1044                   "        arg5 = %d\n\n",
1045                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1046
1047           DEBUG_F("Entering kernel...\n");
1048
1049           /* call the kernel with our stack. */
1050           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1051           continue;
1052      next:
1053           ; /* do nothing */
1054      }
1055 }
1056
1057 static int
1058 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1059 {
1060      int                        i;
1061      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1062      Elf32_Phdr         *p, *ph;
1063      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1064      unsigned long      addr, loadaddr;
1065
1066      /* Read the rest of the Elf header... */
1067      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1068           prom_printf("\nCan't read Elf32 image header\n");
1069           return 0;
1070      }
1071
1072      DEBUG_F("Elf32 header:\n");
1073      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1074      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1075      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1076      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1077      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1078      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1079      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1080      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1081      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1082      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1083
1084      loadinfo->entry = e->e_entry;
1085
1086      if (e->e_phnum > MAX_HEADERS) {
1087           prom_printf ("Can only load kernels with one program header\n");
1088           return 0;
1089      }
1090
1091      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1092      if (!ph) {
1093           prom_printf ("Malloc error\n");
1094           return 0;
1095      }
1096
1097      /* Now, we read the section header */
1098      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1099           prom_printf ("seek error\n");
1100           return 0;
1101      }
1102      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1103          sizeof(Elf32_Phdr) * e->e_phnum) {
1104           prom_printf ("read error\n");
1105           return 0;
1106      }
1107
1108      /* Scan through the program header
1109       * HACK:  We must return the _memory size of the kernel image, not the
1110       *        file size (because we have to leave room before other boot
1111       *   infos. This code works as a side effect of the fact that
1112       *   we have one section and vaddr == p_paddr
1113       */
1114      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1115      p = ph;
1116      for (i = 0; i < e->e_phnum; ++i, ++p) {
1117           if (p->p_type != PT_LOAD || p->p_offset == 0)
1118                continue;
1119           if (loadinfo->memsize == 0) {
1120                loadinfo->offset = p->p_offset;
1121                loadinfo->memsize = p->p_memsz;
1122                loadinfo->filesize = p->p_filesz;
1123                loadinfo->load_loc = p->p_vaddr;
1124           } else {
1125                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1126                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1127           }
1128      }
1129
1130      if (loadinfo->memsize == 0) {
1131           prom_printf("Can't find a loadable segment !\n");
1132           return 0;
1133      }
1134
1135      /* leave some room (1Mb) for boot infos */
1136      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1137      /* Claim OF memory */
1138      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1139
1140      /* On some systems, loadaddr may already be claimed, so try some
1141       * other nearby addresses before giving up.
1142       */
1143      loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC32 ||
1144                  e->e_entry == 0) ? KERNELADDR : e->e_entry;
1145      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1146           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1147           if (loadinfo->base != (void *)-1) break;
1148      }
1149      if (loadinfo->base == (void *)-1) {
1150           prom_printf("Claim error, can't allocate kernel memory\n");
1151           return 0;
1152      }  
1153
1154      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1155              loadinfo->base, loadinfo->memsize);
1156      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1157              loadaddr, loadinfo->memsize);
1158
1159      /* Load the program segments... */
1160      p = ph;
1161      for (i = 0; i < e->e_phnum; ++i, ++p) {
1162           unsigned long offset;
1163           if (p->p_type != PT_LOAD || p->p_offset == 0)
1164                continue;
1165
1166           /* Now, we skip to the image itself */
1167           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1168                prom_printf ("Seek error\n");
1169                prom_release(loadinfo->base, loadinfo->memsize);
1170                return 0;
1171           }
1172           offset = p->p_vaddr - loadinfo->load_loc;
1173           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1174                prom_printf ("Read failed\n");
1175                prom_release(loadinfo->base, loadinfo->memsize);
1176                return 0;
1177           }
1178      }
1179
1180      free(ph);
1181     
1182      /* Return success at loading the Elf32 kernel */
1183      return 1;
1184 }
1185
1186 static int
1187 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1188 {
1189      int                        i;
1190      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1191      Elf64_Phdr         *p, *ph;
1192      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1193      unsigned long      addr, loadaddr;
1194
1195      /* Read the rest of the Elf header... */
1196      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1197           prom_printf("\nCan't read Elf64 image header\n");
1198           return 0;
1199      }
1200
1201      DEBUG_F("Elf64 header:\n");
1202      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1203      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1204      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1205      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1206      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1207      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1208      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1209      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1210      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1211      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1212
1213      loadinfo->entry = e->e_entry;
1214
1215      if (e->e_phnum > MAX_HEADERS) {
1216           prom_printf ("Can only load kernels with one program header\n");
1217           return 0;
1218      }
1219
1220      ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1221      if (!ph) {
1222           prom_printf ("Malloc error\n");
1223           return 0;
1224      }
1225
1226      /* Now, we read the section header */
1227      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1228           prom_printf ("Seek error\n");
1229           return 0;
1230      }
1231      if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1232          sizeof(Elf64_Phdr) * e->e_phnum) {
1233           prom_printf ("Read error\n");
1234           return 0;
1235      }
1236
1237      /* Scan through the program header
1238       * HACK:  We must return the _memory size of the kernel image, not the
1239       *        file size (because we have to leave room before other boot
1240       *   infos. This code works as a side effect of the fact that
1241       *   we have one section and vaddr == p_paddr
1242       */
1243      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1244      p = ph;
1245      for (i = 0; i < e->e_phnum; ++i, ++p) {
1246           if (p->p_type != PT_LOAD || p->p_offset == 0)
1247                continue;
1248           if (loadinfo->memsize == 0) {
1249                loadinfo->offset = p->p_offset;
1250                loadinfo->memsize = p->p_memsz;
1251                loadinfo->filesize = p->p_filesz;
1252                loadinfo->load_loc = p->p_vaddr;
1253           } else {
1254                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1255                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1256           }
1257      }
1258
1259      if (loadinfo->memsize == 0) {
1260           prom_printf("Can't find a loadable segment !\n");
1261           return 0;
1262      }
1263
1264      /* leave some room (1Mb) for boot infos */
1265      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1266      /* Claim OF memory */
1267      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1268
1269      /* On some systems, loadaddr may already be claimed, so try some
1270       * other nearby addresses before giving up.
1271       */
1272      loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC64) ? KERNELADDR : e->e_entry;
1273      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1274           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1275           if (loadinfo->base != (void *)-1) break;
1276      }
1277      if (loadinfo->base == (void *)-1) {
1278           prom_printf("Claim error, can't allocate kernel memory\n");
1279           return 0;
1280      }  
1281
1282      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1283              loadinfo->base, loadinfo->memsize);
1284      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1285              loadaddr, loadinfo->memsize);
1286
1287      /* Load the program segments... */
1288      p = ph;
1289      for (i = 0; i < e->e_phnum; ++i, ++p) {
1290           unsigned long offset;
1291           if (p->p_type != PT_LOAD || p->p_offset == 0)
1292                continue;
1293
1294           /* Now, we skip to the image itself */
1295           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1296                prom_printf ("Seek error\n");
1297                prom_release(loadinfo->base, loadinfo->memsize);
1298                return 0;
1299           }
1300           offset = p->p_vaddr - loadinfo->load_loc;
1301           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1302                prom_printf ("Read failed\n");
1303                prom_release(loadinfo->base, loadinfo->memsize);
1304                return 0;
1305           }
1306      }
1307
1308      free(ph);
1309     
1310      /* Return success at loading the Elf64 kernel */
1311      return 1;
1312 }
1313
1314 static int
1315 is_elf32(loadinfo_t *loadinfo)
1316 {
1317      Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1318
1319      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1320              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1321              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1322              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1323              e->e_ident[EI_CLASS] == ELFCLASS32  &&
1324              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1325              e->e_type            == ET_EXEC        &&
1326              e->e_machine         == EM_PPC);
1327 }
1328
1329 static int
1330 is_elf64(loadinfo_t *loadinfo)
1331 {
1332      Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1333
1334      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1335              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1336              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1337              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1338              e->e_ident[EI_CLASS] == ELFCLASS64  &&
1339              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1340              e->e_type            == ET_EXEC        &&
1341              e->e_machine         == EM_PPC64);
1342 }
1343
1344 static void
1345 setup_display(void)
1346 {
1347 #ifdef CONFIG_SET_COLORMAP
1348      static unsigned char default_colors[] = {
1349           0x00, 0x00, 0x00,
1350           0x00, 0x00, 0xaa,
1351           0x00, 0xaa, 0x00,
1352           0x00, 0xaa, 0xaa,
1353           0xaa, 0x00, 0x00,
1354           0xaa, 0x00, 0xaa,
1355           0xaa, 0x55, 0x00,
1356           0xaa, 0xaa, 0xaa,
1357           0x55, 0x55, 0x55,
1358           0x55, 0x55, 0xff,
1359           0x55, 0xff, 0x55,
1360           0x55, 0xff, 0xff,
1361           0xff, 0x55, 0x55,
1362           0xff, 0x55, 0xff,
1363           0xff, 0xff, 0x55,
1364           0xff, 0xff, 0xff
1365      };
1366      int i, result;
1367      prom_handle scrn = PROM_INVALID_HANDLE;
1368
1369      /* Try Apple's mac-boot screen ihandle */
1370      result = (int)call_prom_return("interpret", 1, 2,
1371                                     "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1372      DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1373
1374      if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1375           char type[32];
1376           /* Hrm... check to see if stdout is a display */
1377           scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1378           DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1379           if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1380                DEBUG_F("got it ! stdout is a screen\n");
1381                scrn = prom_stdout;
1382           } else {
1383                /* Else, we try to open the package */
1384                scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1385                DEBUG_F("Open screen result: %p\n", scrn);
1386           }
1387      }
1388         
1389      if (scrn == PROM_INVALID_HANDLE) {
1390           prom_printf("No screen device found !/n");
1391           return;
1392      }
1393      for(i=0;i<16;i++) {
1394           prom_set_color(scrn, i, default_colors[i*3],
1395                          default_colors[i*3+1], default_colors[i*3+2]);
1396      }
1397      prom_printf("\x1b[1;37m\x1b[2;40m");       
1398 #ifdef COLOR_TEST
1399      for (i=0;i<16; i++) {
1400           prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1401                       ansi_color_table[i].index,
1402                       ansi_color_table[i].value,
1403                       ansi_color_table[i].name,
1404                       ansi_color_table[i].name);
1405           prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1406                       ansi_color_table[i].index,
1407                       ansi_color_table[i].value+10,
1408                       ansi_color_table[i].name,
1409                       ansi_color_table[i].name);
1410      }
1411      prom_printf("\x1b[1;37m\x1b[2;40m");       
1412 #endif /* COLOR_TEST */
1413
1414 #if !DEBUG
1415      prom_printf("\xc");
1416 #endif /* !DEBUG */
1417
1418 #endif /* CONFIG_SET_COLORMAP */
1419 }
1420
1421 int
1422 yaboot_main(void)
1423 {
1424      char *ptype;
1425
1426      if (_machine == _MACH_Pmac)
1427           setup_display();
1428         
1429      prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1430      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1431      if (bootdevice[0] == 0)
1432           prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1433      if (bootdevice[0] == 0) {
1434           prom_printf("Couldn't determine boot device\n");
1435           return -1;
1436      }
1437
1438      if (!parse_device_path(bootdevice, (_machine == _MACH_Pmac) ? "hd" : "disc",
1439                             -1, "", &boot)) {
1440           prom_printf("%s: Unable to parse\n", bootdevice);
1441           return -1;
1442      }
1443      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1444              boot.dev, boot.part, boot.file);
1445
1446      if (strlen(boot.file)) {
1447           if (!strncmp(boot.file, "\\\\", 2))
1448                boot.file = "\\\\";
1449           else {
1450                char *p, *last;
1451                p = last = boot.file;
1452                while(*p) {
1453                     if (*p == '\\')
1454                          last = p;
1455                     p++;
1456                }
1457                if (p)
1458                     *(last) = 0;
1459                else
1460                     boot.file = "";
1461                if (strlen(boot.file))
1462                     strcat(boot.file, "\\");
1463           }
1464      }
1465      DEBUG_F("After path fixup: dev=%s, part=%d, file=%s\n",
1466              boot.dev, boot.part, boot.file);
1467
1468      useconf = load_config_file(boot.dev, boot.file, boot.part);
1469
1470      prom_printf("Welcome to yaboot version " VERSION "\n");
1471      prom_printf("Enter \"help\" to get some basic usage information\n");
1472
1473      /* I am fed up with lusers using the wrong partition type and
1474         mailing me *when* it breaks */
1475
1476      if (_machine == _MACH_Pmac) {
1477           char *entry = cfg_get_strg(0, "ptypewarning");
1478           int warn = 1;
1479           if (entry)
1480                warn = strcmp(entry,
1481                              "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1482           if (warn) {
1483                ptype = get_part_type(boot.dev, boot.part);
1484                if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1485                     prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1486                                 "         type should be: \"Apple_Bootstrap\"\n\n", ptype);
1487           }
1488      }
1489
1490      yaboot_text_ui();
1491         
1492      prom_printf("Bye.\n");
1493      return 0;
1494 }
1495
1496 /* 
1497  * Local variables:
1498  * c-file-style: "k&r"
1499  * c-basic-offset: 5
1500  * End:
1501  */