1 /* Yaboot - secondary boot loader for Linux on ppc.
3 Copyright (C) 1999 Benjamin Herrenschmidt
7 Copyright (C) 1999 Marius Vollmer
11 Copyright (C) 1996 Paul Mackerras.
13 Because this program is derived from the corresponding file in the
14 silo-0.64 distribution, it is also
16 Copyright (C) 1996 Pete A. Zaitcev
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.
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.
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
47 #include "linux/elf.h"
51 #define CONFIG_FILE_NAME "yaboot.conf"
52 #define CONFIG_FILE_MAX 0x8000 /* 32k */
54 #ifdef USE_MD5_PASSWORDS
56 #endif /* USE_MD5_PASSWORDS */
58 /* align addr on a size boundry - adjust address up if needed -- Cort */
59 #define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1)))
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
67 #define KERNEL_LINK_ADDR_PPC32 0xC0000000UL
68 #define KERNEL_LINK_ADDR_PPC64 0xC000000000000000ULL
76 unsigned long memsize;
77 unsigned long filesize;
79 unsigned long load_loc;
83 typedef void (*kernel_entry_t)( void *,
89 /* Imported functions */
90 extern unsigned long reloc_offset(void);
91 extern long flush_icache_range(unsigned long start, unsigned long stop);
93 /* Exported functions */
94 int yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
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);
104 /* Locals & globals */
107 char bootdevice[1024];
108 char *password = NULL;
109 struct boot_fspec_t boot;
110 int _machine = _MACH_Pmac;
112 #ifdef CONFIG_COLOR_TEXT
114 /* Color values for text ui */
115 static struct ansi_color_t {
119 } ansi_color_table[] = {
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 },
139 /* Default colors for text ui */
142 #endif /* CONFIG_COLOR_TEXT */
146 static int test_data = 0;
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;
153 extern unsigned char linux_logo_red[];
154 extern unsigned char linux_logo_green[];
155 extern unsigned char linux_logo_blue[];
157 #define DEFAULT_TIMEOUT -1
159 /* Entry, currently called directly by crt0 (bss not inited) */
161 extern char* __bss_start;
164 static struct first_info *quik_fip = NULL;
167 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
170 void* malloc_base = NULL;
173 /* OF seems to do it, but I'm not very confident */
174 memset(&__bss_start, 0, &_end - &__bss_start);
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
180 if (r5 == 0xdeadbeef) {
182 quik_fip = (struct first_info *)r4;
185 /* Initialize OF interface */
186 prom_init ((prom_entry) r5);
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);
195 malloc_init(malloc_base, MALLOCSIZE);
196 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
197 malloc_base, MALLOCSIZE);
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);
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("/");
211 static char model[256];
212 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
213 !strncmp("chrp", model, 4))
214 _machine = _MACH_chrp;
216 if (prom_getprop(root, "model", model, 256 ) > 0 &&
217 !strncmp(model, "IBM", 3))
218 _machine = _MACH_chrp;
222 DEBUG_F("Running on _machine = %d\n", _machine);
226 result = yaboot_main();
228 /* Get rid of malloc pool */
230 prom_release(malloc_base, MALLOCSIZE);
231 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
241 #ifdef CONFIG_COLOR_TEXT
243 * Validify color for text ui
246 check_color_text_ui(char *color)
249 while(ansi_color_table[i].name) {
250 if (!strcmp(color, ansi_color_table[i].name))
256 #endif /* CONFIG_COLOR_TEXT */
258 /* Currently, the config file must be at the root of the filesystem.
259 * todo: recognize the full path to myself and use it to load the
260 * config file. Handle the "\\" (blessed system folder)
263 load_config_file(char *device, char* path, int partition)
265 char *conf_file = NULL, *p;
266 struct boot_file_t file;
267 int sz, opened = 0, result = 0;
269 struct boot_fspec_t fspec;
271 /* Allocate a buffer for the config file */
272 conf_file = malloc(CONFIG_FILE_MAX);
274 prom_printf("Can't alloc config file buffer\n");
278 /* Build the path to the file */
280 strcpy(conf_path, path);
281 else if ( _machine == _MACH_chrp )
282 strcpy(conf_path, "/etc/");
285 strcat(conf_path, CONFIG_FILE_NAME);
289 fspec.file = conf_path;
290 fspec.part = partition;
291 result = open_file(&fspec, &file);
292 if (result != FILE_ERR_OK) {
293 prom_printf("%s:%d,", fspec.dev, fspec.part);
294 prom_perror(result, fspec.file);
295 prom_printf("Can't open config file\n");
301 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
303 prom_printf("Error, can't read config file\n");
306 prom_printf("Config file read, %d bytes\n", sz);
310 file.fs->close(&file);
313 /* Call the parsing code in cfg.c */
314 if (cfg_parse(conf_path, conf_file, sz) < 0) {
315 prom_printf ("Syntax error or read error config\n");
319 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
321 /* Now, we do the initialisations stored in the config file */
322 p = cfg_get_strg(0, "init-code");
326 password = cfg_get_strg(0, "password");
328 #ifdef CONFIG_COLOR_TEXT
329 p = cfg_get_strg(0, "fgcolor");
331 DEBUG_F("fgcolor=%s\n", p);
332 fgcolor = check_color_text_ui(p);
334 prom_printf("Invalid fgcolor: \"%s\".\n", p);
337 p = cfg_get_strg(0, "bgcolor");
339 DEBUG_F("bgcolor=%s\n", p);
340 bgcolor = check_color_text_ui(p);
342 prom_printf("Invalid bgcolor: \"%s\".\n", p);
346 sprintf(temp, "%x to background-color", bgcolor);
347 prom_interpret(temp);
354 sprintf(temp, "%x to foreground-color", fgcolor);
355 prom_interpret(temp);
357 #endif /* CONFIG_COLOR_TEXT */
359 p = cfg_get_strg(0, "init-message");
361 prom_printf("%s\n", p);
363 p = cfg_get_strg(0, "message");
365 print_message_file(p);
373 file.fs->close(&file);
375 if (result != 1 && conf_file)
381 void maintabfunc (void)
385 prom_printf("boot: %s", cbuff);
390 word_split(char **linep, char **paramsp)
405 while (*p != 0 && *p != ' ')
414 make_params(char *label, char *params)
417 static char buffer[2048];
422 p = cfg_get_strg(label, "literal");
434 p = cfg_get_strg(label, "root");
441 if (cfg_get_flag(label, "read-only")) {
445 if (cfg_get_flag(label, "read-write")) {
449 p = cfg_get_strg(label, "ramdisk");
451 strcpy (q, "ramdisk=");
456 p = cfg_get_strg(label, "initrd-size");
458 strcpy (q, "ramdisk_size=");
463 if (cfg_get_flag(label, "novideo")) {
464 strcpy (q, "video=ofonly");
468 p = cfg_get_strg (label, "append");
475 pause_after = cfg_get_flag (label, "pause-after");
476 p = cfg_get_strg(label, "pause-message");
485 void check_password(char *str)
489 for (i = 0; i < 3; i++) {
490 prom_printf ("\n%sassword: ", str);
492 cmdedit ((void (*)(void)) 0, 1);
494 #ifdef USE_MD5_PASSWORDS
495 if (!strncmp (password, "$1$", 3)) {
496 if (!check_md5_password(passwdbuff, password))
499 else if (!strcmp (password, passwdbuff))
502 if (!strcmp (password, passwdbuff))
504 #endif /* USE_MD5_PASSWORDS */
506 prom_printf ("Password incorrect. Please try again...");
508 prom_printf ("Seems like you don't know the access password. Go away!\n");
510 prom_interpret("reset-all");
513 int get_params(struct boot_param_t* params)
519 char *imagename = 0, *label;
524 static int first = 1;
525 static char bootargs[1024];
526 static char imagepath[1024];
527 static char initrdpath[1024];
528 static char sysmappath[1024];
531 memset(params, 0, sizeof(*params));
533 params->kernel.part = -1;
534 params->rd.part = -1;
535 params->sysmap.part = -1;
542 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
543 imagename = bootargs;
544 word_split(&imagename, ¶ms->args);
545 timeout = DEFAULT_TIMEOUT;
547 prom_printf("Default supplied on the command line: %s ", imagename);
549 prom_printf("%s", params->args);
552 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
553 timeout = simple_strtol(q, NULL, 0);
556 prom_printf("boot: ");
561 end = beg + 100 * timeout;
563 c = prom_nbgetchar();
564 } while (c == -1 && prom_getms() <= end);
568 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
574 if (c != -1 && c != '\n' && c != '\r') {
577 } else if (c >= ' ') {
580 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
583 prom_printf("%s\n", cbuff);
588 if (c == '\n' || c == '\r') {
590 imagename = cfg_get_default();
592 prom_printf("%s", imagename);
594 prom_printf(" %s", params->args);
596 } else if (!singlekey) {
597 cmdedit(maintabfunc, 0);
599 strcpy(given_bootargs, cbuff);
600 given_bootargs_by_user = 1;
602 word_split(&imagename, ¶ms->args);
605 /* chrp gets this wrong, force it -- Cort */
606 if ( useconf && (!imagename || imagename[0] == 0 ))
607 imagename = cfg_get_default();
610 defdevice = boot.dev;
613 defdevice = cfg_get_strg(0, "device");
614 p = cfg_get_strg(0, "partition");
616 n = simple_strtol(p, &endp, 10);
617 if (endp != p && *endp == 0)
620 p = cfg_get_strg(0, "pause-message");
623 if (cfg_get_flag(0, "restricted"))
625 p = cfg_get_strg(imagename, "image");
629 defdevice = cfg_get_strg(label, "device");
630 if(!defdevice) defdevice=boot.dev;
631 p = cfg_get_strg(label, "partition");
633 n = simple_strtol(p, &endp, 10);
634 if (endp != p && *endp == 0)
637 if (cfg_get_flag(label, "restricted"))
640 if (params->args && password && restricted)
641 check_password ("To specify image arguments you must enter the p");
642 else if (password && !restricted)
643 check_password ("P");
645 params->args = make_params(label, params->args);
649 if (!strcmp (imagename, "help")) {
651 "\nPress the tab key for a list of defined images.\n"
652 "The label marked with a \"*\" is is the default image, "
653 "press <return> to boot it.\n\n"
654 "To boot any other label simply type its name and press <return>.\n\n"
655 "To boot a kernel image which is not defined in the yaboot configuration \n"
656 "file, enter the kernel image name as [device:][partno],/path, where \n"
657 "\"device:\" is the OpenFirmware device path to the disk the image \n"
658 "resides on, and \"partno\" is the partition number the image resides on.\n"
659 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
660 "device, if you only specify a filename you should not start it with a \",\"\n\n"
661 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
662 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
664 "partition=%d\n\n", defdevice, defpart);
668 if (!strcmp (imagename, "halt")) {
670 check_password ("P");
674 if (!strcmp (imagename, "bye")) {
676 check_password ("P");
682 if (imagename[0] == '$') {
683 /* forth command string */
685 check_password ("P");
686 prom_interpret(imagename+1);
690 strncpy(imagepath, imagename, 1024);
692 if (!label && password)
693 check_password ("To boot a custom image you must enter the p");
695 if (!parse_device_path(imagepath, defdevice, defpart,
696 "/vmlinux", ¶ms->kernel)) {
697 prom_printf("%s: Unable to parse\n", imagepath);
700 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
701 params->kernel.part, params->kernel.file);
704 p = cfg_get_strg(label, "initrd");
706 DEBUG_F("Parsing initrd path <%s>\n", p);
707 strncpy(initrdpath, p, 1024);
708 if (!parse_device_path(initrdpath, defdevice, defpart,
709 "/root.bin", ¶ms->rd)) {
710 prom_printf("%s: Unable to parse\n", imagepath);
714 p = cfg_get_strg(label, "sysmap");
716 DEBUG_F("Parsing sysmap path <%s>\n", p);
717 strncpy(sysmappath, p, 1024);
718 if (!parse_device_path(sysmappath, defdevice, defpart,
719 "/boot/System.map", ¶ms->sysmap)) {
720 prom_printf("%s: Unable to parse\n", imagepath);
728 /* This is derived from quik core. To be changed to first parse the headers
729 * doing lazy-loading, and then claim the memory before loading the kernel
731 * We also need to add initrd support to this whole mecanism
736 #define MAX_HEADERS 32
738 struct boot_file_t file;
740 static struct boot_param_t params;
742 unsigned long initrd_size;
744 unsigned long sysmap_size;
745 kernel_entry_t kernel_entry;
746 struct bi_record* birec;
749 void *initrd_more,*initrd_want;
750 unsigned long initrd_read;
752 loadinfo.load_loc = 0;
760 if (get_params(¶ms))
762 if (!params.kernel.file)
765 prom_printf("Please wait, loading kernel...\n");
767 memset(&file, 0, sizeof(file));
769 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
770 && params.kernel.file[0] != '\\') {
771 loc=(char*)malloc(strlen(params.kernel.file)+3);
773 prom_printf ("malloc error\n");
776 strcpy(loc,boot.file);
777 strcat(loc,params.kernel.file);
778 free(params.kernel.file);
779 params.kernel.file=loc;
781 result = open_file(¶ms.kernel, &file);
782 if (result != FILE_ERR_OK) {
783 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
784 prom_perror(result, params.kernel.file);
788 /* Read the Elf e_ident, e_type and e_machine fields to
789 * determine Elf file type
791 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
792 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
793 file.fs->close(&file);
794 memset(&file, 0, sizeof(file));
798 if (is_elf32(&loadinfo)) {
799 if (!load_elf32(&file, &loadinfo)) {
800 file.fs->close(&file);
801 memset(&file, 0, sizeof(file));
804 prom_printf(" Elf32 kernel loaded...\n");
805 } else if (is_elf64(&loadinfo)) {
806 if (!load_elf64(&file, &loadinfo)) {
807 file.fs->close(&file);
808 memset(&file, 0, sizeof(file));
811 prom_printf(" Elf64 kernel loaded...\n");
813 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
814 file.fs->close(&file);
815 memset(&file, 0, sizeof(file));
818 file.fs->close(&file);
819 memset(&file, 0, sizeof(file));
821 /* If sysmap, load it.
823 if (params.sysmap.file) {
824 prom_printf("Loading System.map ...\n");
825 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
826 && params.sysmap.file[0] != '\\') {
828 loc=(char*)malloc(strlen(params.sysmap.file)+3);
830 prom_printf ("malloc error\n");
833 strcpy(loc,boot.file);
834 strcat(loc,params.sysmap.file);
835 free(params.sysmap.file);
836 params.sysmap.file=loc;
839 result = open_file(¶ms.sysmap, &file);
840 if (result != FILE_ERR_OK) {
841 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
842 prom_perror(result, params.sysmap.file);
845 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
846 if (sysmap_base == (void *)-1) {
847 prom_printf("Claim failed for sysmap memory\n");
850 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
851 if (sysmap_size == 0)
854 ((char *)sysmap_base)[sysmap_size++] = 0;
856 file.fs->close(&file);
857 memset(&file, 0, sizeof(file));
860 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
861 sysmap_base, sysmap_size >> 10);
862 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
864 prom_printf("System.map load failed !\n");
869 /* If ramdisk, load it. For now, we can't tell the size it will be
870 * so we claim an arbitrary amount of 4Mb
872 if (params.rd.file) {
873 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
874 && params.kernel.file[0] != '\\')
877 loc=(char*)malloc(strlen(params.rd.file)+3);
879 prom_printf ("Malloc error\n");
882 strcpy(loc,boot.file);
883 strcat(loc,params.rd.file);
884 free(params.rd.file);
887 prom_printf("Loading ramdisk...\n");
888 result = open_file(¶ms.rd, &file);
889 if (result != FILE_ERR_OK) {
890 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
891 prom_perror(result, params.rd.file);
894 #define INITRD_CHUNKSIZE 0x400000
895 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
896 if (initrd_base == (void *)-1) {
897 prom_printf("Claim failed for initrd memory\n");
900 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
901 if (initrd_size == 0)
903 initrd_read = initrd_size;
904 initrd_more = initrd_base;
905 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
906 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
907 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
908 if (initrd_more != initrd_want) {
909 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
912 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
913 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
914 initrd_size += initrd_read;
917 file.fs->close(&file);
918 memset(&file, 0, sizeof(file));
921 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
922 initrd_base, initrd_size >> 10);
924 prom_printf("ramdisk load failed !\n");
929 DEBUG_F("setting kernel args to: %s\n", params.args);
930 prom_setargs(params.args);
931 DEBUG_F("flushing icache...");
932 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
936 * Fill mew boot infos
938 * The birec is low on memory, probably inside the malloc pool, so
939 * we don't write it earlier. At this point, we should not use anything
940 * coming from the malloc pool
942 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
944 /* We make sure it's mapped. We map only 64k for now, it's plenty enough
945 * we don't claim since this precise memory range may already be claimed
948 prom_map (birec, birec, 0x10000);
949 DEBUG_F("birec at %p\n", birec);
952 birec->tag = BI_FIRST;
953 birec->size = sizeof(struct bi_record);
954 birec = (struct bi_record *)((unsigned long)birec + birec->size);
956 birec->tag = BI_BOOTLOADER_ID;
957 sprintf( (char *)birec->data, "yaboot");
958 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
959 birec = (struct bi_record *)((unsigned long)birec + birec->size);
961 birec->tag = BI_MACHTYPE;
962 birec->data[0] = _machine;
963 birec->size = sizeof(struct bi_record) + sizeof(unsigned long);
964 birec = (struct bi_record *)((unsigned long)birec + birec->size);
967 birec->tag = BI_SYSMAP;
968 birec->data[0] = (unsigned long)sysmap_base;
969 birec->data[1] = sysmap_size;
970 birec->size = sizeof(struct bi_record) + sizeof(unsigned long)*2;
971 birec = (struct bi_record *)((unsigned long)birec + birec->size);
973 birec->tag = BI_LAST;
974 birec->size = sizeof(struct bi_record);
975 birec = (struct bi_record *)((unsigned long)birec + birec->size);
977 /* compute the kernel's entry point. */
978 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
980 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
981 DEBUG_F("kernel: arg1 = %p,\n"
986 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
988 DEBUG_F("Entering kernel...\n");
990 /* call the kernel with our stack. */
991 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
999 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1002 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1004 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1005 unsigned long addr, loadaddr;
1007 /* Read the rest of the Elf header... */
1008 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1009 prom_printf("\nCan't read Elf32 image header\n");
1013 DEBUG_F("Elf32 header:\n");
1014 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1015 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1016 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1017 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1018 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1019 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1020 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1021 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1022 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1023 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1025 loadinfo->entry = e->e_entry;
1027 if (e->e_phnum > MAX_HEADERS) {
1028 prom_printf ("Can only load kernels with one program header\n");
1032 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1034 prom_printf ("Malloc error\n");
1038 /* Now, we read the section header */
1039 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1040 prom_printf ("seek error\n");
1043 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1044 sizeof(Elf32_Phdr) * e->e_phnum) {
1045 prom_printf ("read error\n");
1049 /* Scan through the program header
1050 * HACK: We must return the _memory size of the kernel image, not the
1051 * file size (because we have to leave room before other boot
1052 * infos. This code works as a side effect of the fact that
1053 * we have one section and vaddr == p_paddr
1055 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1057 for (i = 0; i < e->e_phnum; ++i, ++p) {
1058 if (p->p_type != PT_LOAD || p->p_offset == 0)
1060 if (loadinfo->memsize == 0) {
1061 loadinfo->offset = p->p_offset;
1062 loadinfo->memsize = p->p_memsz;
1063 loadinfo->filesize = p->p_filesz;
1064 loadinfo->load_loc = p->p_vaddr;
1066 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1067 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1071 if (loadinfo->memsize == 0) {
1072 prom_printf("Can't find a loadable segment !\n");
1076 /* leave some room (1Mb) for boot infos */
1077 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1078 /* Claim OF memory */
1079 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1081 /* On some systems, loadaddr may already be claimed, so try some
1082 * other nearby addresses before giving up.
1084 loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC32 ||
1085 e->e_entry == 0) ? KERNELADDR : e->e_entry;
1086 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1087 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1088 if (loadinfo->base != (void *)-1) break;
1090 if (loadinfo->base == (void *)-1) {
1091 prom_printf("Claim error, can't allocate kernel memory\n");
1095 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1096 loadinfo->base, loadinfo->memsize);
1097 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1098 loadaddr, loadinfo->memsize);
1100 /* Load the program segments... */
1102 for (i = 0; i < e->e_phnum; ++i, ++p) {
1103 unsigned long offset;
1104 if (p->p_type != PT_LOAD || p->p_offset == 0)
1107 /* Now, we skip to the image itself */
1108 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1109 prom_printf ("Seek error\n");
1110 prom_release(loadinfo->base, loadinfo->memsize);
1113 offset = p->p_vaddr - loadinfo->load_loc;
1114 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1115 prom_printf ("Read failed\n");
1116 prom_release(loadinfo->base, loadinfo->memsize);
1123 /* Return success at loading the Elf32 kernel */
1128 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1131 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1133 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1134 unsigned long addr, loadaddr;
1136 /* Read the rest of the Elf header... */
1137 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1138 prom_printf("\nCan't read Elf64 image header\n");
1142 DEBUG_F("Elf64 header:\n");
1143 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1144 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1145 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1146 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1147 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1148 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1149 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1150 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1151 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1152 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1154 loadinfo->entry = e->e_entry;
1156 if (e->e_phnum > MAX_HEADERS) {
1157 prom_printf ("Can only load kernels with one program header\n");
1161 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1163 prom_printf ("Malloc error\n");
1167 /* Now, we read the section header */
1168 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1169 prom_printf ("Seek error\n");
1172 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1173 sizeof(Elf64_Phdr) * e->e_phnum) {
1174 prom_printf ("Read error\n");
1178 /* Scan through the program header
1179 * HACK: We must return the _memory size of the kernel image, not the
1180 * file size (because we have to leave room before other boot
1181 * infos. This code works as a side effect of the fact that
1182 * we have one section and vaddr == p_paddr
1184 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1186 for (i = 0; i < e->e_phnum; ++i, ++p) {
1187 if (p->p_type != PT_LOAD || p->p_offset == 0)
1189 if (loadinfo->memsize == 0) {
1190 loadinfo->offset = p->p_offset;
1191 loadinfo->memsize = p->p_memsz;
1192 loadinfo->filesize = p->p_filesz;
1193 loadinfo->load_loc = p->p_vaddr;
1195 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1196 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1200 if (loadinfo->memsize == 0) {
1201 prom_printf("Can't find a loadable segment !\n");
1205 /* leave some room (1Mb) for boot infos */
1206 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1207 /* Claim OF memory */
1208 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1210 /* On some systems, loadaddr may already be claimed, so try some
1211 * other nearby addresses before giving up.
1213 loadaddr = (e->e_entry == KERNEL_LINK_ADDR_PPC64) ? KERNELADDR : e->e_entry;
1214 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1215 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1216 if (loadinfo->base != (void *)-1) break;
1218 if (loadinfo->base == (void *)-1) {
1219 prom_printf("Claim error, can't allocate kernel memory\n");
1223 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1224 loadinfo->base, loadinfo->memsize);
1225 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1226 loadaddr, loadinfo->memsize);
1228 /* Load the program segments... */
1230 for (i = 0; i < e->e_phnum; ++i, ++p) {
1231 unsigned long offset;
1232 if (p->p_type != PT_LOAD || p->p_offset == 0)
1235 /* Now, we skip to the image itself */
1236 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1237 prom_printf ("Seek error\n");
1238 prom_release(loadinfo->base, loadinfo->memsize);
1241 offset = p->p_vaddr - loadinfo->load_loc;
1242 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1243 prom_printf ("Read failed\n");
1244 prom_release(loadinfo->base, loadinfo->memsize);
1251 /* Return success at loading the Elf64 kernel */
1256 is_elf32(loadinfo_t *loadinfo)
1258 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1260 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1261 e->e_ident[EI_MAG1] == ELFMAG1 &&
1262 e->e_ident[EI_MAG2] == ELFMAG2 &&
1263 e->e_ident[EI_MAG3] == ELFMAG3 &&
1264 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1265 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1266 e->e_type == ET_EXEC &&
1267 e->e_machine == EM_PPC);
1271 is_elf64(loadinfo_t *loadinfo)
1273 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1275 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1276 e->e_ident[EI_MAG1] == ELFMAG1 &&
1277 e->e_ident[EI_MAG2] == ELFMAG2 &&
1278 e->e_ident[EI_MAG3] == ELFMAG3 &&
1279 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1280 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1281 e->e_type == ET_EXEC &&
1282 e->e_machine == EM_PPC64);
1288 #ifdef CONFIG_SET_COLORMAP
1289 static unsigned char default_colors[] = {
1308 prom_handle scrn = PROM_INVALID_HANDLE;
1310 /* Try Apple's mac-boot screen ihandle */
1311 result = (int)call_prom_return("interpret", 1, 2,
1312 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1313 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1315 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1317 /* Hrm... check to see if stdout is a display */
1318 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1319 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1320 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1321 DEBUG_F("got it ! stdout is a screen\n");
1324 /* Else, we try to open the package */
1325 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1326 DEBUG_F("Open screen result: %p\n", scrn);
1330 if (scrn == PROM_INVALID_HANDLE) {
1331 prom_printf("No screen device found !/n");
1335 prom_set_color(scrn, i, default_colors[i*3],
1336 default_colors[i*3+1], default_colors[i*3+2]);
1338 prom_printf("\x1b[1;37m\x1b[2;40m");
1340 for (i=0;i<16; i++) {
1341 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1342 ansi_color_table[i].index,
1343 ansi_color_table[i].value,
1344 ansi_color_table[i].name,
1345 ansi_color_table[i].name);
1346 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1347 ansi_color_table[i].index,
1348 ansi_color_table[i].value+10,
1349 ansi_color_table[i].name,
1350 ansi_color_table[i].name);
1352 prom_printf("\x1b[1;37m\x1b[2;40m");
1353 #endif /* COLOR_TEST */
1359 #endif /* CONFIG_SET_COLORMAP */
1367 if (_machine == _MACH_Pmac)
1370 prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1371 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1372 if (bootdevice[0] == 0)
1373 prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1374 if (bootdevice[0] == 0) {
1375 prom_printf("Couldn't determine boot device\n");
1379 if (!parse_device_path(bootdevice, (_machine == _MACH_Pmac) ? "hd" : "disc",
1381 prom_printf("%s: Unable to parse\n", bootdevice);
1384 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1385 boot.dev, boot.part, boot.file);
1387 if (strlen(boot.file)) {
1388 if (!strncmp(boot.file, "\\\\", 2))
1392 p = last = boot.file;
1402 if (strlen(boot.file))
1403 strcat(boot.file, "\\");
1406 DEBUG_F("After path fixup: dev=%s, part=%d, file=%s\n",
1407 boot.dev, boot.part, boot.file);
1409 useconf = load_config_file(boot.dev, boot.file, boot.part);
1411 prom_printf("Welcome to yaboot version " VERSION "\n");
1412 prom_printf("Enter \"help\" to get some basic usage information\n");
1414 /* I am fed up with lusers using the wrong partition type and
1415 mailing me *when* it breaks */
1417 if (_machine == _MACH_Pmac) {
1418 char *entry = cfg_get_strg(0, "ptypewarning");
1421 warn = strcmp(entry,
1422 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1424 ptype = get_part_type(boot.dev, boot.part);
1425 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1426 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1427 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1433 prom_printf("Bye.\n");
1439 * c-file-style: "K&R"