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[BOOTDEVSZ];
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(struct boot_fspec_t *orig_fspec)
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 = *orig_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/");
347 if (fspec.file && *fspec.file)
348 strcat(conf_path, fspec.file);
350 strcat(conf_path, CONFIG_FILE_NAME);
353 fspec.file = conf_path;
354 result = open_file(&fspec, &file);
355 if (result != FILE_ERR_OK) {
356 prom_printf("%s:%d,", fspec.dev, fspec.part);
357 prom_perror(result, fspec.file);
358 prom_printf("Can't open config file\n");
364 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
366 prom_printf("Error, can't read config file\n");
369 prom_printf("Config file read, %d bytes\n", sz);
373 file.fs->close(&file);
376 /* Call the parsing code in cfg.c */
377 if (cfg_parse(conf_path, conf_file, sz) < 0) {
378 prom_printf ("Syntax error or read error config\n");
382 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
384 /* Now, we do the initialisations stored in the config file */
385 p = cfg_get_strg(0, "init-code");
389 password = cfg_get_strg(0, "password");
391 #ifdef CONFIG_COLOR_TEXT
392 p = cfg_get_strg(0, "fgcolor");
394 DEBUG_F("fgcolor=%s\n", p);
395 fgcolor = check_color_text_ui(p);
397 prom_printf("Invalid fgcolor: \"%s\".\n", p);
400 p = cfg_get_strg(0, "bgcolor");
402 DEBUG_F("bgcolor=%s\n", p);
403 bgcolor = check_color_text_ui(p);
405 prom_printf("Invalid bgcolor: \"%s\".\n", p);
409 sprintf(temp, "%x to background-color", bgcolor);
410 prom_interpret(temp);
417 sprintf(temp, "%x to foreground-color", fgcolor);
418 prom_interpret(temp);
420 #endif /* CONFIG_COLOR_TEXT */
422 p = cfg_get_strg(0, "init-message");
424 prom_printf("%s\n", p);
426 p = cfg_get_strg(0, "message");
428 print_message_file(p);
435 file.fs->close(&file);
444 * "bootp-response" is the property name which is specified in
445 * the recommended practice doc for obp-tftp. However, pmac
446 * provides a "dhcp-response" property and chrp provides a
447 * "bootpreply-packet" property. The latter appears to begin the
448 * bootp packet at offset 0x2a in the property for some reason.
451 struct bootp_property_offset {
452 char *name; /* property name */
453 int offset; /* offset into property where bootp packet occurs */
455 static const struct bootp_property_offset bootp_response_properties[] = {
456 { .name = "bootp-response", .offset = 0 },
457 { .name = "dhcp-response", .offset = 0 },
458 { .name = "bootpreply-packet", .offset = 0x2a },
461 struct bootp_packet {
462 u8 op, htype, hlen, hops;
465 u32 ciaddr, yiaddr, siaddr, giaddr;
466 unsigned char chaddr[16];
467 unsigned char sname[64];
468 unsigned char file[128];
469 /* vendor options go here if we need them */
473 * Search for config file by MAC address, then by IP address.
474 * Basically copying pxelinux's algorithm.
475 * http://syslinux.zytor.com/pxe.php#config
477 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
479 void *bootp_response = NULL;
481 struct bootp_packet *packet;
482 int i = 0, size, offset = 0, rc = 0;
484 struct boot_fspec_t fspec = *orig_fspec;
485 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
487 chosen = prom_finddevice("/chosen");
489 prom_printf("chosen=%d\n", chosen);
493 for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
494 propname = bootp_response_properties[i].name;
495 size = prom_getproplen(chosen, propname);
499 DEBUG_F("using /chosen/%s\n", propname);
500 offset = bootp_response_properties[i].offset;
507 if (sizeof(*packet) > size - offset) {
508 prom_printf("Malformed %s property?\n", propname);
512 bootp_response = malloc(size);
516 if (prom_getprop(chosen, propname, bootp_response, size) < 0)
519 packet = bootp_response + offset;
522 * First, try to match on mac address with the hardware type
526 /* 3 chars per byte in chaddr + 2 chars for htype + \0 */
527 fspec.file = malloc(packet->hlen * 3 + 2 + 1);
531 sprintf(fspec.file, "%02x", packet->htype);
533 for (i = 0; i < packet->hlen; i++) {
535 sprintf(tmp, "-%02x", packet->chaddr[i]);
536 strcat(fspec.file, tmp);
539 rc = load_config_file(&fspec);
545 * Now try to match on IP.
548 fspec.file = malloc(9);
549 sprintf(fspec.file, "%08X", packet->yiaddr);
551 while (strlen(fspec.file)) {
552 rc = load_config_file(&fspec);
555 /* Chop one digit off the end, try again */
556 fspec.file[strlen(fspec.file) - 1] = '\0';
560 if (rc) /* modify original only on success */
561 orig_fspec->file = fspec.file;
564 free(bootp_response);
568 void maintabfunc (void)
572 prom_printf("boot: %s", cbuff);
577 word_split(char **linep, char **paramsp)
592 while (*p != 0 && *p != ' ')
601 make_params(char *label, char *params)
604 static char buffer[2048];
609 p = cfg_get_strg(label, "literal");
621 p = cfg_get_strg(label, "root");
628 if (cfg_get_flag(label, "read-only")) {
632 if (cfg_get_flag(label, "read-write")) {
636 p = cfg_get_strg(label, "ramdisk");
638 strcpy (q, "ramdisk=");
643 p = cfg_get_strg(label, "initrd-size");
645 strcpy (q, "ramdisk_size=");
650 if (cfg_get_flag(label, "novideo")) {
651 strcpy (q, "video=ofonly");
655 p = cfg_get_strg (label, "append");
662 pause_after = cfg_get_flag (label, "pause-after");
663 p = cfg_get_strg(label, "pause-message");
672 void check_password(char *str)
676 prom_printf("\n%s", str);
677 for (i = 0; i < 3; i++) {
678 prom_printf ("\nPassword: ");
680 cmdedit ((void (*)(void)) 0, 1);
682 #ifdef USE_MD5_PASSWORDS
683 if (!strncmp (password, "$1$", 3)) {
684 if (!check_md5_password(passwdbuff, password))
687 else if (!strcmp (password, passwdbuff))
690 if (!strcmp (password, passwdbuff))
692 #endif /* USE_MD5_PASSWORDS */
695 prom_printf ("Incorrect password. Try again.");
698 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
699 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
700 " ||----w |\n || ||\n");
702 prom_interpret("reset-all");
705 int get_params(struct boot_param_t* params)
711 char *imagename = 0, *label;
716 static int first = 1;
717 static char bootargs[1024];
718 static char imagepath[1024];
719 static char initrdpath[1024];
720 static char sysmappath[1024];
723 memset(params, 0, sizeof(*params));
725 params->kernel.part = -1;
726 params->rd.part = -1;
727 params->sysmap.part = -1;
734 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
735 imagename = bootargs;
736 word_split(&imagename, ¶ms->args);
737 timeout = DEFAULT_TIMEOUT;
739 prom_printf("Default supplied on the command line: %s ", imagename);
741 prom_printf("%s", params->args);
744 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
745 timeout = simple_strtol(q, NULL, 0);
748 prom_printf("boot: ");
753 end = beg + 100 * timeout;
755 c = prom_nbgetchar();
756 } while (c == -1 && prom_getms() <= end);
760 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
766 if (c != -1 && c != '\n' && c != '\r') {
769 } else if (c >= ' ') {
772 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
775 prom_printf("%s\n", cbuff);
780 if (c == '\n' || c == '\r') {
782 imagename = cfg_get_default();
784 prom_printf("%s", imagename);
786 prom_printf(" %s", params->args);
788 } else if (!singlekey) {
789 cmdedit(maintabfunc, 0);
791 strcpy(given_bootargs, cbuff);
792 given_bootargs_by_user = 1;
794 word_split(&imagename, ¶ms->args);
797 /* chrp gets this wrong, force it -- Cort */
798 if ( useconf && (!imagename || imagename[0] == 0 ))
799 imagename = cfg_get_default();
802 defdevice = boot.dev;
805 defdevice = cfg_get_strg(0, "device");
806 p = cfg_get_strg(0, "partition");
808 n = simple_strtol(p, &endp, 10);
809 if (endp != p && *endp == 0)
812 p = cfg_get_strg(0, "pause-message");
815 if (cfg_get_flag(0, "restricted"))
817 p = cfg_get_strg(imagename, "image");
821 defdevice = cfg_get_strg(label, "device");
822 if(!defdevice) defdevice=boot.dev;
823 p = cfg_get_strg(label, "partition");
825 n = simple_strtol(p, &endp, 10);
826 if (endp != p && *endp == 0)
829 if (cfg_get_flag(label, "restricted"))
832 if (params->args && password && restricted)
833 check_password ("To specify arguments for this image "
834 "you must enter the password.");
835 else if (password && !restricted)
836 check_password ("This image is restricted.");
838 params->args = make_params(label, params->args);
842 if (!strcmp (imagename, "help")) {
843 /* FIXME: defdevice shouldn't need to be reset all over the place */
844 if(!defdevice) defdevice = boot.dev;
846 "\nPress the tab key for a list of defined images.\n"
847 "The label marked with a \"*\" is is the default image, "
848 "press <return> to boot it.\n\n"
849 "To boot any other label simply type its name and press <return>.\n\n"
850 "To boot a kernel image which is not defined in the yaboot configuration \n"
851 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
852 "\"device:\" is the OpenFirmware device path to the disk the image \n"
853 "resides on, and \"partno\" is the partition number the image resides on.\n"
854 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
855 "device, if you only specify a filename you should not start it with a \",\"\n\n"
856 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
857 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
859 "partition=%d\n\n", defdevice, defpart);
863 if (!strcmp (imagename, "halt")) {
865 check_password ("Restricted command.");
869 if (!strcmp (imagename, "bye")) {
871 check_password ("Restricted command.");
877 if (imagename[0] == '$') {
878 /* forth command string */
880 check_password ("OpenFirmware commands are restricted.");
881 prom_interpret(imagename+1);
885 strncpy(imagepath, imagename, 1024);
887 if (!label && password)
888 check_password ("To boot a custom image you must enter the password.");
890 if (!parse_device_path(imagepath, defdevice, defpart,
891 "/vmlinux", ¶ms->kernel)) {
892 prom_printf("%s: Unable to parse\n", imagepath);
895 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
896 params->kernel.part, params->kernel.file);
899 p = cfg_get_strg(label, "initrd");
901 DEBUG_F("Parsing initrd path <%s>\n", p);
902 strncpy(initrdpath, p, 1024);
903 if (!parse_device_path(initrdpath, defdevice, defpart,
904 "/root.bin", ¶ms->rd)) {
905 prom_printf("%s: Unable to parse\n", imagepath);
909 p = cfg_get_strg(label, "sysmap");
911 DEBUG_F("Parsing sysmap path <%s>\n", p);
912 strncpy(sysmappath, p, 1024);
913 if (!parse_device_path(sysmappath, defdevice, defpart,
914 "/boot/System.map", ¶ms->sysmap)) {
915 prom_printf("%s: Unable to parse\n", imagepath);
923 /* This is derived from quik core. To be changed to first parse the headers
924 * doing lazy-loading, and then claim the memory before loading the kernel
926 * We also need to add initrd support to this whole mecanism
931 #define MAX_HEADERS 32
933 struct boot_file_t file;
935 static struct boot_param_t params;
937 unsigned long initrd_size;
939 unsigned long sysmap_size;
940 kernel_entry_t kernel_entry;
941 struct bi_record* birec;
944 void *initrd_more,*initrd_want;
945 unsigned long initrd_read;
947 loadinfo.load_loc = 0;
955 if (get_params(¶ms))
957 if (!params.kernel.file)
960 prom_printf("Please wait, loading kernel...\n");
962 memset(&file, 0, sizeof(file));
964 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
965 && params.kernel.file[0] != '\\') {
966 loc=(char*)malloc(strlen(params.kernel.file)+3);
968 prom_printf ("malloc error\n");
971 strcpy(loc,boot.file);
972 strcat(loc,params.kernel.file);
973 free(params.kernel.file);
974 params.kernel.file=loc;
976 result = open_file(¶ms.kernel, &file);
977 if (result != FILE_ERR_OK) {
978 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
979 prom_perror(result, params.kernel.file);
983 /* Read the Elf e_ident, e_type and e_machine fields to
984 * determine Elf file type
986 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
987 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
988 file.fs->close(&file);
989 memset(&file, 0, sizeof(file));
993 if (is_elf32(&loadinfo)) {
994 if (!load_elf32(&file, &loadinfo)) {
995 file.fs->close(&file);
996 memset(&file, 0, sizeof(file));
999 prom_printf(" Elf32 kernel loaded...\n");
1000 } else if (is_elf64(&loadinfo)) {
1001 if (!load_elf64(&file, &loadinfo)) {
1002 file.fs->close(&file);
1003 memset(&file, 0, sizeof(file));
1006 prom_printf(" Elf64 kernel loaded...\n");
1008 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1009 file.fs->close(&file);
1010 memset(&file, 0, sizeof(file));
1013 file.fs->close(&file);
1014 memset(&file, 0, sizeof(file));
1016 /* If sysmap, load it (only if booting a vmlinux).
1018 if (flat_vmlinux && params.sysmap.file) {
1019 prom_printf("Loading System.map ...\n");
1020 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1021 && params.sysmap.file[0] != '\\') {
1023 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1025 prom_printf ("malloc error\n");
1028 strcpy(loc,boot.file);
1029 strcat(loc,params.sysmap.file);
1030 free(params.sysmap.file);
1031 params.sysmap.file=loc;
1034 result = open_file(¶ms.sysmap, &file);
1035 if (result != FILE_ERR_OK) {
1036 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1037 prom_perror(result, params.sysmap.file);
1040 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1041 if (sysmap_base == (void *)-1) {
1042 prom_printf("Claim failed for sysmap memory\n");
1046 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1047 if (sysmap_size == 0)
1050 ((char *)sysmap_base)[sysmap_size++] = 0;
1052 file.fs->close(&file);
1053 memset(&file, 0, sizeof(file));
1056 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1057 sysmap_base, sysmap_size >> 10);
1058 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1060 prom_printf("System.map load failed !\n");
1065 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1066 * can't tell the size it will be so we claim an arbitrary amount
1069 if (flat_vmlinux && params.rd.file) {
1070 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1071 && params.kernel.file[0] != '\\')
1074 loc=(char*)malloc(strlen(params.rd.file)+3);
1076 prom_printf ("Malloc error\n");
1079 strcpy(loc,boot.file);
1080 strcat(loc,params.rd.file);
1081 free(params.rd.file);
1084 prom_printf("Loading ramdisk...\n");
1085 result = open_file(¶ms.rd, &file);
1086 if (result != FILE_ERR_OK) {
1087 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1088 prom_perror(result, params.rd.file);
1091 #define INITRD_CHUNKSIZE 0x100000
1092 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1093 if (initrd_base == (void *)-1) {
1094 prom_printf("Claim failed for initrd memory\n");
1097 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1098 if (initrd_size == 0)
1100 initrd_read = initrd_size;
1101 initrd_more = initrd_base;
1102 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1103 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1104 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1105 if (initrd_more != initrd_want) {
1106 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1110 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1111 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1112 initrd_size += initrd_read;
1115 file.fs->close(&file);
1116 memset(&file, 0, sizeof(file));
1119 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1120 initrd_base, initrd_size >> 10);
1122 prom_printf("ramdisk load failed !\n");
1127 DEBUG_F("setting kernel args to: %s\n", params.args);
1128 prom_setargs(params.args);
1129 DEBUG_F("flushing icache...");
1130 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1135 * Fill new boot infos (only if booting a vmlinux).
1137 * The birec is low on memory, probably inside the malloc pool,
1138 * so we don't write it earlier. At this point, we should not
1139 * use anything coming from the malloc pool.
1141 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1143 /* We make sure it's mapped. We map only 64k for now, it's
1144 * plenty enough we don't claim since this precise memory
1145 * range may already be claimed by the malloc pool.
1147 prom_map (birec, birec, 0x10000);
1148 DEBUG_F("birec at %p\n", birec);
1151 birec->tag = BI_FIRST;
1152 birec->size = sizeof(struct bi_record);
1153 birec = (struct bi_record *)((ulong)birec + birec->size);
1155 birec->tag = BI_BOOTLOADER_ID;
1156 sprintf( (char *)birec->data, "yaboot");
1157 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1158 birec = (struct bi_record *)((ulong)birec + birec->size);
1160 birec->tag = BI_MACHTYPE;
1161 birec->data[0] = _machine;
1162 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1163 birec = (struct bi_record *)((ulong)birec + birec->size);
1166 birec->tag = BI_SYSMAP;
1167 birec->data[0] = (ulong)sysmap_base;
1168 birec->data[1] = sysmap_size;
1169 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1170 birec = (struct bi_record *)((ulong)birec + birec->size);
1172 birec->tag = BI_LAST;
1173 birec->size = sizeof(struct bi_record);
1174 birec = (struct bi_record *)((ulong)birec + birec->size);
1177 /* compute the kernel's entry point. */
1178 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1180 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1181 DEBUG_F("kernel: arg1 = %p,\n"
1182 " arg2 = 0x%08lx,\n"
1186 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1188 DEBUG_F("Entering kernel...\n");
1190 /* call the kernel with our stack. */
1191 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1199 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1202 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1204 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1205 unsigned long addr, loadaddr;
1207 /* Read the rest of the Elf header... */
1208 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1209 prom_printf("\nCan't read Elf32 image header\n");
1213 DEBUG_F("Elf32 header:\n");
1214 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1215 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1216 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1217 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1218 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1219 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1220 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1221 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1222 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1223 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1225 loadinfo->entry = e->e_entry;
1227 if (e->e_phnum > MAX_HEADERS) {
1228 prom_printf ("Can only load kernels with one program header\n");
1232 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1234 prom_printf ("Malloc error\n");
1238 /* Now, we read the section header */
1239 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1240 prom_printf ("seek error\n");
1243 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1244 sizeof(Elf32_Phdr) * e->e_phnum) {
1245 prom_printf ("read error\n");
1249 /* Scan through the program header
1250 * HACK: We must return the _memory size of the kernel image, not the
1251 * file size (because we have to leave room before other boot
1252 * infos. This code works as a side effect of the fact that
1253 * we have one section and vaddr == p_paddr
1255 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1257 for (i = 0; i < e->e_phnum; ++i, ++p) {
1258 if (p->p_type != PT_LOAD || p->p_offset == 0)
1260 if (loadinfo->memsize == 0) {
1261 loadinfo->offset = p->p_offset;
1262 loadinfo->memsize = p->p_memsz;
1263 loadinfo->filesize = p->p_filesz;
1264 loadinfo->load_loc = p->p_vaddr;
1266 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1267 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1271 if (loadinfo->memsize == 0) {
1272 prom_printf("Can't find a loadable segment !\n");
1276 /* leave some room (1Mb) for boot infos */
1277 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1278 /* Claim OF memory */
1279 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1281 /* Determine whether we are trying to boot a vmlinux or some
1282 * other binary image (eg, zImage). We load vmlinux's at
1283 * KERNELADDR and all other binaries at their e_entry value.
1285 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1287 loadaddr = KERNELADDR;
1290 loadaddr = loadinfo->load_loc;
1293 /* On some systems, loadaddr may already be claimed, so try some
1294 * other nearby addresses before giving up.
1296 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1297 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1298 if (loadinfo->base != (void *)-1) break;
1300 if (loadinfo->base == (void *)-1) {
1301 prom_printf("Claim error, can't allocate kernel memory\n");
1305 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1306 loadinfo->base, loadinfo->memsize);
1307 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1308 loadaddr, loadinfo->memsize);
1310 /* Load the program segments... */
1312 for (i = 0; i < e->e_phnum; ++i, ++p) {
1313 unsigned long offset;
1314 if (p->p_type != PT_LOAD || p->p_offset == 0)
1317 /* Now, we skip to the image itself */
1318 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1319 prom_printf ("Seek error\n");
1320 prom_release(loadinfo->base, loadinfo->memsize);
1323 offset = p->p_vaddr - loadinfo->load_loc;
1324 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1325 prom_printf ("Read failed\n");
1326 prom_release(loadinfo->base, loadinfo->memsize);
1333 /* Return success at loading the Elf32 kernel */
1343 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1346 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1348 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1349 unsigned long addr, loadaddr;
1351 /* Read the rest of the Elf header... */
1352 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1353 prom_printf("\nCan't read Elf64 image header\n");
1357 DEBUG_F("Elf64 header:\n");
1358 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1359 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1360 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1361 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1362 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1363 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1364 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1365 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1366 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1367 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1369 loadinfo->entry = e->e_entry;
1371 if (e->e_phnum > MAX_HEADERS) {
1372 prom_printf ("Can only load kernels with one program header\n");
1376 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1378 prom_printf ("Malloc error\n");
1382 /* Now, we read the section header */
1383 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1384 prom_printf ("Seek error\n");
1387 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1388 sizeof(Elf64_Phdr) * e->e_phnum) {
1389 prom_printf ("Read error\n");
1393 /* Scan through the program header
1394 * HACK: We must return the _memory size of the kernel image, not the
1395 * file size (because we have to leave room before other boot
1396 * infos. This code works as a side effect of the fact that
1397 * we have one section and vaddr == p_paddr
1399 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1401 for (i = 0; i < e->e_phnum; ++i, ++p) {
1402 if (p->p_type != PT_LOAD || p->p_offset == 0)
1404 if (loadinfo->memsize == 0) {
1405 loadinfo->offset = p->p_offset;
1406 loadinfo->memsize = p->p_memsz;
1407 loadinfo->filesize = p->p_filesz;
1408 loadinfo->load_loc = p->p_vaddr;
1410 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1411 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1415 if (loadinfo->memsize == 0) {
1416 prom_printf("Can't find a loadable segment !\n");
1420 /* leave some room (1Mb) for boot infos */
1421 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1422 /* Claim OF memory */
1423 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1425 /* Determine whether we are trying to boot a vmlinux or some
1426 * other binary image (eg, zImage). We load vmlinux's at
1427 * KERNELADDR and all other binaries at their e_entry value.
1429 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1431 loadaddr = KERNELADDR;
1434 loadaddr = e->e_entry;
1437 /* On some systems, loadaddr may already be claimed, so try some
1438 * other nearby addresses before giving up.
1440 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1441 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1442 if (loadinfo->base != (void *)-1) break;
1444 if (loadinfo->base == (void *)-1) {
1445 prom_printf("Claim error, can't allocate kernel memory\n");
1449 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1450 loadinfo->base, loadinfo->memsize);
1451 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1452 loadaddr, loadinfo->memsize);
1454 /* Load the program segments... */
1456 for (i = 0; i < e->e_phnum; ++i, ++p) {
1457 unsigned long offset;
1458 if (p->p_type != PT_LOAD || p->p_offset == 0)
1461 /* Now, we skip to the image itself */
1462 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1463 prom_printf ("Seek error\n");
1464 prom_release(loadinfo->base, loadinfo->memsize);
1467 offset = p->p_vaddr - loadinfo->load_loc;
1468 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1469 prom_printf ("Read failed\n");
1470 prom_release(loadinfo->base, loadinfo->memsize);
1477 /* Return success at loading the Elf64 kernel */
1487 is_elf32(loadinfo_t *loadinfo)
1489 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1491 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1492 e->e_ident[EI_MAG1] == ELFMAG1 &&
1493 e->e_ident[EI_MAG2] == ELFMAG2 &&
1494 e->e_ident[EI_MAG3] == ELFMAG3 &&
1495 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1496 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1497 e->e_type == ET_EXEC &&
1498 e->e_machine == EM_PPC);
1502 is_elf64(loadinfo_t *loadinfo)
1504 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1506 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1507 e->e_ident[EI_MAG1] == ELFMAG1 &&
1508 e->e_ident[EI_MAG2] == ELFMAG2 &&
1509 e->e_ident[EI_MAG3] == ELFMAG3 &&
1510 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1511 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1512 e->e_type == ET_EXEC &&
1513 e->e_machine == EM_PPC64);
1519 #ifdef CONFIG_SET_COLORMAP
1520 static unsigned char default_colors[] = {
1539 prom_handle scrn = PROM_INVALID_HANDLE;
1541 /* Try Apple's mac-boot screen ihandle */
1542 result = (int)call_prom_return("interpret", 1, 2,
1543 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1544 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1546 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1548 /* Hrm... check to see if stdout is a display */
1549 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1550 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1551 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1552 DEBUG_F("got it ! stdout is a screen\n");
1555 /* Else, we try to open the package */
1556 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1557 DEBUG_F("Open screen result: %p\n", scrn);
1561 if (scrn == PROM_INVALID_HANDLE) {
1562 prom_printf("No screen device found !/n");
1566 prom_set_color(scrn, i, default_colors[i*3],
1567 default_colors[i*3+1], default_colors[i*3+2]);
1569 prom_printf("\x1b[1;37m\x1b[2;40m");
1571 for (i=0;i<16; i++) {
1572 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1573 ansi_color_table[i].index,
1574 ansi_color_table[i].value,
1575 ansi_color_table[i].name,
1576 ansi_color_table[i].name);
1577 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1578 ansi_color_table[i].index,
1579 ansi_color_table[i].value+10,
1580 ansi_color_table[i].name,
1581 ansi_color_table[i].name);
1583 prom_printf("\x1b[1;37m\x1b[2;40m");
1584 #endif /* COLOR_TEST */
1590 #endif /* CONFIG_SET_COLORMAP */
1598 if (_machine == _MACH_Pmac)
1601 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1602 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1603 if (bootdevice[0] == 0) {
1604 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1605 DEBUG_F("boot-device = %s\n", bootdevice);
1607 if (bootdevice[0] == 0) {
1608 prom_printf("Couldn't determine boot device\n");
1612 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1613 prom_printf("%s: Unable to parse\n", bootdevice);
1616 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1617 boot.dev, boot.part, boot.file);
1619 if (strlen(boot.file)) {
1620 if (!strncmp(boot.file, "\\\\", 2))
1624 p = last = boot.file;
1634 if (strlen(boot.file))
1635 strcat(boot.file, "\\");
1638 DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1639 boot.dev, boot.part, boot.file);
1642 * If we're doing a netboot, first look for one which matches our
1645 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1646 prom_printf("Try to netboot\n");
1647 useconf = load_my_config_file(&boot);
1651 useconf = load_config_file(&boot);
1653 prom_printf("Welcome to yaboot version " VERSION "\n");
1654 prom_printf("Enter \"help\" to get some basic usage information\n");
1656 /* I am fed up with lusers using the wrong partition type and
1657 mailing me *when* it breaks */
1659 if (_machine == _MACH_Pmac) {
1660 char *entry = cfg_get_strg(0, "ptypewarning");
1663 warn = strcmp(entry,
1664 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1666 ptype = get_part_type(boot.dev, boot.part);
1667 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1668 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1669 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1677 prom_printf("Bye.\n");
1683 * c-file-style: "k&r"