2 * Yaboot - secondary boot loader for Linux on PowerPC.
4 * Copyright (C) 2001 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);
438 if (result != 1 && conf_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 */
1212 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1215 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1217 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1218 unsigned long addr, loadaddr;
1220 /* Read the rest of the Elf header... */
1221 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1222 prom_printf("\nCan't read Elf64 image header\n");
1226 DEBUG_F("Elf64 header:\n");
1227 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1228 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1229 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1230 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1231 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1232 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1233 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1234 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1235 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1236 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1238 loadinfo->entry = e->e_entry;
1240 if (e->e_phnum > MAX_HEADERS) {
1241 prom_printf ("Can only load kernels with one program header\n");
1245 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1247 prom_printf ("Malloc error\n");
1251 /* Now, we read the section header */
1252 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1253 prom_printf ("Seek error\n");
1256 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1257 sizeof(Elf64_Phdr) * e->e_phnum) {
1258 prom_printf ("Read error\n");
1262 /* Scan through the program header
1263 * HACK: We must return the _memory size of the kernel image, not the
1264 * file size (because we have to leave room before other boot
1265 * infos. This code works as a side effect of the fact that
1266 * we have one section and vaddr == p_paddr
1268 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1270 for (i = 0; i < e->e_phnum; ++i, ++p) {
1271 if (p->p_type != PT_LOAD || p->p_offset == 0)
1273 if (loadinfo->memsize == 0) {
1274 loadinfo->offset = p->p_offset;
1275 loadinfo->memsize = p->p_memsz;
1276 loadinfo->filesize = p->p_filesz;
1277 loadinfo->load_loc = p->p_vaddr;
1279 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1280 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1284 if (loadinfo->memsize == 0) {
1285 prom_printf("Can't find a loadable segment !\n");
1289 /* leave some room (1Mb) for boot infos */
1290 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1291 /* Claim OF memory */
1292 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1294 /* Determine whether we are trying to boot a vmlinux or some
1295 * other binary image (eg, zImage). We load vmlinux's at
1296 * KERNELADDR and all other binaries at their e_entry value.
1298 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1300 loadaddr = KERNELADDR;
1303 loadaddr = e->e_entry;
1306 /* On some systems, loadaddr may already be claimed, so try some
1307 * other nearby addresses before giving up.
1309 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1310 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1311 if (loadinfo->base != (void *)-1) break;
1313 if (loadinfo->base == (void *)-1) {
1314 prom_printf("Claim error, can't allocate kernel memory\n");
1318 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1319 loadinfo->base, loadinfo->memsize);
1320 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1321 loadaddr, loadinfo->memsize);
1323 /* Load the program segments... */
1325 for (i = 0; i < e->e_phnum; ++i, ++p) {
1326 unsigned long offset;
1327 if (p->p_type != PT_LOAD || p->p_offset == 0)
1330 /* Now, we skip to the image itself */
1331 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1332 prom_printf ("Seek error\n");
1333 prom_release(loadinfo->base, loadinfo->memsize);
1336 offset = p->p_vaddr - loadinfo->load_loc;
1337 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1338 prom_printf ("Read failed\n");
1339 prom_release(loadinfo->base, loadinfo->memsize);
1346 /* Return success at loading the Elf64 kernel */
1351 is_elf32(loadinfo_t *loadinfo)
1353 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1355 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1356 e->e_ident[EI_MAG1] == ELFMAG1 &&
1357 e->e_ident[EI_MAG2] == ELFMAG2 &&
1358 e->e_ident[EI_MAG3] == ELFMAG3 &&
1359 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1360 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1361 e->e_type == ET_EXEC &&
1362 e->e_machine == EM_PPC);
1366 is_elf64(loadinfo_t *loadinfo)
1368 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1370 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1371 e->e_ident[EI_MAG1] == ELFMAG1 &&
1372 e->e_ident[EI_MAG2] == ELFMAG2 &&
1373 e->e_ident[EI_MAG3] == ELFMAG3 &&
1374 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1375 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1376 e->e_type == ET_EXEC &&
1377 e->e_machine == EM_PPC64);
1383 #ifdef CONFIG_SET_COLORMAP
1384 static unsigned char default_colors[] = {
1403 prom_handle scrn = PROM_INVALID_HANDLE;
1405 /* Try Apple's mac-boot screen ihandle */
1406 result = (int)call_prom_return("interpret", 1, 2,
1407 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1408 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1410 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1412 /* Hrm... check to see if stdout is a display */
1413 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1414 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1415 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1416 DEBUG_F("got it ! stdout is a screen\n");
1419 /* Else, we try to open the package */
1420 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1421 DEBUG_F("Open screen result: %p\n", scrn);
1425 if (scrn == PROM_INVALID_HANDLE) {
1426 prom_printf("No screen device found !/n");
1430 prom_set_color(scrn, i, default_colors[i*3],
1431 default_colors[i*3+1], default_colors[i*3+2]);
1433 prom_printf("\x1b[1;37m\x1b[2;40m");
1435 for (i=0;i<16; i++) {
1436 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1437 ansi_color_table[i].index,
1438 ansi_color_table[i].value,
1439 ansi_color_table[i].name,
1440 ansi_color_table[i].name);
1441 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1442 ansi_color_table[i].index,
1443 ansi_color_table[i].value+10,
1444 ansi_color_table[i].name,
1445 ansi_color_table[i].name);
1447 prom_printf("\x1b[1;37m\x1b[2;40m");
1448 #endif /* COLOR_TEST */
1454 #endif /* CONFIG_SET_COLORMAP */
1462 if (_machine == _MACH_Pmac)
1465 prom_get_chosen("bootpath", bootdevice, sizeof(bootdevice));
1466 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1467 if (bootdevice[0] == 0) {
1468 prom_get_options("boot-device", bootdevice, sizeof(bootdevice));
1469 DEBUG_F("boot-device = %s\n", bootdevice);
1471 if (bootdevice[0] == 0) {
1472 prom_printf("Couldn't determine boot device\n");
1476 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1477 prom_printf("%s: Unable to parse\n", bootdevice);
1480 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1481 boot.dev, boot.part, boot.file);
1483 if (strlen(boot.file)) {
1484 if (!strncmp(boot.file, "\\\\", 2))
1488 p = last = boot.file;
1498 if (strlen(boot.file))
1499 strcat(boot.file, "\\");
1502 DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1503 boot.dev, boot.part, boot.file);
1505 useconf = load_config_file(boot.dev, boot.file, boot.part);
1507 prom_printf("Welcome to yaboot version " VERSION "\n");
1508 prom_printf("Enter \"help\" to get some basic usage information\n");
1510 /* I am fed up with lusers using the wrong partition type and
1511 mailing me *when* it breaks */
1513 if (_machine == _MACH_Pmac) {
1514 char *entry = cfg_get_strg(0, "ptypewarning");
1517 warn = strcmp(entry,
1518 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1520 ptype = get_part_type(boot.dev, boot.part);
1521 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1522 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1523 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1529 prom_printf("Bye.\n");
1535 * c-file-style: "k&r"