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 bootoncelabel[1024];
117 char *password = NULL;
118 struct boot_fspec_t boot;
119 int _machine = _MACH_Pmac;
122 #ifdef CONFIG_COLOR_TEXT
124 /* Color values for text ui */
125 static struct ansi_color_t {
129 } ansi_color_table[] = {
137 { "light-gray", 0, 37 },
138 { "dark-gray", 1, 30 },
139 { "light-blue", 1, 31 },
140 { "light-green", 1, 32 },
141 { "light-cyan", 1, 33 },
142 { "light-red", 1, 34 },
143 { "light-purple", 1, 35 },
149 /* Default colors for text ui */
152 #endif /* CONFIG_COLOR_TEXT */
156 static int test_data = 0;
158 static int pause_after;
159 static char *pause_message = "Type go<return> to continue.\n";
160 static char given_bootargs[1024];
161 static int given_bootargs_by_user = 0;
163 extern unsigned char linux_logo_red[];
164 extern unsigned char linux_logo_green[];
165 extern unsigned char linux_logo_blue[];
167 #define DEFAULT_TIMEOUT -1
169 /* Entry, currently called directly by crt0 (bss not inited) */
171 extern char* __bss_start;
174 static struct first_info *quik_fip = NULL;
177 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
180 void* malloc_base = NULL;
183 /* OF seems to do it, but I'm not very confident */
184 memset(&__bss_start, 0, &_end - &__bss_start);
186 /* Check for quik first stage bootloader (but I don't think we are
187 * compatible with it anyway, I'll look into backporting to older OF
190 if (r5 == 0xdeadbeef) {
192 quik_fip = (struct first_info *)r4;
195 /* Initialize OF interface */
196 prom_init ((prom_entry) r5);
198 /* Allocate some memory for malloc'ator */
199 malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
200 if (malloc_base == (void *)-1) {
201 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
202 MALLOCSIZE, MALLOCADDR);
205 malloc_init(malloc_base, MALLOCSIZE);
206 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
207 malloc_base, MALLOCSIZE);
209 /* A few useless DEBUG_F's */
210 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
211 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
212 DEBUG_F("test_data : %d (should be 0)\n", test_data);
213 DEBUG_F("&test_data : %p\n", &test_data);
214 DEBUG_F("&test_bss : %p\n", &test_bss);
215 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
217 /* ask the OF info if we're a chrp or pmac */
218 /* we need to set _machine before calling finish_device_tree */
219 root = prom_finddevice("/");
221 static char model[256];
222 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
223 !strncmp("chrp", model, 4))
224 _machine = _MACH_chrp;
226 if (prom_getprop(root, "model", model, 256 ) > 0 &&
227 !strncmp(model, "IBM", 3))
228 _machine = _MACH_chrp;
232 DEBUG_F("Running on _machine = %d\n", _machine);
236 result = yaboot_main();
238 /* Get rid of malloc pool */
240 prom_release(malloc_base, MALLOCSIZE);
241 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
251 #ifdef CONFIG_COLOR_TEXT
253 * Validify color for text ui
256 check_color_text_ui(char *color)
259 while(ansi_color_table[i].name) {
260 if (!strcmp(color, ansi_color_table[i].name))
266 #endif /* CONFIG_COLOR_TEXT */
269 void print_message_file(char *filename)
273 char *defdev = boot.dev;
274 int defpart = boot.part;
279 struct boot_file_t file;
280 struct boot_fspec_t msgfile;
282 defdev = cfg_get_strg(0, "device");
285 p = cfg_get_strg(0, "partition");
287 n = simple_strtol(p, &endp, 10);
288 if (endp != p && *endp == 0)
292 strncpy(msgpath, filename, sizeof(msgpath));
293 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
294 prom_printf("%s: Unable to parse\n", msgpath);
298 result = open_file(&msgfile, &file);
299 if (result != FILE_ERR_OK) {
300 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
301 prom_perror(result, msgfile.file);
310 memset(msg, 0, 2001);
312 if (file.fs->read(&file, 2000, msg) <= 0)
315 prom_printf("%s", msg);
319 file.fs->close(&file);
324 /* Currently, the config file must be at the root of the filesystem.
325 * todo: recognize the full path to myself and use it to load the
326 * config file. Handle the "\\" (blessed system folder)
329 load_config_file(struct boot_fspec_t *fspec)
331 char *conf_file = NULL, *p;
332 struct boot_file_t file;
333 int sz, opened = 0, result = 0;
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");
343 result = open_file(fspec, &file);
344 if (result != FILE_ERR_OK) {
345 prom_printf("%s:%d,", fspec->dev, fspec->part);
346 prom_perror(result, fspec->file);
347 prom_printf("Can't open config file\n");
353 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
355 prom_printf("Error, can't read config file\n");
358 prom_printf("Config file read, %d bytes\n", sz);
362 file.fs->close(&file);
365 /* Call the parsing code in cfg.c */
366 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
367 prom_printf ("Syntax error or read error config\n");
371 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
373 /* Now, we do the initialisations stored in the config file */
374 p = cfg_get_strg(0, "init-code");
378 password = cfg_get_strg(0, "password");
380 #ifdef CONFIG_COLOR_TEXT
381 p = cfg_get_strg(0, "fgcolor");
383 DEBUG_F("fgcolor=%s\n", p);
384 fgcolor = check_color_text_ui(p);
386 prom_printf("Invalid fgcolor: \"%s\".\n", p);
389 p = cfg_get_strg(0, "bgcolor");
391 DEBUG_F("bgcolor=%s\n", p);
392 bgcolor = check_color_text_ui(p);
394 prom_printf("Invalid bgcolor: \"%s\".\n", p);
398 sprintf(temp, "%x to background-color", bgcolor);
399 prom_interpret(temp);
406 sprintf(temp, "%x to foreground-color", fgcolor);
407 prom_interpret(temp);
409 #endif /* CONFIG_COLOR_TEXT */
411 p = cfg_get_strg(0, "init-message");
413 prom_printf("%s\n", p);
415 p = cfg_get_strg(0, "message");
417 print_message_file(p);
424 file.fs->close(&file);
433 * "bootp-response" is the property name which is specified in
434 * the recommended practice doc for obp-tftp. However, pmac
435 * provides a "dhcp-response" property and chrp provides a
436 * "bootpreply-packet" property. The latter appears to begin the
437 * bootp packet at offset 0x2a in the property for some reason.
440 struct bootp_property_offset {
441 char *name; /* property name */
442 int offset; /* offset into property where bootp packet occurs */
444 static const struct bootp_property_offset bootp_response_properties[] = {
445 { .name = "bootp-response", .offset = 0 },
446 { .name = "dhcp-response", .offset = 0 },
447 { .name = "bootpreply-packet", .offset = 0x2a },
450 struct bootp_packet {
451 u8 op, htype, hlen, hops;
454 u32 ciaddr, yiaddr, siaddr, giaddr;
455 unsigned char chaddr[16];
456 unsigned char sname[64];
457 unsigned char file[128];
458 /* vendor options go here if we need them */
462 * Search for config file by MAC address, then by IP address.
463 * Basically copying pxelinux's algorithm.
464 * http://syslinux.zytor.com/pxe.php#config
466 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
468 void *bootp_response = NULL;
470 struct bootp_packet *packet;
471 int i = 0, size, offset = 0, rc = 0;
473 struct boot_fspec_t fspec = *orig_fspec;
474 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
476 chosen = prom_finddevice("/chosen");
478 prom_printf("chosen=%d\n", chosen);
482 for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
483 propname = bootp_response_properties[i].name;
484 size = prom_getproplen(chosen, propname);
488 DEBUG_F("using /chosen/%s\n", propname);
489 offset = bootp_response_properties[i].offset;
496 if (sizeof(*packet) > size - offset) {
497 prom_printf("Malformed %s property?\n", propname);
501 bootp_response = malloc(size);
505 if (prom_getprop(chosen, propname, bootp_response, size) < 0)
508 packet = bootp_response + offset;
511 * First, try to match on mac address with the hardware type
515 /* 3 chars per byte in chaddr + 2 chars for htype + \0 */
516 fspec.file = malloc(packet->hlen * 3 + 2 + 1);
520 sprintf(fspec.file, "%02x", packet->htype);
522 for (i = 0; i < packet->hlen; i++) {
524 sprintf(tmp, "-%02x", packet->chaddr[i]);
525 strcat(fspec.file, tmp);
528 rc = load_config_file(&fspec);
534 * Now try to match on IP.
537 fspec.file = malloc(9);
538 sprintf(fspec.file, "%08X", packet->yiaddr);
540 while (strlen(fspec.file)) {
541 rc = load_config_file(&fspec);
544 /* Chop one digit off the end, try again */
545 fspec.file[strlen(fspec.file) - 1] = '\0';
549 if (rc) /* modify original only on success */
550 orig_fspec->file = fspec.file;
553 free(bootp_response);
557 void maintabfunc (void)
561 prom_printf("boot: %s", cbuff);
566 word_split(char **linep, char **paramsp)
581 while (*p != 0 && *p != ' ')
590 make_params(char *label, char *params)
593 static char buffer[2048];
598 p = cfg_get_strg(label, "literal");
610 p = cfg_get_strg(label, "root");
617 if (cfg_get_flag(label, "read-only")) {
621 if (cfg_get_flag(label, "read-write")) {
625 p = cfg_get_strg(label, "ramdisk");
627 strcpy (q, "ramdisk=");
632 p = cfg_get_strg(label, "initrd-size");
634 strcpy (q, "ramdisk_size=");
639 if (cfg_get_flag(label, "novideo")) {
640 strcpy (q, "video=ofonly");
644 p = cfg_get_strg (label, "append");
651 pause_after = cfg_get_flag (label, "pause-after");
652 p = cfg_get_strg(label, "pause-message");
661 void check_password(char *str)
665 prom_printf("\n%s", str);
666 for (i = 0; i < 3; i++) {
667 prom_printf ("\nPassword: ");
669 cmdedit ((void (*)(void)) 0, 1);
671 #ifdef USE_MD5_PASSWORDS
672 if (!strncmp (password, "$1$", 3)) {
673 if (!check_md5_password(passwdbuff, password))
676 else if (!strcmp (password, passwdbuff))
679 if (!strcmp (password, passwdbuff))
681 #endif /* USE_MD5_PASSWORDS */
684 prom_printf ("Incorrect password. Try again.");
687 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
688 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
689 " ||----w |\n || ||\n");
691 prom_interpret("reset-all");
694 int get_params(struct boot_param_t* params)
700 char *imagename = 0, *label;
705 static int first = 1;
706 static char imagepath[1024];
707 static char initrdpath[1024];
708 static char sysmappath[1024];
711 memset(params, 0, sizeof(*params));
713 params->kernel.part = -1;
714 params->rd.part = -1;
715 params->sysmap.part = -1;
722 imagename = bootargs;
723 word_split(&imagename, ¶ms->args);
724 timeout = DEFAULT_TIMEOUT;
726 prom_printf("Default supplied on the command line: %s ", imagename);
728 prom_printf("%s", params->args);
731 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
732 timeout = simple_strtol(q, NULL, 0);
735 prom_printf("boot: ");
740 end = beg + 100 * timeout;
742 c = prom_nbgetchar();
743 } while (c == -1 && prom_getms() <= end);
747 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
753 if (c != -1 && c != '\n' && c != '\r') {
756 } else if (c >= ' ') {
759 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
762 prom_printf("%s\n", cbuff);
767 if (c == '\n' || c == '\r') {
769 if (bootoncelabel[0] != 0)
770 imagename = bootoncelabel;
772 imagename = cfg_get_default();
775 prom_printf("%s", imagename);
777 prom_printf(" %s", params->args);
779 } else if (!singlekey) {
780 cmdedit(maintabfunc, 0);
782 strcpy(given_bootargs, cbuff);
783 given_bootargs_by_user = 1;
785 word_split(&imagename, ¶ms->args);
788 /* chrp gets this wrong, force it -- Cort */
789 if ( useconf && (!imagename || imagename[0] == 0 ))
790 imagename = cfg_get_default();
793 defdevice = boot.dev;
796 defdevice = cfg_get_strg(0, "device");
797 p = cfg_get_strg(0, "partition");
799 n = simple_strtol(p, &endp, 10);
800 if (endp != p && *endp == 0)
803 p = cfg_get_strg(0, "pause-message");
806 if (cfg_get_flag(0, "restricted"))
808 p = cfg_get_strg(imagename, "image");
812 defdevice = cfg_get_strg(label, "device");
813 if(!defdevice) defdevice=boot.dev;
814 p = cfg_get_strg(label, "partition");
816 n = simple_strtol(p, &endp, 10);
817 if (endp != p && *endp == 0)
820 if (cfg_get_flag(label, "restricted"))
823 if (params->args && password && restricted)
824 check_password ("To specify arguments for this image "
825 "you must enter the password.");
826 else if (password && !restricted)
827 check_password ("This image is restricted.");
829 params->args = make_params(label, params->args);
833 if (!strcmp (imagename, "help")) {
834 /* FIXME: defdevice shouldn't need to be reset all over the place */
835 if(!defdevice) defdevice = boot.dev;
837 "\nPress the tab key for a list of defined images.\n"
838 "The label marked with a \"*\" is is the default image, "
839 "press <return> to boot it.\n\n"
840 "To boot any other label simply type its name and press <return>.\n\n"
841 "To boot a kernel image which is not defined in the yaboot configuration \n"
842 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
843 "\"device:\" is the OpenFirmware device path to the disk the image \n"
844 "resides on, and \"partno\" is the partition number the image resides on.\n"
845 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
846 "device, if you only specify a filename you should not start it with a \",\"\n\n"
847 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
848 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
851 "To use an alternative config file rather than /etc/yaboot.conf, type on\n"
852 " Open FirmWare Prompt: \"boot conf=device:partition,/path/to/configfile\"\n"
853 "where \"device\" and \"partition\" are defined like above.\n\n", defdevice, defpart);
858 if (!strcmp (imagename, "halt")) {
860 check_password ("Restricted command.");
864 if (!strcmp (imagename, "bye")) {
866 check_password ("Restricted command.");
872 if (imagename[0] == '$') {
873 /* forth command string */
875 check_password ("OpenFirmware commands are restricted.");
876 prom_interpret(imagename+1);
880 strncpy(imagepath, imagename, 1024);
882 if (!label && password)
883 check_password ("To boot a custom image you must enter the password.");
885 if (!parse_device_path(imagepath, defdevice, defpart,
886 "/vmlinux", ¶ms->kernel)) {
887 prom_printf("%s: Unable to parse\n", imagepath);
890 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
891 params->kernel.part, params->kernel.file);
894 p = cfg_get_strg(label, "initrd");
896 DEBUG_F("Parsing initrd path <%s>\n", p);
897 strncpy(initrdpath, p, 1024);
898 if (!parse_device_path(initrdpath, defdevice, defpart,
899 "/root.bin", ¶ms->rd)) {
900 prom_printf("%s: Unable to parse\n", imagepath);
904 p = cfg_get_strg(label, "sysmap");
906 DEBUG_F("Parsing sysmap path <%s>\n", p);
907 strncpy(sysmappath, p, 1024);
908 if (!parse_device_path(sysmappath, defdevice, defpart,
909 "/boot/System.map", ¶ms->sysmap)) {
910 prom_printf("%s: Unable to parse\n", imagepath);
918 /* This is derived from quik core. To be changed to first parse the headers
919 * doing lazy-loading, and then claim the memory before loading the kernel
921 * We also need to add initrd support to this whole mecanism
926 #define MAX_HEADERS 32
928 struct boot_file_t file;
930 static struct boot_param_t params;
932 unsigned long initrd_size;
934 unsigned long sysmap_size;
935 kernel_entry_t kernel_entry;
936 struct bi_record* birec;
939 void *initrd_more,*initrd_want;
940 unsigned long initrd_read;
942 loadinfo.load_loc = 0;
950 if (get_params(¶ms))
952 if (!params.kernel.file)
955 prom_printf("Please wait, loading kernel...\n");
957 memset(&file, 0, sizeof(file));
959 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
960 && params.kernel.file[0] != '\\') {
961 loc=(char*)malloc(strlen(params.kernel.file)+3);
963 prom_printf ("malloc error\n");
966 strcpy(loc,boot.file);
967 strcat(loc,params.kernel.file);
968 free(params.kernel.file);
969 params.kernel.file=loc;
971 result = open_file(¶ms.kernel, &file);
972 if (result != FILE_ERR_OK) {
973 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
974 prom_perror(result, params.kernel.file);
978 /* Read the Elf e_ident, e_type and e_machine fields to
979 * determine Elf file type
981 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
982 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
983 file.fs->close(&file);
984 memset(&file, 0, sizeof(file));
988 if (is_elf32(&loadinfo)) {
989 if (!load_elf32(&file, &loadinfo)) {
990 file.fs->close(&file);
991 memset(&file, 0, sizeof(file));
994 prom_printf(" Elf32 kernel loaded...\n");
995 } else if (is_elf64(&loadinfo)) {
996 if (!load_elf64(&file, &loadinfo)) {
997 file.fs->close(&file);
998 memset(&file, 0, sizeof(file));
1001 prom_printf(" Elf64 kernel loaded...\n");
1003 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1004 file.fs->close(&file);
1005 memset(&file, 0, sizeof(file));
1008 file.fs->close(&file);
1009 memset(&file, 0, sizeof(file));
1011 /* If sysmap, load it (only if booting a vmlinux).
1013 if (flat_vmlinux && params.sysmap.file) {
1014 prom_printf("Loading System.map ...\n");
1015 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1016 && params.sysmap.file[0] != '\\') {
1018 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1020 prom_printf ("malloc error\n");
1023 strcpy(loc,boot.file);
1024 strcat(loc,params.sysmap.file);
1025 free(params.sysmap.file);
1026 params.sysmap.file=loc;
1029 result = open_file(¶ms.sysmap, &file);
1030 if (result != FILE_ERR_OK) {
1031 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1032 prom_perror(result, params.sysmap.file);
1035 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1036 if (sysmap_base == (void *)-1) {
1037 prom_printf("Claim failed for sysmap memory\n");
1041 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1042 if (sysmap_size == 0)
1045 ((char *)sysmap_base)[sysmap_size++] = 0;
1047 file.fs->close(&file);
1048 memset(&file, 0, sizeof(file));
1051 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1052 sysmap_base, sysmap_size >> 10);
1053 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1055 prom_printf("System.map load failed !\n");
1060 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1061 * can't tell the size it will be so we claim an arbitrary amount
1064 if (flat_vmlinux && params.rd.file) {
1065 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1066 && params.kernel.file[0] != '\\')
1069 loc=(char*)malloc(strlen(params.rd.file)+3);
1071 prom_printf ("Malloc error\n");
1074 strcpy(loc,boot.file);
1075 strcat(loc,params.rd.file);
1076 free(params.rd.file);
1079 prom_printf("Loading ramdisk...\n");
1080 result = open_file(¶ms.rd, &file);
1081 if (result != FILE_ERR_OK) {
1082 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1083 prom_perror(result, params.rd.file);
1086 #define INITRD_CHUNKSIZE 0x100000
1087 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1088 if (initrd_base == (void *)-1) {
1089 prom_printf("Claim failed for initrd memory\n");
1092 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1093 if (initrd_size == 0)
1095 initrd_read = initrd_size;
1096 initrd_more = initrd_base;
1097 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1098 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1099 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1100 if (initrd_more != initrd_want) {
1101 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1105 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1106 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1107 initrd_size += initrd_read;
1110 file.fs->close(&file);
1111 memset(&file, 0, sizeof(file));
1114 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1115 initrd_base, initrd_size >> 10);
1117 prom_printf("ramdisk load failed !\n");
1122 DEBUG_F("setting kernel args to: %s\n", params.args);
1123 prom_setargs(params.args);
1124 DEBUG_F("flushing icache...");
1125 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1130 * Fill new boot infos (only if booting a vmlinux).
1132 * The birec is low on memory, probably inside the malloc pool,
1133 * so we don't write it earlier. At this point, we should not
1134 * use anything coming from the malloc pool.
1136 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1138 /* We make sure it's mapped. We map only 64k for now, it's
1139 * plenty enough we don't claim since this precise memory
1140 * range may already be claimed by the malloc pool.
1142 prom_map (birec, birec, 0x10000);
1143 DEBUG_F("birec at %p\n", birec);
1146 birec->tag = BI_FIRST;
1147 birec->size = sizeof(struct bi_record);
1148 birec = (struct bi_record *)((ulong)birec + birec->size);
1150 birec->tag = BI_BOOTLOADER_ID;
1151 sprintf( (char *)birec->data, "yaboot");
1152 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1153 birec = (struct bi_record *)((ulong)birec + birec->size);
1155 birec->tag = BI_MACHTYPE;
1156 birec->data[0] = _machine;
1157 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1158 birec = (struct bi_record *)((ulong)birec + birec->size);
1161 birec->tag = BI_SYSMAP;
1162 birec->data[0] = (ulong)sysmap_base;
1163 birec->data[1] = sysmap_size;
1164 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1165 birec = (struct bi_record *)((ulong)birec + birec->size);
1167 birec->tag = BI_LAST;
1168 birec->size = sizeof(struct bi_record);
1169 birec = (struct bi_record *)((ulong)birec + birec->size);
1172 /* compute the kernel's entry point. */
1173 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1175 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1176 DEBUG_F("kernel: arg1 = %p,\n"
1177 " arg2 = 0x%08lx,\n"
1181 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1183 DEBUG_F("Entering kernel...\n");
1185 /* call the kernel with our stack. */
1186 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1194 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1197 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1199 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1200 unsigned long addr, loadaddr;
1202 /* Read the rest of the Elf header... */
1203 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1204 prom_printf("\nCan't read Elf32 image header\n");
1208 DEBUG_F("Elf32 header:\n");
1209 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1210 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1211 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1212 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1213 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1214 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1215 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1216 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1217 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1218 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1220 loadinfo->entry = e->e_entry;
1222 if (e->e_phnum > MAX_HEADERS) {
1223 prom_printf ("Can only load kernels with one program header\n");
1227 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1229 prom_printf ("Malloc error\n");
1233 /* Now, we read the section header */
1234 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1235 prom_printf ("seek error\n");
1238 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1239 sizeof(Elf32_Phdr) * e->e_phnum) {
1240 prom_printf ("read error\n");
1244 /* Scan through the program header
1245 * HACK: We must return the _memory size of the kernel image, not the
1246 * file size (because we have to leave room before other boot
1247 * infos. This code works as a side effect of the fact that
1248 * we have one section and vaddr == p_paddr
1250 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1252 for (i = 0; i < e->e_phnum; ++i, ++p) {
1253 if (p->p_type != PT_LOAD || p->p_offset == 0)
1255 if (loadinfo->memsize == 0) {
1256 loadinfo->offset = p->p_offset;
1257 loadinfo->memsize = p->p_memsz;
1258 loadinfo->filesize = p->p_filesz;
1259 loadinfo->load_loc = p->p_vaddr;
1261 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1262 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1266 if (loadinfo->memsize == 0) {
1267 prom_printf("Can't find a loadable segment !\n");
1271 /* leave some room (1Mb) for boot infos */
1272 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1273 /* Claim OF memory */
1274 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1276 /* Determine whether we are trying to boot a vmlinux or some
1277 * other binary image (eg, zImage). We load vmlinux's at
1278 * KERNELADDR and all other binaries at their e_entry value.
1280 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1282 loadaddr = KERNELADDR;
1285 loadaddr = loadinfo->load_loc;
1288 /* On some systems, loadaddr may already be claimed, so try some
1289 * other nearby addresses before giving up.
1291 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1292 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1293 if (loadinfo->base != (void *)-1) break;
1295 if (loadinfo->base == (void *)-1) {
1296 prom_printf("Claim error, can't allocate kernel memory\n");
1300 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1301 loadinfo->base, loadinfo->memsize);
1302 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1303 loadaddr, loadinfo->memsize);
1305 /* Load the program segments... */
1307 for (i = 0; i < e->e_phnum; ++i, ++p) {
1308 unsigned long offset;
1309 if (p->p_type != PT_LOAD || p->p_offset == 0)
1312 /* Now, we skip to the image itself */
1313 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1314 prom_printf ("Seek error\n");
1315 prom_release(loadinfo->base, loadinfo->memsize);
1318 offset = p->p_vaddr - loadinfo->load_loc;
1319 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1320 prom_printf ("Read failed\n");
1321 prom_release(loadinfo->base, loadinfo->memsize);
1328 /* Return success at loading the Elf32 kernel */
1338 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1341 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1343 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1344 unsigned long addr, loadaddr;
1346 /* Read the rest of the Elf header... */
1347 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1348 prom_printf("\nCan't read Elf64 image header\n");
1352 DEBUG_F("Elf64 header:\n");
1353 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1354 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1355 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1356 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1357 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1358 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1359 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1360 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1361 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1362 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1364 loadinfo->entry = e->e_entry;
1366 if (e->e_phnum > MAX_HEADERS) {
1367 prom_printf ("Can only load kernels with one program header\n");
1371 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1373 prom_printf ("Malloc error\n");
1377 /* Now, we read the section header */
1378 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1379 prom_printf ("Seek error\n");
1382 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1383 sizeof(Elf64_Phdr) * e->e_phnum) {
1384 prom_printf ("Read error\n");
1388 /* Scan through the program header
1389 * HACK: We must return the _memory size of the kernel image, not the
1390 * file size (because we have to leave room before other boot
1391 * infos. This code works as a side effect of the fact that
1392 * we have one section and vaddr == p_paddr
1394 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1396 for (i = 0; i < e->e_phnum; ++i, ++p) {
1397 if (p->p_type != PT_LOAD || p->p_offset == 0)
1399 if (loadinfo->memsize == 0) {
1400 loadinfo->offset = p->p_offset;
1401 loadinfo->memsize = p->p_memsz;
1402 loadinfo->filesize = p->p_filesz;
1403 loadinfo->load_loc = p->p_vaddr;
1405 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1406 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1410 if (loadinfo->memsize == 0) {
1411 prom_printf("Can't find a loadable segment !\n");
1415 /* leave some room (1Mb) for boot infos */
1416 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1417 /* Claim OF memory */
1418 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1420 /* Determine whether we are trying to boot a vmlinux or some
1421 * other binary image (eg, zImage). We load vmlinux's at
1422 * KERNELADDR and all other binaries at their e_entry value.
1424 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1426 loadaddr = KERNELADDR;
1429 loadaddr = e->e_entry;
1432 /* On some systems, loadaddr may already be claimed, so try some
1433 * other nearby addresses before giving up.
1435 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1436 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1437 if (loadinfo->base != (void *)-1) break;
1439 if (loadinfo->base == (void *)-1) {
1440 prom_printf("Claim error, can't allocate kernel memory\n");
1444 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1445 loadinfo->base, loadinfo->memsize);
1446 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1447 loadaddr, loadinfo->memsize);
1449 /* Load the program segments... */
1451 for (i = 0; i < e->e_phnum; ++i, ++p) {
1452 unsigned long offset;
1453 if (p->p_type != PT_LOAD || p->p_offset == 0)
1456 /* Now, we skip to the image itself */
1457 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1458 prom_printf ("Seek error\n");
1459 prom_release(loadinfo->base, loadinfo->memsize);
1462 offset = p->p_vaddr - loadinfo->load_loc;
1463 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1464 prom_printf ("Read failed\n");
1465 prom_release(loadinfo->base, loadinfo->memsize);
1472 /* Return success at loading the Elf64 kernel */
1482 is_elf32(loadinfo_t *loadinfo)
1484 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1486 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1487 e->e_ident[EI_MAG1] == ELFMAG1 &&
1488 e->e_ident[EI_MAG2] == ELFMAG2 &&
1489 e->e_ident[EI_MAG3] == ELFMAG3 &&
1490 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1491 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1492 e->e_type == ET_EXEC &&
1493 e->e_machine == EM_PPC);
1497 is_elf64(loadinfo_t *loadinfo)
1499 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1501 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1502 e->e_ident[EI_MAG1] == ELFMAG1 &&
1503 e->e_ident[EI_MAG2] == ELFMAG2 &&
1504 e->e_ident[EI_MAG3] == ELFMAG3 &&
1505 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1506 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1507 e->e_type == ET_EXEC &&
1508 e->e_machine == EM_PPC64);
1514 #ifdef CONFIG_SET_COLORMAP
1515 static unsigned char default_colors[] = {
1534 prom_handle scrn = PROM_INVALID_HANDLE;
1536 /* Try Apple's mac-boot screen ihandle */
1537 result = (int)call_prom_return("interpret", 1, 2,
1538 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1539 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1541 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1543 /* Hrm... check to see if stdout is a display */
1544 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1545 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1546 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1547 DEBUG_F("got it ! stdout is a screen\n");
1550 /* Else, we try to open the package */
1551 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1552 DEBUG_F("Open screen result: %p\n", scrn);
1556 if (scrn == PROM_INVALID_HANDLE) {
1557 prom_printf("No screen device found !/n");
1561 prom_set_color(scrn, i, default_colors[i*3],
1562 default_colors[i*3+1], default_colors[i*3+2]);
1564 prom_printf("\x1b[1;37m\x1b[2;40m");
1566 for (i=0;i<16; i++) {
1567 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1568 ansi_color_table[i].index,
1569 ansi_color_table[i].value,
1570 ansi_color_table[i].name,
1571 ansi_color_table[i].name);
1572 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1573 ansi_color_table[i].index,
1574 ansi_color_table[i].value+10,
1575 ansi_color_table[i].name,
1576 ansi_color_table[i].name);
1578 prom_printf("\x1b[1;37m\x1b[2;40m");
1579 #endif /* COLOR_TEST */
1585 #endif /* CONFIG_SET_COLORMAP */
1593 char conf_path[1024];
1595 if (_machine == _MACH_Pmac)
1598 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1599 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1600 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1601 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1603 /* If conf= specified on command line, it overrides
1604 Usage: conf=device:partition,/path/to/conffile
1605 Example: On Open Firmware Prompt, type
1606 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1608 if (!strncmp(bootargs, "conf=", 5)) {
1609 DEBUG_F("Using conf argument in Open Firmware\n");
1610 char *end = strchr(bootargs,' ');
1614 strcpy(bootdevice, bootargs + 5);
1616 DEBUG_F("Using conf=%s\n", bootdevice);
1618 /* Remove conf=xxx from bootargs */
1620 memmove(bootargs, end+1, strlen(end+1)+1);
1624 if (bootdevice[0] == 0) {
1625 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1626 DEBUG_F("boot-device = %s\n", bootdevice);
1628 if (bootdevice[0] == 0) {
1629 prom_printf("Couldn't determine boot device\n");
1633 if (bootoncelabel[0] == 0) {
1634 prom_get_options("boot-once", bootoncelabel,
1635 sizeof(bootoncelabel));
1636 if (bootoncelabel[0] != 0)
1637 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1639 prom_set_options("boot-once", NULL, 0);
1641 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1642 prom_printf("%s: Unable to parse\n", bootdevice);
1645 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1646 boot.dev, boot.part, boot.file);
1649 if (_machine == _MACH_chrp)
1650 boot.file = "/etc/";
1651 else if (strlen(boot.file)) {
1652 if (!strncmp(boot.file, "\\\\", 2))
1656 p = last = boot.file;
1666 if (strlen(boot.file))
1667 strcat(boot.file, "\\");
1670 strcpy(conf_path, boot.file);
1671 strcat(conf_path, CONFIG_FILE_NAME);
1672 boot.file = conf_path;
1673 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1674 boot.dev, boot.part, boot.file);
1678 * If we're doing a netboot, first look for one which matches our
1681 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1682 prom_printf("Try to netboot\n");
1683 useconf = load_my_config_file(&boot);
1687 useconf = load_config_file(&boot);
1689 prom_printf("Welcome to yaboot version " VERSION "\n");
1690 prom_printf("Enter \"help\" to get some basic usage information\n");
1692 /* I am fed up with lusers using the wrong partition type and
1693 mailing me *when* it breaks */
1695 if (_machine == _MACH_Pmac) {
1696 char *entry = cfg_get_strg(0, "ptypewarning");
1699 warn = strcmp(entry,
1700 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1702 ptype = get_part_type(boot.dev, boot.part);
1703 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1704 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1705 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1713 prom_printf("Bye.\n");
1719 * c-file-style: "k&r"