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");
921 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
922 if (sysmap_size == 0)
925 ((char *)sysmap_base)[sysmap_size++] = 0;
927 file.fs->close(&file);
928 memset(&file, 0, sizeof(file));
931 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
932 sysmap_base, sysmap_size >> 10);
933 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
935 prom_printf("System.map load failed !\n");
940 /* If ramdisk, load it (only if booting a vmlinux). For now, we
941 * can't tell the size it will be so we claim an arbitrary amount
944 if (flat_vmlinux && params.rd.file) {
945 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
946 && params.kernel.file[0] != '\\')
949 loc=(char*)malloc(strlen(params.rd.file)+3);
951 prom_printf ("Malloc error\n");
954 strcpy(loc,boot.file);
955 strcat(loc,params.rd.file);
956 free(params.rd.file);
959 prom_printf("Loading ramdisk...\n");
960 result = open_file(¶ms.rd, &file);
961 if (result != FILE_ERR_OK) {
962 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
963 prom_perror(result, params.rd.file);
966 #define INITRD_CHUNKSIZE 0x400000
967 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
968 if (initrd_base == (void *)-1) {
969 prom_printf("Claim failed for initrd memory\n");
972 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
973 if (initrd_size == 0)
975 initrd_read = initrd_size;
976 initrd_more = initrd_base;
977 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
978 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
979 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
980 if (initrd_more != initrd_want) {
981 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
984 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
985 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
986 initrd_size += initrd_read;
989 file.fs->close(&file);
990 memset(&file, 0, sizeof(file));
993 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
994 initrd_base, initrd_size >> 10);
996 prom_printf("ramdisk load failed !\n");
1001 DEBUG_F("setting kernel args to: %s\n", params.args);
1002 prom_setargs(params.args);
1003 DEBUG_F("flushing icache...");
1004 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1009 * Fill new boot infos (only if booting a vmlinux).
1011 * The birec is low on memory, probably inside the malloc pool,
1012 * so we don't write it earlier. At this point, we should not
1013 * use anything coming from the malloc pool.
1015 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1017 /* We make sure it's mapped. We map only 64k for now, it's
1018 * plenty enough we don't claim since this precise memory
1019 * range may already be claimed by the malloc pool.
1021 prom_map (birec, birec, 0x10000);
1022 DEBUG_F("birec at %p\n", birec);
1025 birec->tag = BI_FIRST;
1026 birec->size = sizeof(struct bi_record);
1027 birec = (struct bi_record *)((ulong)birec + birec->size);
1029 birec->tag = BI_BOOTLOADER_ID;
1030 sprintf( (char *)birec->data, "yaboot");
1031 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1032 birec = (struct bi_record *)((ulong)birec + birec->size);
1034 birec->tag = BI_MACHTYPE;
1035 birec->data[0] = _machine;
1036 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1037 birec = (struct bi_record *)((ulong)birec + birec->size);
1040 birec->tag = BI_SYSMAP;
1041 birec->data[0] = (ulong)sysmap_base;
1042 birec->data[1] = sysmap_size;
1043 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1044 birec = (struct bi_record *)((ulong)birec + birec->size);
1046 birec->tag = BI_LAST;
1047 birec->size = sizeof(struct bi_record);
1048 birec = (struct bi_record *)((ulong)birec + birec->size);
1051 /* compute the kernel's entry point. */
1052 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1054 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1055 DEBUG_F("kernel: arg1 = %p,\n"
1056 " arg2 = 0x%08lx,\n"
1060 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1062 DEBUG_F("Entering kernel...\n");
1064 /* call the kernel with our stack. */
1065 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1073 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1076 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1078 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1079 unsigned long addr, loadaddr;
1081 /* Read the rest of the Elf header... */
1082 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1083 prom_printf("\nCan't read Elf32 image header\n");
1087 DEBUG_F("Elf32 header:\n");
1088 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1089 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1090 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1091 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1092 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1093 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1094 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1095 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1096 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1097 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1099 loadinfo->entry = e->e_entry;
1101 if (e->e_phnum > MAX_HEADERS) {
1102 prom_printf ("Can only load kernels with one program header\n");
1106 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1108 prom_printf ("Malloc error\n");
1112 /* Now, we read the section header */
1113 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1114 prom_printf ("seek error\n");
1117 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1118 sizeof(Elf32_Phdr) * e->e_phnum) {
1119 prom_printf ("read error\n");
1123 /* Scan through the program header
1124 * HACK: We must return the _memory size of the kernel image, not the
1125 * file size (because we have to leave room before other boot
1126 * infos. This code works as a side effect of the fact that
1127 * we have one section and vaddr == p_paddr
1129 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1131 for (i = 0; i < e->e_phnum; ++i, ++p) {
1132 if (p->p_type != PT_LOAD || p->p_offset == 0)
1134 if (loadinfo->memsize == 0) {
1135 loadinfo->offset = p->p_offset;
1136 loadinfo->memsize = p->p_memsz;
1137 loadinfo->filesize = p->p_filesz;
1138 loadinfo->load_loc = p->p_vaddr;
1140 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1141 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1145 if (loadinfo->memsize == 0) {
1146 prom_printf("Can't find a loadable segment !\n");
1150 /* leave some room (1Mb) for boot infos */
1151 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1152 /* Claim OF memory */
1153 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1155 /* Determine whether we are trying to boot a vmlinux or some
1156 * other binary image (eg, zImage). We load vmlinux's at
1157 * KERNELADDR and all other binaries at their e_entry value.
1159 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1161 loadaddr = KERNELADDR;
1164 loadaddr = e->e_entry;
1167 /* On some systems, loadaddr may already be claimed, so try some
1168 * other nearby addresses before giving up.
1170 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1171 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1172 if (loadinfo->base != (void *)-1) break;
1174 if (loadinfo->base == (void *)-1) {
1175 prom_printf("Claim error, can't allocate kernel memory\n");
1179 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1180 loadinfo->base, loadinfo->memsize);
1181 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1182 loadaddr, loadinfo->memsize);
1184 /* Load the program segments... */
1186 for (i = 0; i < e->e_phnum; ++i, ++p) {
1187 unsigned long offset;
1188 if (p->p_type != PT_LOAD || p->p_offset == 0)
1191 /* Now, we skip to the image itself */
1192 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1193 prom_printf ("Seek error\n");
1194 prom_release(loadinfo->base, loadinfo->memsize);
1197 offset = p->p_vaddr - loadinfo->load_loc;
1198 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1199 prom_printf ("Read failed\n");
1200 prom_release(loadinfo->base, loadinfo->memsize);
1207 /* Return success at loading the Elf32 kernel */
1217 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1220 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1222 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1223 unsigned long addr, loadaddr;
1225 /* Read the rest of the Elf header... */
1226 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1227 prom_printf("\nCan't read Elf64 image header\n");
1231 DEBUG_F("Elf64 header:\n");
1232 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1233 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1234 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1235 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1236 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1237 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1238 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1239 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1240 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1241 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1243 loadinfo->entry = e->e_entry;
1245 if (e->e_phnum > MAX_HEADERS) {
1246 prom_printf ("Can only load kernels with one program header\n");
1250 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1252 prom_printf ("Malloc error\n");
1256 /* Now, we read the section header */
1257 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1258 prom_printf ("Seek error\n");
1261 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1262 sizeof(Elf64_Phdr) * e->e_phnum) {
1263 prom_printf ("Read error\n");
1267 /* Scan through the program header
1268 * HACK: We must return the _memory size of the kernel image, not the
1269 * file size (because we have to leave room before other boot
1270 * infos. This code works as a side effect of the fact that
1271 * we have one section and vaddr == p_paddr
1273 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1275 for (i = 0; i < e->e_phnum; ++i, ++p) {
1276 if (p->p_type != PT_LOAD || p->p_offset == 0)
1278 if (loadinfo->memsize == 0) {
1279 loadinfo->offset = p->p_offset;
1280 loadinfo->memsize = p->p_memsz;
1281 loadinfo->filesize = p->p_filesz;
1282 loadinfo->load_loc = p->p_vaddr;
1284 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1285 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1289 if (loadinfo->memsize == 0) {
1290 prom_printf("Can't find a loadable segment !\n");
1294 /* leave some room (1Mb) for boot infos */
1295 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1296 /* Claim OF memory */
1297 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1299 /* Determine whether we are trying to boot a vmlinux or some
1300 * other binary image (eg, zImage). We load vmlinux's at
1301 * KERNELADDR and all other binaries at their e_entry value.
1303 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1305 loadaddr = KERNELADDR;
1308 loadaddr = e->e_entry;
1311 /* On some systems, loadaddr may already be claimed, so try some
1312 * other nearby addresses before giving up.
1314 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1315 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1316 if (loadinfo->base != (void *)-1) break;
1318 if (loadinfo->base == (void *)-1) {
1319 prom_printf("Claim error, can't allocate kernel memory\n");
1323 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1324 loadinfo->base, loadinfo->memsize);
1325 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1326 loadaddr, loadinfo->memsize);
1328 /* Load the program segments... */
1330 for (i = 0; i < e->e_phnum; ++i, ++p) {
1331 unsigned long offset;
1332 if (p->p_type != PT_LOAD || p->p_offset == 0)
1335 /* Now, we skip to the image itself */
1336 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1337 prom_printf ("Seek error\n");
1338 prom_release(loadinfo->base, loadinfo->memsize);
1341 offset = p->p_vaddr - loadinfo->load_loc;
1342 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1343 prom_printf ("Read failed\n");
1344 prom_release(loadinfo->base, loadinfo->memsize);
1351 /* Return success at loading the Elf64 kernel */
1361 is_elf32(loadinfo_t *loadinfo)
1363 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1365 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1366 e->e_ident[EI_MAG1] == ELFMAG1 &&
1367 e->e_ident[EI_MAG2] == ELFMAG2 &&
1368 e->e_ident[EI_MAG3] == ELFMAG3 &&
1369 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1370 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1371 e->e_type == ET_EXEC &&
1372 e->e_machine == EM_PPC);
1376 is_elf64(loadinfo_t *loadinfo)
1378 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1380 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1381 e->e_ident[EI_MAG1] == ELFMAG1 &&
1382 e->e_ident[EI_MAG2] == ELFMAG2 &&
1383 e->e_ident[EI_MAG3] == ELFMAG3 &&
1384 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1385 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1386 e->e_type == ET_EXEC &&
1387 e->e_machine == EM_PPC64);
1393 #ifdef CONFIG_SET_COLORMAP
1394 static unsigned char default_colors[] = {
1413 prom_handle scrn = PROM_INVALID_HANDLE;
1415 /* Try Apple's mac-boot screen ihandle */
1416 result = (int)call_prom_return("interpret", 1, 2,
1417 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1418 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1420 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1422 /* Hrm... check to see if stdout is a display */
1423 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1424 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1425 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1426 DEBUG_F("got it ! stdout is a screen\n");
1429 /* Else, we try to open the package */
1430 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1431 DEBUG_F("Open screen result: %p\n", scrn);
1435 if (scrn == PROM_INVALID_HANDLE) {
1436 prom_printf("No screen device found !/n");
1440 prom_set_color(scrn, i, default_colors[i*3],
1441 default_colors[i*3+1], default_colors[i*3+2]);
1443 prom_printf("\x1b[1;37m\x1b[2;40m");
1445 for (i=0;i<16; i++) {
1446 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1447 ansi_color_table[i].index,
1448 ansi_color_table[i].value,
1449 ansi_color_table[i].name,
1450 ansi_color_table[i].name);
1451 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1452 ansi_color_table[i].index,
1453 ansi_color_table[i].value+10,
1454 ansi_color_table[i].name,
1455 ansi_color_table[i].name);
1457 prom_printf("\x1b[1;37m\x1b[2;40m");
1458 #endif /* COLOR_TEST */
1464 #endif /* CONFIG_SET_COLORMAP */
1472 if (_machine == _MACH_Pmac)
1475 prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1476 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1477 if (bootdevice[0] == 0) {
1478 prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1479 DEBUG_F("boot-device = %s\n", bootdevice);
1481 if (bootdevice[0] == 0) {
1482 prom_printf("Couldn't determine boot device\n");
1486 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1487 prom_printf("%s: Unable to parse\n", bootdevice);
1490 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1491 boot.dev, boot.part, boot.file);
1493 if (strlen(boot.file)) {
1494 if (!strncmp(boot.file, "\\\\", 2))
1498 p = last = boot.file;
1508 if (strlen(boot.file))
1509 strcat(boot.file, "\\");
1512 DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1513 boot.dev, boot.part, boot.file);
1515 useconf = load_config_file(boot.dev, boot.file, boot.part);
1517 prom_printf("Welcome to yaboot version " VERSION "\n");
1518 prom_printf("Enter \"help\" to get some basic usage information\n");
1520 /* I am fed up with lusers using the wrong partition type and
1521 mailing me *when* it breaks */
1523 if (_machine == _MACH_Pmac) {
1524 char *entry = cfg_get_strg(0, "ptypewarning");
1527 warn = strcmp(entry,
1528 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1530 ptype = get_part_type(boot.dev, boot.part);
1531 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1532 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1533 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1541 prom_printf("Bye.\n");
1547 * c-file-style: "k&r"