2 * Yaboot - secondary boot loader for Linux on PowerPC.
4 * Copyright (C) 2001, 2002 Ethan Benson
6 * Copyright (C) 1999, 2000, 2001 Benjamin Herrenschmidt
10 * Copyright (C) 2001 Peter Bergner
12 * portions based on poof
14 * Copyright (C) 1999 Marius Vollmer
16 * portions based on quik
18 * Copyright (C) 1996 Paul Mackerras.
20 * Because this program is derived from the corresponding file in the
21 * silo-0.64 distribution, it is also
23 * Copyright (C) 1996 Pete A. Zaitcev
25 * 1996 David S. Miller
26 * 1996 Miguel de Icaza
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 2 of the License, or
32 * (at your option) any later version.
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
39 * You should have received a copy of the GNU General Public License
40 * along with this program; if not, write to the Free Software
41 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
54 #include "linux/elf.h"
58 #define CONFIG_FILE_NAME "yaboot.conf"
59 #define CONFIG_FILE_MAX 0x8000 /* 32k */
61 #ifdef USE_MD5_PASSWORDS
63 #endif /* USE_MD5_PASSWORDS */
65 /* align addr on a size boundry - adjust address up if needed -- Cort */
66 #define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1)))
68 /* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at.
69 * These are used to determine whether we are booting a vmlinux, in
70 * which case, it will be loaded at KERNELADDR. Otherwise (eg zImage),
71 * we load the binary where it was linked at (ie, e_entry field in
74 #define KERNEL_LINK_ADDR_PPC32 0xC0000000UL
75 #define KERNEL_LINK_ADDR_PPC64 0xC000000000000000ULL
83 unsigned long memsize;
84 unsigned long filesize;
86 unsigned long load_loc;
90 typedef void (*kernel_entry_t)( void *,
96 /* Imported functions */
97 extern unsigned long reloc_offset(void);
98 extern long flush_icache_range(unsigned long start, unsigned long stop);
100 /* Exported functions */
101 int yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
103 /* Local functions */
104 static int yaboot_main(void);
105 static int is_elf32(loadinfo_t *loadinfo);
106 static int is_elf64(loadinfo_t *loadinfo);
107 static int load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
108 static int load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
109 static void setup_display(void);
111 /* Locals & globals */
114 char bootdevice[1024];
115 char *password = NULL;
116 struct boot_fspec_t boot;
117 int _machine = _MACH_Pmac;
120 #ifdef CONFIG_COLOR_TEXT
122 /* Color values for text ui */
123 static struct ansi_color_t {
127 } ansi_color_table[] = {
135 { "light-gray", 0, 37 },
136 { "dark-gray", 1, 30 },
137 { "light-blue", 1, 31 },
138 { "light-green", 1, 32 },
139 { "light-cyan", 1, 33 },
140 { "light-red", 1, 34 },
141 { "light-purple", 1, 35 },
147 /* Default colors for text ui */
150 #endif /* CONFIG_COLOR_TEXT */
154 static int test_data = 0;
156 static int pause_after;
157 static char *pause_message = "Type go<return> to continue.\n";
158 static char given_bootargs[1024];
159 static int given_bootargs_by_user = 0;
161 extern unsigned char linux_logo_red[];
162 extern unsigned char linux_logo_green[];
163 extern unsigned char linux_logo_blue[];
165 #define DEFAULT_TIMEOUT -1
167 /* Entry, currently called directly by crt0 (bss not inited) */
169 extern char* __bss_start;
172 static struct first_info *quik_fip = NULL;
175 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
178 void* malloc_base = NULL;
181 /* OF seems to do it, but I'm not very confident */
182 memset(&__bss_start, 0, &_end - &__bss_start);
184 /* Check for quik first stage bootloader (but I don't think we are
185 * compatible with it anyway, I'll look into backporting to older OF
188 if (r5 == 0xdeadbeef) {
190 quik_fip = (struct first_info *)r4;
193 /* Initialize OF interface */
194 prom_init ((prom_entry) r5);
196 /* Allocate some memory for malloc'ator */
197 malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
198 if (malloc_base == (void *)-1) {
199 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
200 MALLOCSIZE, MALLOCADDR);
203 malloc_init(malloc_base, MALLOCSIZE);
204 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
205 malloc_base, MALLOCSIZE);
207 /* A few useless DEBUG_F's */
208 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
209 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
210 DEBUG_F("test_data : %d (should be 0)\n", test_data);
211 DEBUG_F("&test_data : %p\n", &test_data);
212 DEBUG_F("&test_bss : %p\n", &test_bss);
213 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
215 /* ask the OF info if we're a chrp or pmac */
216 /* we need to set _machine before calling finish_device_tree */
217 root = prom_finddevice("/");
219 static char model[256];
220 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
221 !strncmp("chrp", model, 4))
222 _machine = _MACH_chrp;
224 if (prom_getprop(root, "model", model, 256 ) > 0 &&
225 !strncmp(model, "IBM", 3))
226 _machine = _MACH_chrp;
230 DEBUG_F("Running on _machine = %d\n", _machine);
234 result = yaboot_main();
236 /* Get rid of malloc pool */
238 prom_release(malloc_base, MALLOCSIZE);
239 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
249 #ifdef CONFIG_COLOR_TEXT
251 * Validify color for text ui
254 check_color_text_ui(char *color)
257 while(ansi_color_table[i].name) {
258 if (!strcmp(color, ansi_color_table[i].name))
264 #endif /* CONFIG_COLOR_TEXT */
267 void print_message_file(char *filename)
271 char *defdev = boot.dev;
272 int defpart = boot.part;
277 struct boot_file_t file;
278 struct boot_fspec_t msgfile;
280 defdev = cfg_get_strg(0, "device");
283 p = cfg_get_strg(0, "partition");
285 n = simple_strtol(p, &endp, 10);
286 if (endp != p && *endp == 0)
290 strncpy(msgpath, filename, sizeof(msgpath));
291 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
292 prom_printf("%s: Unable to parse\n", msgpath);
296 result = open_file(&msgfile, &file);
297 if (result != FILE_ERR_OK) {
298 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
299 prom_perror(result, msgfile.file);
308 memset(msg, 0, 2001);
310 if (file.fs->read(&file, 2000, msg) <= 0)
313 prom_printf("%s", msg);
317 file.fs->close(&file);
322 /* Currently, the config file must be at the root of the filesystem.
323 * todo: recognize the full path to myself and use it to load the
324 * config file. Handle the "\\" (blessed system folder)
327 load_config_file(char *device, char* path, int partition)
329 char *conf_file = NULL, *p;
330 struct boot_file_t file;
331 int sz, opened = 0, result = 0;
333 struct boot_fspec_t fspec;
335 /* Allocate a buffer for the config file */
336 conf_file = malloc(CONFIG_FILE_MAX);
338 prom_printf("Can't alloc config file buffer\n");
342 /* Build the path to the file */
343 if (_machine == _MACH_chrp)
344 strcpy(conf_path, "/etc/");
345 else if (path && *path)
346 strcpy(conf_path, path);
349 strcat(conf_path, CONFIG_FILE_NAME);
353 fspec.file = conf_path;
354 fspec.part = partition;
355 result = open_file(&fspec, &file);
356 if (result != FILE_ERR_OK) {
357 prom_printf("%s:%d,", fspec.dev, fspec.part);
358 prom_perror(result, fspec.file);
359 prom_printf("Can't open config file\n");
365 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
367 prom_printf("Error, can't read config file\n");
370 prom_printf("Config file read, %d bytes\n", sz);
374 file.fs->close(&file);
377 /* Call the parsing code in cfg.c */
378 if (cfg_parse(conf_path, conf_file, sz) < 0) {
379 prom_printf ("Syntax error or read error config\n");
383 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
385 /* Now, we do the initialisations stored in the config file */
386 p = cfg_get_strg(0, "init-code");
390 password = cfg_get_strg(0, "password");
392 #ifdef CONFIG_COLOR_TEXT
393 p = cfg_get_strg(0, "fgcolor");
395 DEBUG_F("fgcolor=%s\n", p);
396 fgcolor = check_color_text_ui(p);
398 prom_printf("Invalid fgcolor: \"%s\".\n", p);
401 p = cfg_get_strg(0, "bgcolor");
403 DEBUG_F("bgcolor=%s\n", p);
404 bgcolor = check_color_text_ui(p);
406 prom_printf("Invalid bgcolor: \"%s\".\n", p);
410 sprintf(temp, "%x to background-color", bgcolor);
411 prom_interpret(temp);
418 sprintf(temp, "%x to foreground-color", fgcolor);
419 prom_interpret(temp);
421 #endif /* CONFIG_COLOR_TEXT */
423 p = cfg_get_strg(0, "init-message");
425 prom_printf("%s\n", p);
427 p = cfg_get_strg(0, "message");
429 print_message_file(p);
436 file.fs->close(&file);
444 void maintabfunc (void)
448 prom_printf("boot: %s", cbuff);
453 word_split(char **linep, char **paramsp)
468 while (*p != 0 && *p != ' ')
477 make_params(char *label, char *params)
480 static char buffer[2048];
485 p = cfg_get_strg(label, "literal");
497 p = cfg_get_strg(label, "root");
504 if (cfg_get_flag(label, "read-only")) {
508 if (cfg_get_flag(label, "read-write")) {
512 p = cfg_get_strg(label, "ramdisk");
514 strcpy (q, "ramdisk=");
519 p = cfg_get_strg(label, "initrd-size");
521 strcpy (q, "ramdisk_size=");
526 if (cfg_get_flag(label, "novideo")) {
527 strcpy (q, "video=ofonly");
531 p = cfg_get_strg (label, "append");
538 pause_after = cfg_get_flag (label, "pause-after");
539 p = cfg_get_strg(label, "pause-message");
548 void check_password(char *str)
552 prom_printf("\n%s", str);
553 for (i = 0; i < 3; i++) {
554 prom_printf ("\nPassword: ");
556 cmdedit ((void (*)(void)) 0, 1);
558 #ifdef USE_MD5_PASSWORDS
559 if (!strncmp (password, "$1$", 3)) {
560 if (!check_md5_password(passwdbuff, password))
563 else if (!strcmp (password, passwdbuff))
566 if (!strcmp (password, passwdbuff))
568 #endif /* USE_MD5_PASSWORDS */
571 prom_printf ("Incorrect password. Try again.");
574 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
575 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
576 " ||----w |\n || ||\n");
578 prom_interpret("reset-all");
581 int get_params(struct boot_param_t* params)
587 char *imagename = 0, *label;
592 static int first = 1;
593 static char bootargs[1024];
594 static char imagepath[1024];
595 static char initrdpath[1024];
596 static char sysmappath[1024];
599 memset(params, 0, sizeof(*params));
601 params->kernel.part = -1;
602 params->rd.part = -1;
603 params->sysmap.part = -1;
610 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
611 imagename = bootargs;
612 word_split(&imagename, ¶ms->args);
613 timeout = DEFAULT_TIMEOUT;
615 prom_printf("Default supplied on the command line: %s ", imagename);
617 prom_printf("%s", params->args);
620 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
621 timeout = simple_strtol(q, NULL, 0);
624 prom_printf("boot: ");
629 end = beg + 100 * timeout;
631 c = prom_nbgetchar();
632 } while (c == -1 && prom_getms() <= end);
636 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
642 if (c != -1 && c != '\n' && c != '\r') {
645 } else if (c >= ' ') {
648 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
651 prom_printf("%s\n", cbuff);
656 if (c == '\n' || c == '\r') {
658 imagename = cfg_get_default();
660 prom_printf("%s", imagename);
662 prom_printf(" %s", params->args);
664 } else if (!singlekey) {
665 cmdedit(maintabfunc, 0);
667 strcpy(given_bootargs, cbuff);
668 given_bootargs_by_user = 1;
670 word_split(&imagename, ¶ms->args);
673 /* chrp gets this wrong, force it -- Cort */
674 if ( useconf && (!imagename || imagename[0] == 0 ))
675 imagename = cfg_get_default();
678 defdevice = boot.dev;
681 defdevice = cfg_get_strg(0, "device");
682 p = cfg_get_strg(0, "partition");
684 n = simple_strtol(p, &endp, 10);
685 if (endp != p && *endp == 0)
688 p = cfg_get_strg(0, "pause-message");
691 if (cfg_get_flag(0, "restricted"))
693 p = cfg_get_strg(imagename, "image");
697 defdevice = cfg_get_strg(label, "device");
698 if(!defdevice) defdevice=boot.dev;
699 p = cfg_get_strg(label, "partition");
701 n = simple_strtol(p, &endp, 10);
702 if (endp != p && *endp == 0)
705 if (cfg_get_flag(label, "restricted"))
708 if (params->args && password && restricted)
709 check_password ("To specify arguments for this image "
710 "you must enter the password.");
711 else if (password && !restricted)
712 check_password ("This image is restricted.");
714 params->args = make_params(label, params->args);
718 if (!strcmp (imagename, "help")) {
719 /* FIXME: defdevice shouldn't need to be reset all over the place */
720 if(!defdevice) defdevice = boot.dev;
722 "\nPress the tab key for a list of defined images.\n"
723 "The label marked with a \"*\" is is the default image, "
724 "press <return> to boot it.\n\n"
725 "To boot any other label simply type its name and press <return>.\n\n"
726 "To boot a kernel image which is not defined in the yaboot configuration \n"
727 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
728 "\"device:\" is the OpenFirmware device path to the disk the image \n"
729 "resides on, and \"partno\" is the partition number the image resides on.\n"
730 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
731 "device, if you only specify a filename you should not start it with a \",\"\n\n"
732 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
733 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
735 "partition=%d\n\n", defdevice, defpart);
739 if (!strcmp (imagename, "halt")) {
741 check_password ("Restricted command.");
745 if (!strcmp (imagename, "bye")) {
747 check_password ("Restricted command.");
753 if (imagename[0] == '$') {
754 /* forth command string */
756 check_password ("OpenFirmware commands are restricted.");
757 prom_interpret(imagename+1);
761 strncpy(imagepath, imagename, 1024);
763 if (!label && password)
764 check_password ("To boot a custom image you must enter the password.");
766 if (!parse_device_path(imagepath, defdevice, defpart,
767 "/vmlinux", ¶ms->kernel)) {
768 prom_printf("%s: Unable to parse\n", imagepath);
771 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
772 params->kernel.part, params->kernel.file);
775 p = cfg_get_strg(label, "initrd");
777 DEBUG_F("Parsing initrd path <%s>\n", p);
778 strncpy(initrdpath, p, 1024);
779 if (!parse_device_path(initrdpath, defdevice, defpart,
780 "/root.bin", ¶ms->rd)) {
781 prom_printf("%s: Unable to parse\n", imagepath);
785 p = cfg_get_strg(label, "sysmap");
787 DEBUG_F("Parsing sysmap path <%s>\n", p);
788 strncpy(sysmappath, p, 1024);
789 if (!parse_device_path(sysmappath, defdevice, defpart,
790 "/boot/System.map", ¶ms->sysmap)) {
791 prom_printf("%s: Unable to parse\n", imagepath);
799 /* This is derived from quik core. To be changed to first parse the headers
800 * doing lazy-loading, and then claim the memory before loading the kernel
802 * We also need to add initrd support to this whole mecanism
807 #define MAX_HEADERS 32
809 struct boot_file_t file;
811 static struct boot_param_t params;
813 unsigned long initrd_size;
815 unsigned long sysmap_size;
816 kernel_entry_t kernel_entry;
817 struct bi_record* birec;
820 void *initrd_more,*initrd_want;
821 unsigned long initrd_read;
823 loadinfo.load_loc = 0;
831 if (get_params(¶ms))
833 if (!params.kernel.file)
836 prom_printf("Please wait, loading kernel...\n");
838 memset(&file, 0, sizeof(file));
840 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
841 && params.kernel.file[0] != '\\') {
842 loc=(char*)malloc(strlen(params.kernel.file)+3);
844 prom_printf ("malloc error\n");
847 strcpy(loc,boot.file);
848 strcat(loc,params.kernel.file);
849 free(params.kernel.file);
850 params.kernel.file=loc;
852 result = open_file(¶ms.kernel, &file);
853 if (result != FILE_ERR_OK) {
854 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
855 prom_perror(result, params.kernel.file);
859 /* Read the Elf e_ident, e_type and e_machine fields to
860 * determine Elf file type
862 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
863 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
864 file.fs->close(&file);
865 memset(&file, 0, sizeof(file));
869 if (is_elf32(&loadinfo)) {
870 if (!load_elf32(&file, &loadinfo)) {
871 file.fs->close(&file);
872 memset(&file, 0, sizeof(file));
875 prom_printf(" Elf32 kernel loaded...\n");
876 } else if (is_elf64(&loadinfo)) {
877 if (!load_elf64(&file, &loadinfo)) {
878 file.fs->close(&file);
879 memset(&file, 0, sizeof(file));
882 prom_printf(" Elf64 kernel loaded...\n");
884 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
885 file.fs->close(&file);
886 memset(&file, 0, sizeof(file));
889 file.fs->close(&file);
890 memset(&file, 0, sizeof(file));
892 /* If sysmap, load it (only if booting a vmlinux).
894 if (flat_vmlinux && params.sysmap.file) {
895 prom_printf("Loading System.map ...\n");
896 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
897 && params.sysmap.file[0] != '\\') {
899 loc=(char*)malloc(strlen(params.sysmap.file)+3);
901 prom_printf ("malloc error\n");
904 strcpy(loc,boot.file);
905 strcat(loc,params.sysmap.file);
906 free(params.sysmap.file);
907 params.sysmap.file=loc;
910 result = open_file(¶ms.sysmap, &file);
911 if (result != FILE_ERR_OK) {
912 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
913 prom_perror(result, params.sysmap.file);
916 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
917 if (sysmap_base == (void *)-1) {
918 prom_printf("Claim failed for sysmap memory\n");
922 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
923 if (sysmap_size == 0)
926 ((char *)sysmap_base)[sysmap_size++] = 0;
928 file.fs->close(&file);
929 memset(&file, 0, sizeof(file));
932 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
933 sysmap_base, sysmap_size >> 10);
934 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
936 prom_printf("System.map load failed !\n");
941 /* If ramdisk, load it (only if booting a vmlinux). For now, we
942 * can't tell the size it will be so we claim an arbitrary amount
945 if (flat_vmlinux && params.rd.file) {
946 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
947 && params.kernel.file[0] != '\\')
950 loc=(char*)malloc(strlen(params.rd.file)+3);
952 prom_printf ("Malloc error\n");
955 strcpy(loc,boot.file);
956 strcat(loc,params.rd.file);
957 free(params.rd.file);
960 prom_printf("Loading ramdisk...\n");
961 result = open_file(¶ms.rd, &file);
962 if (result != FILE_ERR_OK) {
963 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
964 prom_perror(result, params.rd.file);
967 #define INITRD_CHUNKSIZE 0x100000
968 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
969 if (initrd_base == (void *)-1) {
970 prom_printf("Claim failed for initrd memory\n");
973 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
974 if (initrd_size == 0)
976 initrd_read = initrd_size;
977 initrd_more = initrd_base;
978 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
979 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
980 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
981 if (initrd_more != initrd_want) {
982 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
986 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
987 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
988 initrd_size += initrd_read;
991 file.fs->close(&file);
992 memset(&file, 0, sizeof(file));
995 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
996 initrd_base, initrd_size >> 10);
998 prom_printf("ramdisk load failed !\n");
1003 DEBUG_F("setting kernel args to: %s\n", params.args);
1004 prom_setargs(params.args);
1005 DEBUG_F("flushing icache...");
1006 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1011 * Fill new boot infos (only if booting a vmlinux).
1013 * The birec is low on memory, probably inside the malloc pool,
1014 * so we don't write it earlier. At this point, we should not
1015 * use anything coming from the malloc pool.
1017 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1019 /* We make sure it's mapped. We map only 64k for now, it's
1020 * plenty enough we don't claim since this precise memory
1021 * range may already be claimed by the malloc pool.
1023 prom_map (birec, birec, 0x10000);
1024 DEBUG_F("birec at %p\n", birec);
1027 birec->tag = BI_FIRST;
1028 birec->size = sizeof(struct bi_record);
1029 birec = (struct bi_record *)((ulong)birec + birec->size);
1031 birec->tag = BI_BOOTLOADER_ID;
1032 sprintf( (char *)birec->data, "yaboot");
1033 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1034 birec = (struct bi_record *)((ulong)birec + birec->size);
1036 birec->tag = BI_MACHTYPE;
1037 birec->data[0] = _machine;
1038 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1039 birec = (struct bi_record *)((ulong)birec + birec->size);
1042 birec->tag = BI_SYSMAP;
1043 birec->data[0] = (ulong)sysmap_base;
1044 birec->data[1] = sysmap_size;
1045 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1046 birec = (struct bi_record *)((ulong)birec + birec->size);
1048 birec->tag = BI_LAST;
1049 birec->size = sizeof(struct bi_record);
1050 birec = (struct bi_record *)((ulong)birec + birec->size);
1053 /* compute the kernel's entry point. */
1054 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1056 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1057 DEBUG_F("kernel: arg1 = %p,\n"
1058 " arg2 = 0x%08lx,\n"
1062 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1064 DEBUG_F("Entering kernel...\n");
1066 /* call the kernel with our stack. */
1067 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1075 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1078 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1080 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1081 unsigned long addr, loadaddr;
1083 /* Read the rest of the Elf header... */
1084 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1085 prom_printf("\nCan't read Elf32 image header\n");
1089 DEBUG_F("Elf32 header:\n");
1090 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1091 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1092 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1093 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1094 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1095 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1096 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1097 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1098 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1099 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1101 loadinfo->entry = e->e_entry;
1103 if (e->e_phnum > MAX_HEADERS) {
1104 prom_printf ("Can only load kernels with one program header\n");
1108 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1110 prom_printf ("Malloc error\n");
1114 /* Now, we read the section header */
1115 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1116 prom_printf ("seek error\n");
1119 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1120 sizeof(Elf32_Phdr) * e->e_phnum) {
1121 prom_printf ("read error\n");
1125 /* Scan through the program header
1126 * HACK: We must return the _memory size of the kernel image, not the
1127 * file size (because we have to leave room before other boot
1128 * infos. This code works as a side effect of the fact that
1129 * we have one section and vaddr == p_paddr
1131 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1133 for (i = 0; i < e->e_phnum; ++i, ++p) {
1134 if (p->p_type != PT_LOAD || p->p_offset == 0)
1136 if (loadinfo->memsize == 0) {
1137 loadinfo->offset = p->p_offset;
1138 loadinfo->memsize = p->p_memsz;
1139 loadinfo->filesize = p->p_filesz;
1140 loadinfo->load_loc = p->p_vaddr;
1142 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1143 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1147 if (loadinfo->memsize == 0) {
1148 prom_printf("Can't find a loadable segment !\n");
1152 /* leave some room (1Mb) for boot infos */
1153 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1154 /* Claim OF memory */
1155 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1157 /* Determine whether we are trying to boot a vmlinux or some
1158 * other binary image (eg, zImage). We load vmlinux's at
1159 * KERNELADDR and all other binaries at their e_entry value.
1161 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1163 loadaddr = KERNELADDR;
1166 loadaddr = loadinfo->load_loc;
1169 /* On some systems, loadaddr may already be claimed, so try some
1170 * other nearby addresses before giving up.
1172 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1173 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1174 if (loadinfo->base != (void *)-1) break;
1176 if (loadinfo->base == (void *)-1) {
1177 prom_printf("Claim error, can't allocate kernel memory\n");
1181 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1182 loadinfo->base, loadinfo->memsize);
1183 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1184 loadaddr, loadinfo->memsize);
1186 /* Load the program segments... */
1188 for (i = 0; i < e->e_phnum; ++i, ++p) {
1189 unsigned long offset;
1190 if (p->p_type != PT_LOAD || p->p_offset == 0)
1193 /* Now, we skip to the image itself */
1194 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1195 prom_printf ("Seek error\n");
1196 prom_release(loadinfo->base, loadinfo->memsize);
1199 offset = p->p_vaddr - loadinfo->load_loc;
1200 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1201 prom_printf ("Read failed\n");
1202 prom_release(loadinfo->base, loadinfo->memsize);
1209 /* Return success at loading the Elf32 kernel */
1219 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1222 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1224 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1225 unsigned long addr, loadaddr;
1227 /* Read the rest of the Elf header... */
1228 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1229 prom_printf("\nCan't read Elf64 image header\n");
1233 DEBUG_F("Elf64 header:\n");
1234 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1235 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1236 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1237 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1238 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1239 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1240 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1241 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1242 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1243 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1245 loadinfo->entry = e->e_entry;
1247 if (e->e_phnum > MAX_HEADERS) {
1248 prom_printf ("Can only load kernels with one program header\n");
1252 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1254 prom_printf ("Malloc error\n");
1258 /* Now, we read the section header */
1259 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1260 prom_printf ("Seek error\n");
1263 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1264 sizeof(Elf64_Phdr) * e->e_phnum) {
1265 prom_printf ("Read error\n");
1269 /* Scan through the program header
1270 * HACK: We must return the _memory size of the kernel image, not the
1271 * file size (because we have to leave room before other boot
1272 * infos. This code works as a side effect of the fact that
1273 * we have one section and vaddr == p_paddr
1275 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1277 for (i = 0; i < e->e_phnum; ++i, ++p) {
1278 if (p->p_type != PT_LOAD || p->p_offset == 0)
1280 if (loadinfo->memsize == 0) {
1281 loadinfo->offset = p->p_offset;
1282 loadinfo->memsize = p->p_memsz;
1283 loadinfo->filesize = p->p_filesz;
1284 loadinfo->load_loc = p->p_vaddr;
1286 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1287 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1291 if (loadinfo->memsize == 0) {
1292 prom_printf("Can't find a loadable segment !\n");
1296 /* leave some room (1Mb) for boot infos */
1297 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1298 /* Claim OF memory */
1299 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1301 /* Determine whether we are trying to boot a vmlinux or some
1302 * other binary image (eg, zImage). We load vmlinux's at
1303 * KERNELADDR and all other binaries at their e_entry value.
1305 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1307 loadaddr = KERNELADDR;
1310 loadaddr = e->e_entry;
1313 /* On some systems, loadaddr may already be claimed, so try some
1314 * other nearby addresses before giving up.
1316 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1317 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1318 if (loadinfo->base != (void *)-1) break;
1320 if (loadinfo->base == (void *)-1) {
1321 prom_printf("Claim error, can't allocate kernel memory\n");
1325 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1326 loadinfo->base, loadinfo->memsize);
1327 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1328 loadaddr, loadinfo->memsize);
1330 /* Load the program segments... */
1332 for (i = 0; i < e->e_phnum; ++i, ++p) {
1333 unsigned long offset;
1334 if (p->p_type != PT_LOAD || p->p_offset == 0)
1337 /* Now, we skip to the image itself */
1338 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1339 prom_printf ("Seek error\n");
1340 prom_release(loadinfo->base, loadinfo->memsize);
1343 offset = p->p_vaddr - loadinfo->load_loc;
1344 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1345 prom_printf ("Read failed\n");
1346 prom_release(loadinfo->base, loadinfo->memsize);
1353 /* Return success at loading the Elf64 kernel */
1363 is_elf32(loadinfo_t *loadinfo)
1365 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1367 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1368 e->e_ident[EI_MAG1] == ELFMAG1 &&
1369 e->e_ident[EI_MAG2] == ELFMAG2 &&
1370 e->e_ident[EI_MAG3] == ELFMAG3 &&
1371 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1372 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1373 e->e_type == ET_EXEC &&
1374 e->e_machine == EM_PPC);
1378 is_elf64(loadinfo_t *loadinfo)
1380 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1382 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1383 e->e_ident[EI_MAG1] == ELFMAG1 &&
1384 e->e_ident[EI_MAG2] == ELFMAG2 &&
1385 e->e_ident[EI_MAG3] == ELFMAG3 &&
1386 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1387 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1388 e->e_type == ET_EXEC &&
1389 e->e_machine == EM_PPC64);
1395 #ifdef CONFIG_SET_COLORMAP
1396 static unsigned char default_colors[] = {
1415 prom_handle scrn = PROM_INVALID_HANDLE;
1417 /* Try Apple's mac-boot screen ihandle */
1418 result = (int)call_prom_return("interpret", 1, 2,
1419 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1420 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1422 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1424 /* Hrm... check to see if stdout is a display */
1425 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1426 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1427 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1428 DEBUG_F("got it ! stdout is a screen\n");
1431 /* Else, we try to open the package */
1432 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1433 DEBUG_F("Open screen result: %p\n", scrn);
1437 if (scrn == PROM_INVALID_HANDLE) {
1438 prom_printf("No screen device found !/n");
1442 prom_set_color(scrn, i, default_colors[i*3],
1443 default_colors[i*3+1], default_colors[i*3+2]);
1445 prom_printf("\x1b[1;37m\x1b[2;40m");
1447 for (i=0;i<16; i++) {
1448 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1449 ansi_color_table[i].index,
1450 ansi_color_table[i].value,
1451 ansi_color_table[i].name,
1452 ansi_color_table[i].name);
1453 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1454 ansi_color_table[i].index,
1455 ansi_color_table[i].value+10,
1456 ansi_color_table[i].name,
1457 ansi_color_table[i].name);
1459 prom_printf("\x1b[1;37m\x1b[2;40m");
1460 #endif /* COLOR_TEST */
1466 #endif /* CONFIG_SET_COLORMAP */
1474 if (_machine == _MACH_Pmac)
1477 prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1478 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1479 if (bootdevice[0] == 0) {
1480 prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1481 DEBUG_F("boot-device = %s\n", bootdevice);
1483 if (bootdevice[0] == 0) {
1484 prom_printf("Couldn't determine boot device\n");
1488 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1489 prom_printf("%s: Unable to parse\n", bootdevice);
1492 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1493 boot.dev, boot.part, boot.file);
1495 if (strlen(boot.file)) {
1496 if (!strncmp(boot.file, "\\\\", 2))
1500 p = last = boot.file;
1510 if (strlen(boot.file))
1511 strcat(boot.file, "\\");
1514 DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1515 boot.dev, boot.part, boot.file);
1517 useconf = load_config_file(boot.dev, boot.file, boot.part);
1519 prom_printf("Welcome to yaboot version " VERSION "\n");
1520 prom_printf("Enter \"help\" to get some basic usage information\n");
1522 /* I am fed up with lusers using the wrong partition type and
1523 mailing me *when* it breaks */
1525 if (_machine == _MACH_Pmac) {
1526 char *entry = cfg_get_strg(0, "ptypewarning");
1529 warn = strcmp(entry,
1530 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1532 ptype = get_part_type(boot.dev, boot.part);
1533 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1534 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1535 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1543 prom_printf("Bye.\n");
1549 * c-file-style: "k&r"