6eabb427dc20863f73b0d1bfa1d38d9eba89a070
[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, 2001);
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 }
313
314 /* Currently, the config file must be at the root of the filesystem.
315  * todo: recognize the full path to myself and use it to load the
316  * config file. Handle the "\\" (blessed system folder)
317  */
318 static int
319 load_config_file(char *device, char* path, int partition)
320 {
321      char *conf_file = NULL, *p;
322      struct boot_file_t file;
323      int sz, opened = 0, result = 0;
324      char conf_path[512];
325      struct boot_fspec_t fspec;
326
327      /* Allocate a buffer for the config file */
328      conf_file = malloc(CONFIG_FILE_MAX);
329      if (!conf_file) {
330           prom_printf("Can't alloc config file buffer\n");
331           goto bail;
332      }
333
334      /* Build the path to the file */
335      if (path)
336           strcpy(conf_path, path);
337      else if ( _machine == _MACH_chrp )
338           strcpy(conf_path, "/etc/");
339      else
340           conf_path[0] = 0;
341      strcat(conf_path, CONFIG_FILE_NAME);
342
343      /* Open it */
344      fspec.dev = device;
345      fspec.file = conf_path;
346      fspec.part = partition;
347      result = open_file(&fspec, &file);
348      if (result != FILE_ERR_OK) {
349           prom_printf("%s:%d,", fspec.dev, fspec.part);
350           prom_perror(result, fspec.file);
351           prom_printf("Can't open config file\n");
352           goto bail;
353      }
354      opened = 1;
355
356      /* Read it */
357      sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
358      if (sz <= 0) {
359           prom_printf("Error, can't read config file\n");
360           goto bail;
361      }
362      prom_printf("Config file read, %d bytes\n", sz);
363
364      /* Close the file */
365      if (opened)
366           file.fs->close(&file);
367      opened = 0;
368
369      /* Call the parsing code in cfg.c */
370      if (cfg_parse(conf_path, conf_file, sz) < 0) {
371           prom_printf ("Syntax error or read error config\n");
372           goto bail;
373      }
374
375      DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
376
377      /* Now, we do the initialisations stored in the config file */
378      p = cfg_get_strg(0, "init-code");
379      if (p)
380           prom_interpret(p);
381
382      password = cfg_get_strg(0, "password");
383         
384 #ifdef CONFIG_COLOR_TEXT
385      p = cfg_get_strg(0, "fgcolor");
386      if (p) {
387           DEBUG_F("fgcolor=%s\n", p);
388           fgcolor = check_color_text_ui(p);
389           if (fgcolor == -1) {
390                prom_printf("Invalid fgcolor: \"%s\".\n", p);
391           }
392      }
393      p = cfg_get_strg(0, "bgcolor");
394      if (p) {
395           DEBUG_F("bgcolor=%s\n", p);
396           bgcolor = check_color_text_ui(p);
397           if (bgcolor == -1)
398                prom_printf("Invalid bgcolor: \"%s\".\n", p);
399      }
400      if (bgcolor >= 0) {
401           char temp[64];
402           sprintf(temp, "%x to background-color", bgcolor); 
403           prom_interpret(temp); 
404 #if !DEBUG
405           prom_printf("\xc");
406 #endif /* !DEBUG */
407      }
408      if (fgcolor >= 0) {
409           char temp[64];
410           sprintf(temp, "%x to foreground-color", fgcolor); 
411           prom_interpret(temp); 
412      }
413 #endif /* CONFIG_COLOR_TEXT */
414    
415      p = cfg_get_strg(0, "init-message");
416      if (p)
417           prom_printf("%s\n", p);
418
419      p = cfg_get_strg(0, "message");
420      if (p)
421           print_message_file(p);
422
423      result = 1;
424     
425 bail:
426
427      if (opened)
428           file.fs->close(&file);
429     
430      if (result != 1 && conf_file)
431           free(conf_file);
432         
433      return result;
434 }
435
436 void maintabfunc (void)
437 {
438      if (useconf) {
439           cfg_print_images();
440           prom_printf("boot: %s", cbuff);
441      }
442 }
443
444 void
445 word_split(char **linep, char **paramsp)
446 {
447      char *p;
448
449      *paramsp = 0;
450      p = *linep;
451      if (p == 0)
452           return;
453      while (*p == ' ')
454           ++p;
455      if (*p == 0) {
456           *linep = 0;
457           return;
458      }
459      *linep = p;
460      while (*p != 0 && *p != ' ')
461           ++p;
462      while (*p == ' ')
463           *p++ = 0;
464      if (*p != 0)
465           *paramsp = p;
466 }
467
468 char *
469 make_params(char *label, char *params)
470 {
471      char *p, *q;
472      static char buffer[2048];
473
474      q = buffer;
475      *q = 0;
476
477      p = cfg_get_strg(label, "literal");
478      if (p) {
479           strcpy(q, p);
480           q = strchr(q, 0);
481           if (params) {
482                if (*p)
483                     *q++ = ' ';
484                strcpy(q, params);
485           }
486           return buffer;
487      }
488
489      p = cfg_get_strg(label, "root");
490      if (p) {
491           strcpy (q, "root=");
492           strcpy (q + 5, p);
493           q = strchr (q, 0);
494           *q++ = ' ';
495      }
496      if (cfg_get_flag(label, "read-only")) {
497           strcpy (q, "ro ");
498           q += 3;
499      }
500      if (cfg_get_flag(label, "read-write")) {
501           strcpy (q, "rw ");
502           q += 3;
503      }
504      p = cfg_get_strg(label, "ramdisk");
505      if (p) {
506           strcpy (q, "ramdisk=");
507           strcpy (q + 8, p);
508           q = strchr (q, 0);
509           *q++ = ' ';
510      }
511      p = cfg_get_strg(label, "initrd-size");
512      if (p) {
513           strcpy (q, "ramdisk_size=");
514           strcpy (q + 13, p);
515           q = strchr (q, 0);
516           *q++ = ' ';
517      }
518      if (cfg_get_flag(label, "novideo")) {
519           strcpy (q, "video=ofonly");
520           q = strchr (q, 0);
521           *q++ = ' ';
522      }
523      p = cfg_get_strg (label, "append");
524      if (p) {
525           strcpy (q, p);
526           q = strchr (q, 0);
527           *q++ = ' ';
528      }
529      *q = 0;
530      pause_after = cfg_get_flag (label, "pause-after");
531      p = cfg_get_strg(label, "pause-message");
532      if (p)
533           pause_message = p;
534      if (params)
535           strcpy(q, params);
536
537      return buffer;
538 }
539
540 void check_password(char *str)
541 {
542      int i;
543
544      for (i = 0; i < 3; i++) {
545           prom_printf ("\n%sassword: ", str);
546           passwdbuff[0] = 0;
547           cmdedit ((void (*)(void)) 0, 1);
548           prom_printf ("\n");
549 #ifdef USE_MD5_PASSWORDS
550           if (!strncmp (password, "$1$", 3)) {
551                if (!check_md5_password(passwdbuff, password))
552                     return;
553           } 
554           else if (!strcmp (password, passwdbuff))
555                return;
556 #else /* !MD5 */
557           if (!strcmp (password, passwdbuff))
558                return;
559 #endif /* USE_MD5_PASSWORDS */
560           if (i < 2)
561                prom_printf ("Password incorrect. Please try again...");
562      }
563      prom_printf ("Seems like you don't know the access password.  Go away!\n");
564      prom_sleep(3);
565      prom_interpret("reset-all");
566 }
567
568 int get_params(struct boot_param_t* params)
569 {
570      int defpart;
571      char *defdevice = 0;
572      char *p, *q, *endp;
573      int c, n;
574      char *imagename = 0, *label;
575      int timeout = -1;
576      int beg = 0, end;
577      int singlekey = 0;
578      int restricted = 0;
579      static int first = 1;
580      static char bootargs[1024];
581      static char imagepath[1024];
582      static char initrdpath[1024];
583      static char sysmappath[1024];
584
585      pause_after = 0;
586      memset(params, 0, sizeof(*params));
587      params->args = "";
588      params->kernel.part = -1;
589      params->rd.part = -1;
590      params->sysmap.part = -1;
591      defpart = boot.part;
592     
593      cmdinit();
594
595      if (first) {
596           first = 0;
597           prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
598           imagename = bootargs;
599           word_split(&imagename, &params->args);
600           timeout = DEFAULT_TIMEOUT;
601           if (imagename) {
602                prom_printf("Default supplied on the command line: %s ", imagename);
603                if (params->args)
604                     prom_printf("%s", params->args);
605                prom_printf("\n");
606           }
607           if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
608                timeout = simple_strtol(q, NULL, 0);
609      }
610
611      prom_printf("boot: ");
612      c = -1;
613      if (timeout != -1) {
614           beg = prom_getms();
615           if (timeout > 0) {
616                end = beg + 100 * timeout;
617                do {
618                     c = prom_nbgetchar();
619                } while (c == -1 && prom_getms() <= end);
620           }
621           if (c == -1)
622                c = '\n';
623           else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
624                cbuff[0] = c;
625                cbuff[1] = 0;
626           }
627      }
628
629      if (c != -1 && c != '\n' && c != '\r') {
630           if (c == '\t') {
631                maintabfunc ();
632           }  else if (c >= ' ') {
633                cbuff[0] = c;
634                cbuff[1] = 0;
635                if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
636                     imagename = cbuff;
637                     singlekey = 1;
638                     prom_printf("%s\n", cbuff);
639                }
640           }
641      }
642
643      if (c == '\n' || c == '\r') {
644           if (!imagename)
645                imagename = cfg_get_default();
646           if (imagename)
647                prom_printf("%s", imagename);
648           if (params->args)
649                prom_printf(" %s", params->args);
650           prom_printf("\n");
651      } else if (!singlekey) {
652           cmdedit(maintabfunc, 0);
653           prom_printf("\n");
654           strcpy(given_bootargs, cbuff);
655           given_bootargs_by_user = 1;
656           imagename = cbuff;
657           word_split(&imagename, &params->args);
658      }
659
660      /* chrp gets this wrong, force it -- Cort */
661      if ( useconf && (!imagename || imagename[0] == 0 ))
662           imagename = cfg_get_default();
663
664      label = 0;
665      defdevice = boot.dev;
666
667      if (useconf) {
668           defdevice = cfg_get_strg(0, "device");
669           p = cfg_get_strg(0, "partition");
670           if (p) {
671                n = simple_strtol(p, &endp, 10);
672                if (endp != p && *endp == 0)
673                     defpart = n;
674           }
675           p = cfg_get_strg(0, "pause-message");
676           if (p)
677                pause_message = p;
678           if (cfg_get_flag(0, "restricted"))
679                restricted = 1;
680           p = cfg_get_strg(imagename, "image");
681           if (p && *p) {
682                label = imagename;
683                imagename = p;
684                defdevice = cfg_get_strg(label, "device");
685                if(!defdevice) defdevice=boot.dev;
686                p = cfg_get_strg(label, "partition");
687                if (p) {
688                     n = simple_strtol(p, &endp, 10);
689                     if (endp != p && *endp == 0)
690                          defpart = n;
691                }
692                if (cfg_get_flag(label, "restricted"))
693                     restricted = 1;
694                if (label) {
695                     if (params->args && password && restricted)
696                          check_password ("To specify image arguments you must enter the p");
697                     else if (password && !restricted)
698                          check_password ("P");
699                }
700                params->args = make_params(label, params->args);
701           }
702      }
703
704      if (!strcmp (imagename, "help")) {
705           prom_printf(
706                "\nPress the tab key for a list of defined images.\n"
707                "The label marked with a \"*\" is is the default image, "
708                "press <return> to boot it.\n\n"
709                "To boot any other label simply type its name and press <return>.\n\n"
710                "To boot a kernel image which is not defined in the yaboot configuration \n"
711                "file, enter the kernel image name as [[device:][partno],]/path, where \n"
712                "\"device:\" is the OpenFirmware device path to the disk the image \n"
713                "resides on, and \"partno\" is the partition number the image resides on.\n"
714                "Note that the comma (,) is only required if you specify an OpenFirmware\n"
715                "device, if you only specify a filename you should not start it with a \",\"\n\n"
716                "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
717                "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
718                "device=%s\n"
719                "partition=%d\n\n", defdevice, defpart);
720           return 0;
721      }
722
723      if (!strcmp (imagename, "halt")) {
724           if (password)
725                check_password ("P");
726           prom_pause();
727           return 0;
728      }
729      if (!strcmp (imagename, "bye")) {
730           if (password) {
731                check_password ("P");
732                return 1;
733           }
734           return 1; 
735      }
736
737      if (imagename[0] == '$') {
738           /* forth command string */
739           if (password)
740                check_password ("P");
741           prom_interpret(imagename+1);
742           return 0;
743      }
744
745      strncpy(imagepath, imagename, 1024);
746
747      if (!label && password)
748           check_password ("To boot a custom image you must enter the p");
749
750      if (!parse_device_path(imagepath, defdevice, defpart,
751                             "/vmlinux", &params->kernel)) {
752           prom_printf("%s: Unable to parse\n", imagepath);
753           return 0;
754      }
755      DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
756              params->kernel.part, params->kernel.file);
757
758      if (useconf) {
759           p = cfg_get_strg(label, "initrd");
760           if (p && *p) {
761                DEBUG_F("Parsing initrd path <%s>\n", p);
762                strncpy(initrdpath, p, 1024);
763                if (!parse_device_path(initrdpath, defdevice, defpart,
764                                       "/root.bin", &params->rd)) {
765                     prom_printf("%s: Unable to parse\n", imagepath);
766                     return 0;
767                }
768           }
769           p = cfg_get_strg(label, "sysmap");
770           if (p && *p) {
771                DEBUG_F("Parsing sysmap path <%s>\n", p);
772                strncpy(sysmappath, p, 1024);
773                if (!parse_device_path(sysmappath, defdevice, defpart,
774                                       "/boot/System.map", &params->sysmap)) {
775                     prom_printf("%s: Unable to parse\n", imagepath);
776                     return 0;
777                }
778           }
779      }
780      return 0;
781 }
782
783 /* This is derived from quik core. To be changed to first parse the headers
784  * doing lazy-loading, and then claim the memory before loading the kernel
785  * to it
786  * We also need to add initrd support to this whole mecanism
787  */
788 void
789 yaboot_text_ui(void)
790 {
791 #define MAX_HEADERS     32
792
793      struct boot_file_t file;
794      int                        result;
795      static struct boot_param_t params;
796      void               *initrd_base;
797      unsigned long      initrd_size;
798      void                *sysmap_base;
799      unsigned long      sysmap_size;
800      kernel_entry_t      kernel_entry;
801      struct bi_record*  birec;
802      char*               loc=NULL;
803      loadinfo_t          loadinfo;
804      void                *initrd_more,*initrd_want;
805      unsigned long       initrd_read;
806     
807      loadinfo.load_loc = 0;
808
809      for (;;) {
810           initrd_size = 0;
811           initrd_base = 0;
812           sysmap_base = 0;
813           sysmap_size = 0;
814         
815           if (get_params(&params))
816                return;
817           if (!params.kernel.file)
818                continue;
819         
820           prom_printf("Please wait, loading kernel...\n");
821
822           memset(&file, 0, sizeof(file));
823
824           if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
825               && params.kernel.file[0] != '\\') {
826                loc=(char*)malloc(strlen(params.kernel.file)+3);
827                if (!loc) {
828                     prom_printf ("malloc error\n");
829                     goto next;
830                }
831                strcpy(loc,boot.file);
832                strcat(loc,params.kernel.file);
833                free(params.kernel.file);
834                params.kernel.file=loc;
835           }
836           result = open_file(&params.kernel, &file);
837           if (result != FILE_ERR_OK) {
838                prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
839                prom_perror(result, params.kernel.file);
840                goto next;
841           }
842
843           /* Read the Elf e_ident, e_type and e_machine fields to
844            * determine Elf file type
845            */
846           if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
847                prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
848                file.fs->close(&file);
849                memset(&file, 0, sizeof(file));
850                goto next;
851           }
852
853           if (is_elf32(&loadinfo)) {
854                if (!load_elf32(&file, &loadinfo)) {
855                     file.fs->close(&file);
856                     memset(&file, 0, sizeof(file));
857                     goto next;
858                }
859                prom_printf("   Elf32 kernel loaded...\n");
860           } else if (is_elf64(&loadinfo)) {
861                if (!load_elf64(&file, &loadinfo)) {
862                     file.fs->close(&file);
863                     memset(&file, 0, sizeof(file));
864                     goto next;
865                }
866                prom_printf("   Elf64 kernel loaded...\n");
867           } else {
868                prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
869                file.fs->close(&file);
870                memset(&file, 0, sizeof(file));
871                goto next;
872           }
873           file.fs->close(&file);
874           memset(&file, 0, sizeof(file));
875
876           /* If sysmap, load it. 
877            */
878           if (params.sysmap.file) {
879                prom_printf("Loading System.map ...\n");
880                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
881                   && params.sysmap.file[0] != '\\') {
882                     if (loc) free(loc);
883                     loc=(char*)malloc(strlen(params.sysmap.file)+3);
884                     if (!loc) {
885                          prom_printf ("malloc error\n");
886                          goto next;
887                     }
888                     strcpy(loc,boot.file);
889                     strcat(loc,params.sysmap.file);
890                     free(params.sysmap.file);
891                     params.sysmap.file=loc;
892                }
893              
894                result = open_file(&params.sysmap, &file);
895                if (result != FILE_ERR_OK) {
896                     prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
897                     prom_perror(result, params.sysmap.file);
898                }
899                else {
900                     sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
901                     if (sysmap_base == (void *)-1) {
902                          prom_printf("Claim failed for sysmap memory\n");
903                          sysmap_base = 0;
904                     } else {
905                          sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
906                          if (sysmap_size == 0)
907                               sysmap_base = 0;
908                          else
909                               ((char *)sysmap_base)[sysmap_size++] = 0;
910                     }
911                     file.fs->close(&file);
912                     memset(&file, 0, sizeof(file));
913                }
914                if (sysmap_base) {
915                     prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
916                                 sysmap_base, sysmap_size >> 10);
917                     loadinfo.memsize += _ALIGN(0x100000, 0x1000);
918                } else {
919                     prom_printf("System.map load failed !\n");
920                     prom_pause();
921                }
922           }
923
924           /* If ramdisk, load it. For now, we can't tell the size it will be
925            * so we claim an arbitrary amount of 4Mb
926            */
927           if (params.rd.file) {
928                if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
929                   && params.kernel.file[0] != '\\')
930                {
931                     if (loc) free(loc);
932                     loc=(char*)malloc(strlen(params.rd.file)+3);
933                     if (!loc) {
934                          prom_printf ("Malloc error\n");
935                          goto next;
936                     }
937                     strcpy(loc,boot.file);
938                     strcat(loc,params.rd.file);
939                     free(params.rd.file);
940                     params.rd.file=loc;
941                }
942                prom_printf("Loading ramdisk...\n");
943                result = open_file(&params.rd, &file);
944                if (result != FILE_ERR_OK) {
945                     prom_printf("%s:%d,", params.rd.dev, params.rd.part);
946                     prom_perror(result, params.rd.file);
947                }
948                else {
949 #define INITRD_CHUNKSIZE 0x400000
950                     initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
951                     if (initrd_base == (void *)-1) {
952                          prom_printf("Claim failed for initrd memory\n");
953                          initrd_base = 0;
954                     } else {
955                          initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
956                          if (initrd_size == 0)
957                               initrd_base = 0;
958                          initrd_read = initrd_size;
959                          initrd_more = initrd_base;
960                          while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
961                               initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
962                               initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
963                               if (initrd_more != initrd_want) {
964                                    prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
965                                    break;
966                               }
967                               initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
968                               DEBUG_F("  block at %p rc=%lu\n",initrd_more,initrd_read);
969                               initrd_size += initrd_read;
970                          }
971                     }
972                     file.fs->close(&file);
973                     memset(&file, 0, sizeof(file));
974                }
975                if (initrd_base)
976                     prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
977                                 initrd_base, initrd_size >> 10);
978                else {
979                     prom_printf("ramdisk load failed !\n");
980                     prom_pause();
981                }
982           }
983
984           DEBUG_F("setting kernel args to: %s\n", params.args);
985           prom_setargs(params.args);
986           DEBUG_F("flushing icache...");
987           flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
988           DEBUG_F(" done\n");
989
990 /* 
991  * Fill mew boot infos
992  *
993  * The birec is low on memory, probably inside the malloc pool, so
994  * we don't write it earlier. At this point, we should not use anything
995  * coming from the malloc pool
996  */
997           birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
998
999 /* We make sure it's mapped. We map only 64k for now, it's plenty enough
1000  * we don't claim since this precise memory range may already be claimed
1001  * by the malloc pool
1002  */
1003           prom_map (birec, birec, 0x10000);
1004           DEBUG_F("birec at %p\n", birec);
1005           DEBUG_SLEEP;
1006
1007           birec->tag = BI_FIRST;
1008           birec->size = sizeof(struct bi_record);
1009           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1010         
1011           birec->tag = BI_BOOTLOADER_ID;
1012           sprintf( (char *)birec->data, "yaboot");
1013           birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1014           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1015         
1016           birec->tag = BI_MACHTYPE;
1017           birec->data[0] = _machine;
1018           birec->size = sizeof(struct bi_record) + sizeof(unsigned long);
1019           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1020
1021           if (sysmap_base) {
1022                birec->tag = BI_SYSMAP;
1023                birec->data[0] = (unsigned long)sysmap_base;
1024                birec->data[1] = sysmap_size;
1025                birec->size = sizeof(struct bi_record) + sizeof(unsigned long)*2;
1026                birec = (struct bi_record *)((unsigned long)birec + birec->size);
1027           }
1028           birec->tag = BI_LAST;
1029           birec->size = sizeof(struct bi_record);
1030           birec = (struct bi_record *)((unsigned long)birec + birec->size);
1031
1032           /* compute the kernel's entry point. */
1033           kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1034
1035           DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1036           DEBUG_F("kernel: arg1 = %p,\n"
1037                   "        arg2 = 0x%08lx,\n"
1038                   "        prom = %p,\n"
1039                   "        arg4 = %d,\n"
1040                   "        arg5 = %d\n\n",
1041                   initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1042
1043           DEBUG_F("Entering kernel...\n");
1044
1045           /* call the kernel with our stack. */
1046           kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1047           continue;
1048      next:
1049           ; /* do nothing */
1050      }
1051 }
1052
1053 static int
1054 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1055 {
1056      int                        i;
1057      Elf32_Ehdr         *e = &(loadinfo->elf.elf32hdr);
1058      Elf32_Phdr         *p, *ph;
1059      int                        size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1060      unsigned long      addr, loadaddr;
1061
1062      /* Read the rest of the Elf header... */
1063      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1064           prom_printf("\nCan't read Elf32 image header\n");
1065           return 0;
1066      }
1067
1068      DEBUG_F("Elf32 header:\n");
1069      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1070      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1071      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1072      DEBUG_F(" e.e_entry     = 0x%08x\n", (int)e->e_entry);
1073      DEBUG_F(" e.e_phoff     = 0x%08x\n", (int)e->e_phoff);
1074      DEBUG_F(" e.e_shoff     = 0x%08x\n", (int)e->e_shoff);
1075      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1076      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1077      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1078      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1079
1080      loadinfo->entry = e->e_entry;
1081
1082      if (e->e_phnum > MAX_HEADERS) {
1083           prom_printf ("Can only load kernels with one program header\n");
1084           return 0;
1085      }
1086
1087      ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1088      if (!ph) {
1089           prom_printf ("Malloc error\n");
1090           return 0;
1091      }
1092
1093      /* Now, we read the section header */
1094      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1095           prom_printf ("seek error\n");
1096           return 0;
1097      }
1098      if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1099          sizeof(Elf32_Phdr) * e->e_phnum) {
1100           prom_printf ("read error\n");
1101           return 0;
1102      }
1103
1104      /* Scan through the program header
1105       * HACK:  We must return the _memory size of the kernel image, not the
1106       *        file size (because we have to leave room before other boot
1107       *   infos. This code works as a side effect of the fact that
1108       *   we have one section and vaddr == p_paddr
1109       */
1110      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1111      p = ph;
1112      for (i = 0; i < e->e_phnum; ++i, ++p) {
1113           if (p->p_type != PT_LOAD || p->p_offset == 0)
1114                continue;
1115           if (loadinfo->memsize == 0) {
1116                loadinfo->offset = p->p_offset;
1117                loadinfo->memsize = p->p_memsz;
1118                loadinfo->filesize = p->p_filesz;
1119                loadinfo->load_loc = p->p_vaddr;
1120           } else {
1121                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1122                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1123           }
1124      }
1125
1126      if (loadinfo->memsize == 0) {
1127           prom_printf("Can't find a loadable segment !\n");
1128           return 0;
1129      }
1130
1131      /* leave some room (1Mb) for boot infos */
1132      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1133      /* Claim OF memory */
1134      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1135
1136      /* On some systems, loadaddr may already be claimed, so try some
1137       * other nearby addresses before giving up.
1138       */
1139      loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC32 ||
1140                  e->e_entry == 0) ? KERNELADDR : e->e_entry;
1141      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1142           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1143           if (loadinfo->base != (void *)-1) break;
1144      }
1145      if (loadinfo->base == (void *)-1) {
1146           prom_printf("Claim error, can't allocate kernel memory\n");
1147           return 0;
1148      }  
1149
1150      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1151              loadinfo->base, loadinfo->memsize);
1152      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1153              loadaddr, loadinfo->memsize);
1154
1155      /* Load the program segments... */
1156      p = ph;
1157      for (i = 0; i < e->e_phnum; ++i, ++p) {
1158           unsigned long offset;
1159           if (p->p_type != PT_LOAD || p->p_offset == 0)
1160                continue;
1161
1162           /* Now, we skip to the image itself */
1163           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1164                prom_printf ("Seek error\n");
1165                prom_release(loadinfo->base, loadinfo->memsize);
1166                return 0;
1167           }
1168           offset = p->p_vaddr - loadinfo->load_loc;
1169           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1170                prom_printf ("Read failed\n");
1171                prom_release(loadinfo->base, loadinfo->memsize);
1172                return 0;
1173           }
1174      }
1175
1176      free(ph);
1177     
1178      /* Return success at loading the Elf32 kernel */
1179      return 1;
1180 }
1181
1182 static int
1183 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1184 {
1185      int                        i;
1186      Elf64_Ehdr         *e = &(loadinfo->elf.elf64hdr);
1187      Elf64_Phdr         *p, *ph;
1188      int                        size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1189      unsigned long      addr, loadaddr;
1190
1191      /* Read the rest of the Elf header... */
1192      if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1193           prom_printf("\nCan't read Elf64 image header\n");
1194           return 0;
1195      }
1196
1197      DEBUG_F("Elf64 header:\n");
1198      DEBUG_F(" e.e_type      = %d\n", (int)e->e_type);
1199      DEBUG_F(" e.e_machine   = %d\n", (int)e->e_machine);
1200      DEBUG_F(" e.e_version   = %d\n", (int)e->e_version);
1201      DEBUG_F(" e.e_entry     = 0x%016lx\n", (long)e->e_entry);
1202      DEBUG_F(" e.e_phoff     = 0x%016lx\n", (long)e->e_phoff);
1203      DEBUG_F(" e.e_shoff     = 0x%016lx\n", (long)e->e_shoff);
1204      DEBUG_F(" e.e_flags     = %d\n", (int)e->e_flags);
1205      DEBUG_F(" e.e_ehsize    = 0x%08x\n", (int)e->e_ehsize);
1206      DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1207      DEBUG_F(" e.e_phnum     = %d\n", (int)e->e_phnum);
1208
1209      loadinfo->entry = e->e_entry;
1210
1211      if (e->e_phnum > MAX_HEADERS) {
1212           prom_printf ("Can only load kernels with one program header\n");
1213           return 0;
1214      }
1215
1216      ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1217      if (!ph) {
1218           prom_printf ("Malloc error\n");
1219           return 0;
1220      }
1221
1222      /* Now, we read the section header */
1223      if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1224           prom_printf ("Seek error\n");
1225           return 0;
1226      }
1227      if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1228          sizeof(Elf64_Phdr) * e->e_phnum) {
1229           prom_printf ("Read error\n");
1230           return 0;
1231      }
1232
1233      /* Scan through the program header
1234       * HACK:  We must return the _memory size of the kernel image, not the
1235       *        file size (because we have to leave room before other boot
1236       *   infos. This code works as a side effect of the fact that
1237       *   we have one section and vaddr == p_paddr
1238       */
1239      loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1240      p = ph;
1241      for (i = 0; i < e->e_phnum; ++i, ++p) {
1242           if (p->p_type != PT_LOAD || p->p_offset == 0)
1243                continue;
1244           if (loadinfo->memsize == 0) {
1245                loadinfo->offset = p->p_offset;
1246                loadinfo->memsize = p->p_memsz;
1247                loadinfo->filesize = p->p_filesz;
1248                loadinfo->load_loc = p->p_vaddr;
1249           } else {
1250                loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1251                loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1252           }
1253      }
1254
1255      if (loadinfo->memsize == 0) {
1256           prom_printf("Can't find a loadable segment !\n");
1257           return 0;
1258      }
1259
1260      /* leave some room (1Mb) for boot infos */
1261      loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1262      /* Claim OF memory */
1263      DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1264
1265      /* On some systems, loadaddr may already be claimed, so try some
1266       * other nearby addresses before giving up.
1267       */
1268      loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC64) ? KERNELADDR : e->e_entry;
1269      for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1270           loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1271           if (loadinfo->base != (void *)-1) break;
1272      }
1273      if (loadinfo->base == (void *)-1) {
1274           prom_printf("Claim error, can't allocate kernel memory\n");
1275           return 0;
1276      }  
1277
1278      DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1279              loadinfo->base, loadinfo->memsize);
1280      DEBUG_F("    wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1281              loadaddr, loadinfo->memsize);
1282
1283      /* Load the program segments... */
1284      p = ph;
1285      for (i = 0; i < e->e_phnum; ++i, ++p) {
1286           unsigned long offset;
1287           if (p->p_type != PT_LOAD || p->p_offset == 0)
1288                continue;
1289
1290           /* Now, we skip to the image itself */
1291           if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1292                prom_printf ("Seek error\n");
1293                prom_release(loadinfo->base, loadinfo->memsize);
1294                return 0;
1295           }
1296           offset = p->p_vaddr - loadinfo->load_loc;
1297           if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1298                prom_printf ("Read failed\n");
1299                prom_release(loadinfo->base, loadinfo->memsize);
1300                return 0;
1301           }
1302      }
1303
1304      free(ph);
1305     
1306      /* Return success at loading the Elf64 kernel */
1307      return 1;
1308 }
1309
1310 static int
1311 is_elf32(loadinfo_t *loadinfo)
1312 {
1313      Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1314
1315      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1316              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1317              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1318              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1319              e->e_ident[EI_CLASS] == ELFCLASS32  &&
1320              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1321              e->e_type            == ET_EXEC        &&
1322              e->e_machine         == EM_PPC);
1323 }
1324
1325 static int
1326 is_elf64(loadinfo_t *loadinfo)
1327 {
1328      Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1329
1330      return (e->e_ident[EI_MAG0]  == ELFMAG0        &&
1331              e->e_ident[EI_MAG1]  == ELFMAG1        &&
1332              e->e_ident[EI_MAG2]  == ELFMAG2        &&
1333              e->e_ident[EI_MAG3]  == ELFMAG3        &&
1334              e->e_ident[EI_CLASS] == ELFCLASS64  &&
1335              e->e_ident[EI_DATA]  == ELFDATA2MSB &&
1336              e->e_type            == ET_EXEC        &&
1337              e->e_machine         == EM_PPC64);
1338 }
1339
1340 static void
1341 setup_display(void)
1342 {
1343 #ifdef CONFIG_SET_COLORMAP
1344      static unsigned char default_colors[] = {
1345           0x00, 0x00, 0x00,
1346           0x00, 0x00, 0xaa,
1347           0x00, 0xaa, 0x00,
1348           0x00, 0xaa, 0xaa,
1349           0xaa, 0x00, 0x00,
1350           0xaa, 0x00, 0xaa,
1351           0xaa, 0x55, 0x00,
1352           0xaa, 0xaa, 0xaa,
1353           0x55, 0x55, 0x55,
1354           0x55, 0x55, 0xff,
1355           0x55, 0xff, 0x55,
1356           0x55, 0xff, 0xff,
1357           0xff, 0x55, 0x55,
1358           0xff, 0x55, 0xff,
1359           0xff, 0xff, 0x55,
1360           0xff, 0xff, 0xff
1361      };
1362      int i, result;
1363      prom_handle scrn = PROM_INVALID_HANDLE;
1364
1365      /* Try Apple's mac-boot screen ihandle */
1366      result = (int)call_prom_return("interpret", 1, 2,
1367                                     "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1368      DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1369
1370      if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1371           char type[32];
1372           /* Hrm... check to see if stdout is a display */
1373           scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1374           DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1375           if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1376                DEBUG_F("got it ! stdout is a screen\n");
1377                scrn = prom_stdout;
1378           } else {
1379                /* Else, we try to open the package */
1380                scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1381                DEBUG_F("Open screen result: %p\n", scrn);
1382           }
1383      }
1384         
1385      if (scrn == PROM_INVALID_HANDLE) {
1386           prom_printf("No screen device found !/n");
1387           return;
1388      }
1389      for(i=0;i<16;i++) {
1390           prom_set_color(scrn, i, default_colors[i*3],
1391                          default_colors[i*3+1], default_colors[i*3+2]);
1392      }
1393      prom_printf("\x1b[1;37m\x1b[2;40m");       
1394 #ifdef COLOR_TEST
1395      for (i=0;i<16; i++) {
1396           prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1397                       ansi_color_table[i].index,
1398                       ansi_color_table[i].value,
1399                       ansi_color_table[i].name,
1400                       ansi_color_table[i].name);
1401           prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1402                       ansi_color_table[i].index,
1403                       ansi_color_table[i].value+10,
1404                       ansi_color_table[i].name,
1405                       ansi_color_table[i].name);
1406      }
1407      prom_printf("\x1b[1;37m\x1b[2;40m");       
1408 #endif /* COLOR_TEST */
1409
1410 #if !DEBUG
1411      prom_printf("\xc");
1412 #endif /* !DEBUG */
1413
1414 #endif /* CONFIG_SET_COLORMAP */
1415 }
1416
1417 int
1418 yaboot_main(void)
1419 {
1420      char *ptype;
1421
1422      if (_machine == _MACH_Pmac)
1423           setup_display();
1424         
1425      prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1426      DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1427      if (bootdevice[0] == 0)
1428           prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1429      if (bootdevice[0] == 0) {
1430           prom_printf("Couldn't determine boot device\n");
1431           return -1;
1432      }
1433
1434      if (!parse_device_path(bootdevice, (_machine == _MACH_Pmac) ? "hd" : "disc",
1435                             -1, "", &boot)) {
1436           prom_printf("%s: Unable to parse\n", bootdevice);
1437           return -1;
1438      }
1439      DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1440              boot.dev, boot.part, boot.file);
1441
1442      if (strlen(boot.file)) {
1443           if (!strncmp(boot.file, "\\\\", 2))
1444                boot.file = "\\\\";
1445           else {
1446                char *p, *last;
1447                p = last = boot.file;
1448                while(*p) {
1449                     if (*p == '\\')
1450                          last = p;
1451                     p++;
1452                }
1453                if (p)
1454                     *(last) = 0;
1455                else
1456                     boot.file = "";
1457                if (strlen(boot.file))
1458                     strcat(boot.file, "\\");
1459           }
1460      }
1461      DEBUG_F("After path fixup: dev=%s, part=%d, file=%s\n",
1462              boot.dev, boot.part, boot.file);
1463
1464      useconf = load_config_file(boot.dev, boot.file, boot.part);
1465
1466      prom_printf("Welcome to yaboot version " VERSION "\n");
1467      prom_printf("Enter \"help\" to get some basic usage information\n");
1468
1469      /* I am fed up with lusers using the wrong partition type and
1470         mailing me *when* it breaks */
1471
1472      if (_machine == _MACH_Pmac) {
1473           char *entry = cfg_get_strg(0, "ptypewarning");
1474           int warn = 1;
1475           if (entry)
1476                warn = strcmp(entry,
1477                              "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1478           if (warn) {
1479                ptype = get_part_type(boot.dev, boot.part);
1480                if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1481                     prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1482                                 "         type should be: \"Apple_Bootstrap\"\n\n", ptype);
1483           }
1484      }
1485
1486      yaboot_text_ui();
1487         
1488      prom_printf("Bye.\n");
1489      return 0;
1490 }
1491
1492 /* 
1493  * Local variables:
1494  * c-file-style: "k&r"
1495  * c-basic-offset: 5
1496  * End:
1497  */