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 0x100000
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);
985 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
986 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
987 initrd_size += initrd_read;
990 file.fs->close(&file);
991 memset(&file, 0, sizeof(file));
994 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
995 initrd_base, initrd_size >> 10);
997 prom_printf("ramdisk load failed !\n");
1002 DEBUG_F("setting kernel args to: %s\n", params.args);
1003 prom_setargs(params.args);
1004 DEBUG_F("flushing icache...");
1005 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1010 * Fill new boot infos (only if booting a vmlinux).
1012 * The birec is low on memory, probably inside the malloc pool,
1013 * so we don't write it earlier. At this point, we should not
1014 * use anything coming from the malloc pool.
1016 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1018 /* We make sure it's mapped. We map only 64k for now, it's
1019 * plenty enough we don't claim since this precise memory
1020 * range may already be claimed by the malloc pool.
1022 prom_map (birec, birec, 0x10000);
1023 DEBUG_F("birec at %p\n", birec);
1026 birec->tag = BI_FIRST;
1027 birec->size = sizeof(struct bi_record);
1028 birec = (struct bi_record *)((ulong)birec + birec->size);
1030 birec->tag = BI_BOOTLOADER_ID;
1031 sprintf( (char *)birec->data, "yaboot");
1032 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1033 birec = (struct bi_record *)((ulong)birec + birec->size);
1035 birec->tag = BI_MACHTYPE;
1036 birec->data[0] = _machine;
1037 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1038 birec = (struct bi_record *)((ulong)birec + birec->size);
1041 birec->tag = BI_SYSMAP;
1042 birec->data[0] = (ulong)sysmap_base;
1043 birec->data[1] = sysmap_size;
1044 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1045 birec = (struct bi_record *)((ulong)birec + birec->size);
1047 birec->tag = BI_LAST;
1048 birec->size = sizeof(struct bi_record);
1049 birec = (struct bi_record *)((ulong)birec + birec->size);
1052 /* compute the kernel's entry point. */
1053 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1055 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1056 DEBUG_F("kernel: arg1 = %p,\n"
1057 " arg2 = 0x%08lx,\n"
1061 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1063 DEBUG_F("Entering kernel...\n");
1065 /* call the kernel with our stack. */
1066 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1074 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1077 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1079 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1080 unsigned long addr, loadaddr;
1082 /* Read the rest of the Elf header... */
1083 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1084 prom_printf("\nCan't read Elf32 image header\n");
1088 DEBUG_F("Elf32 header:\n");
1089 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1090 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1091 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1092 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1093 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1094 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1095 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1096 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1097 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1098 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1100 loadinfo->entry = e->e_entry;
1102 if (e->e_phnum > MAX_HEADERS) {
1103 prom_printf ("Can only load kernels with one program header\n");
1107 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1109 prom_printf ("Malloc error\n");
1113 /* Now, we read the section header */
1114 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1115 prom_printf ("seek error\n");
1118 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1119 sizeof(Elf32_Phdr) * e->e_phnum) {
1120 prom_printf ("read error\n");
1124 /* Scan through the program header
1125 * HACK: We must return the _memory size of the kernel image, not the
1126 * file size (because we have to leave room before other boot
1127 * infos. This code works as a side effect of the fact that
1128 * we have one section and vaddr == p_paddr
1130 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1132 for (i = 0; i < e->e_phnum; ++i, ++p) {
1133 if (p->p_type != PT_LOAD || p->p_offset == 0)
1135 if (loadinfo->memsize == 0) {
1136 loadinfo->offset = p->p_offset;
1137 loadinfo->memsize = p->p_memsz;
1138 loadinfo->filesize = p->p_filesz;
1139 loadinfo->load_loc = p->p_vaddr;
1141 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1142 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1146 if (loadinfo->memsize == 0) {
1147 prom_printf("Can't find a loadable segment !\n");
1151 /* leave some room (1Mb) for boot infos */
1152 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1153 /* Claim OF memory */
1154 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1156 /* Determine whether we are trying to boot a vmlinux or some
1157 * other binary image (eg, zImage). We load vmlinux's at
1158 * KERNELADDR and all other binaries at their e_entry value.
1160 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1162 loadaddr = KERNELADDR;
1165 loadaddr = loadinfo->load_loc;
1168 /* On some systems, loadaddr may already be claimed, so try some
1169 * other nearby addresses before giving up.
1171 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1172 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1173 if (loadinfo->base != (void *)-1) break;
1175 if (loadinfo->base == (void *)-1) {
1176 prom_printf("Claim error, can't allocate kernel memory\n");
1180 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1181 loadinfo->base, loadinfo->memsize);
1182 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1183 loadaddr, loadinfo->memsize);
1185 /* Load the program segments... */
1187 for (i = 0; i < e->e_phnum; ++i, ++p) {
1188 unsigned long offset;
1189 if (p->p_type != PT_LOAD || p->p_offset == 0)
1192 /* Now, we skip to the image itself */
1193 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1194 prom_printf ("Seek error\n");
1195 prom_release(loadinfo->base, loadinfo->memsize);
1198 offset = p->p_vaddr - loadinfo->load_loc;
1199 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1200 prom_printf ("Read failed\n");
1201 prom_release(loadinfo->base, loadinfo->memsize);
1208 /* Return success at loading the Elf32 kernel */
1218 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1221 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1223 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1224 unsigned long addr, loadaddr;
1226 /* Read the rest of the Elf header... */
1227 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1228 prom_printf("\nCan't read Elf64 image header\n");
1232 DEBUG_F("Elf64 header:\n");
1233 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1234 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1235 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1236 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1237 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1238 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1239 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1240 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1241 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1242 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1244 loadinfo->entry = e->e_entry;
1246 if (e->e_phnum > MAX_HEADERS) {
1247 prom_printf ("Can only load kernels with one program header\n");
1251 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1253 prom_printf ("Malloc error\n");
1257 /* Now, we read the section header */
1258 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1259 prom_printf ("Seek error\n");
1262 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1263 sizeof(Elf64_Phdr) * e->e_phnum) {
1264 prom_printf ("Read error\n");
1268 /* Scan through the program header
1269 * HACK: We must return the _memory size of the kernel image, not the
1270 * file size (because we have to leave room before other boot
1271 * infos. This code works as a side effect of the fact that
1272 * we have one section and vaddr == p_paddr
1274 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1276 for (i = 0; i < e->e_phnum; ++i, ++p) {
1277 if (p->p_type != PT_LOAD || p->p_offset == 0)
1279 if (loadinfo->memsize == 0) {
1280 loadinfo->offset = p->p_offset;
1281 loadinfo->memsize = p->p_memsz;
1282 loadinfo->filesize = p->p_filesz;
1283 loadinfo->load_loc = p->p_vaddr;
1285 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1286 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1290 if (loadinfo->memsize == 0) {
1291 prom_printf("Can't find a loadable segment !\n");
1295 /* leave some room (1Mb) for boot infos */
1296 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1297 /* Claim OF memory */
1298 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1300 /* Determine whether we are trying to boot a vmlinux or some
1301 * other binary image (eg, zImage). We load vmlinux's at
1302 * KERNELADDR and all other binaries at their e_entry value.
1304 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1306 loadaddr = KERNELADDR;
1309 loadaddr = e->e_entry;
1312 /* On some systems, loadaddr may already be claimed, so try some
1313 * other nearby addresses before giving up.
1315 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1316 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1317 if (loadinfo->base != (void *)-1) break;
1319 if (loadinfo->base == (void *)-1) {
1320 prom_printf("Claim error, can't allocate kernel memory\n");
1324 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1325 loadinfo->base, loadinfo->memsize);
1326 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1327 loadaddr, loadinfo->memsize);
1329 /* Load the program segments... */
1331 for (i = 0; i < e->e_phnum; ++i, ++p) {
1332 unsigned long offset;
1333 if (p->p_type != PT_LOAD || p->p_offset == 0)
1336 /* Now, we skip to the image itself */
1337 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1338 prom_printf ("Seek error\n");
1339 prom_release(loadinfo->base, loadinfo->memsize);
1342 offset = p->p_vaddr - loadinfo->load_loc;
1343 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1344 prom_printf ("Read failed\n");
1345 prom_release(loadinfo->base, loadinfo->memsize);
1352 /* Return success at loading the Elf64 kernel */
1362 is_elf32(loadinfo_t *loadinfo)
1364 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1366 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1367 e->e_ident[EI_MAG1] == ELFMAG1 &&
1368 e->e_ident[EI_MAG2] == ELFMAG2 &&
1369 e->e_ident[EI_MAG3] == ELFMAG3 &&
1370 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1371 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1372 e->e_type == ET_EXEC &&
1373 e->e_machine == EM_PPC);
1377 is_elf64(loadinfo_t *loadinfo)
1379 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1381 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1382 e->e_ident[EI_MAG1] == ELFMAG1 &&
1383 e->e_ident[EI_MAG2] == ELFMAG2 &&
1384 e->e_ident[EI_MAG3] == ELFMAG3 &&
1385 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1386 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1387 e->e_type == ET_EXEC &&
1388 e->e_machine == EM_PPC64);
1394 #ifdef CONFIG_SET_COLORMAP
1395 static unsigned char default_colors[] = {
1414 prom_handle scrn = PROM_INVALID_HANDLE;
1416 /* Try Apple's mac-boot screen ihandle */
1417 result = (int)call_prom_return("interpret", 1, 2,
1418 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1419 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1421 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1423 /* Hrm... check to see if stdout is a display */
1424 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1425 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1426 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1427 DEBUG_F("got it ! stdout is a screen\n");
1430 /* Else, we try to open the package */
1431 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1432 DEBUG_F("Open screen result: %p\n", scrn);
1436 if (scrn == PROM_INVALID_HANDLE) {
1437 prom_printf("No screen device found !/n");
1441 prom_set_color(scrn, i, default_colors[i*3],
1442 default_colors[i*3+1], default_colors[i*3+2]);
1444 prom_printf("\x1b[1;37m\x1b[2;40m");
1446 for (i=0;i<16; i++) {
1447 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1448 ansi_color_table[i].index,
1449 ansi_color_table[i].value,
1450 ansi_color_table[i].name,
1451 ansi_color_table[i].name);
1452 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1453 ansi_color_table[i].index,
1454 ansi_color_table[i].value+10,
1455 ansi_color_table[i].name,
1456 ansi_color_table[i].name);
1458 prom_printf("\x1b[1;37m\x1b[2;40m");
1459 #endif /* COLOR_TEST */
1465 #endif /* CONFIG_SET_COLORMAP */
1473 if (_machine == _MACH_Pmac)
1476 prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1477 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1478 if (bootdevice[0] == 0) {
1479 prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1480 DEBUG_F("boot-device = %s\n", bootdevice);
1482 if (bootdevice[0] == 0) {
1483 prom_printf("Couldn't determine boot device\n");
1487 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1488 prom_printf("%s: Unable to parse\n", bootdevice);
1491 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1492 boot.dev, boot.part, boot.file);
1494 if (strlen(boot.file)) {
1495 if (!strncmp(boot.file, "\\\\", 2))
1499 p = last = boot.file;
1509 if (strlen(boot.file))
1510 strcat(boot.file, "\\");
1513 DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1514 boot.dev, boot.part, boot.file);
1516 useconf = load_config_file(boot.dev, boot.file, boot.part);
1518 prom_printf("Welcome to yaboot version " VERSION "\n");
1519 prom_printf("Enter \"help\" to get some basic usage information\n");
1521 /* I am fed up with lusers using the wrong partition type and
1522 mailing me *when* it breaks */
1524 if (_machine == _MACH_Pmac) {
1525 char *entry = cfg_get_strg(0, "ptypewarning");
1528 warn = strcmp(entry,
1529 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1531 ptype = get_part_type(boot.dev, boot.part);
1532 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1533 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1534 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1542 prom_printf("Bye.\n");
1548 * c-file-style: "k&r"