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;
336 /* Allocate a buffer for the config file */
337 conf_file = malloc(CONFIG_FILE_MAX);
339 prom_printf("Can't alloc config file buffer\n");
343 /* Build the path to the file */
344 if (_machine == _MACH_chrp)
345 strcpy(conf_path, "/etc/");
348 if (fspec->file && *fspec->file)
349 strcat(conf_path, fspec->file);
351 strcat(conf_path, CONFIG_FILE_NAME);
355 fspec->file = conf_path;
356 result = open_file(fspec, &file);
357 if (result != FILE_ERR_OK) {
358 prom_printf("%s:%d,", fspec->dev, fspec->part);
359 prom_perror(result, fspec->file);
360 prom_printf("Can't open config file\n");
366 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
368 prom_printf("Error, can't read config file\n");
371 prom_printf("Config file read, %d bytes\n", sz);
375 file.fs->close(&file);
378 /* Call the parsing code in cfg.c */
379 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
380 prom_printf ("Syntax error or read error config\n");
384 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
386 /* Now, we do the initialisations stored in the config file */
387 p = cfg_get_strg(0, "init-code");
391 password = cfg_get_strg(0, "password");
393 #ifdef CONFIG_COLOR_TEXT
394 p = cfg_get_strg(0, "fgcolor");
396 DEBUG_F("fgcolor=%s\n", p);
397 fgcolor = check_color_text_ui(p);
399 prom_printf("Invalid fgcolor: \"%s\".\n", p);
402 p = cfg_get_strg(0, "bgcolor");
404 DEBUG_F("bgcolor=%s\n", p);
405 bgcolor = check_color_text_ui(p);
407 prom_printf("Invalid bgcolor: \"%s\".\n", p);
411 sprintf(temp, "%x to background-color", bgcolor);
412 prom_interpret(temp);
419 sprintf(temp, "%x to foreground-color", fgcolor);
420 prom_interpret(temp);
422 #endif /* CONFIG_COLOR_TEXT */
424 p = cfg_get_strg(0, "init-message");
426 prom_printf("%s\n", p);
428 p = cfg_get_strg(0, "message");
430 print_message_file(p);
437 file.fs->close(&file);
446 * "bootp-response" is the property name which is specified in
447 * the recommended practice doc for obp-tftp. However, pmac
448 * provides a "dhcp-response" property and chrp provides a
449 * "bootpreply-packet" property. The latter appears to begin the
450 * bootp packet at offset 0x2a in the property for some reason.
453 struct bootp_property_offset {
454 char *name; /* property name */
455 int offset; /* offset into property where bootp packet occurs */
457 static const struct bootp_property_offset bootp_response_properties[] = {
458 { .name = "bootp-response", .offset = 0 },
459 { .name = "dhcp-response", .offset = 0 },
460 { .name = "bootpreply-packet", .offset = 0x2a },
463 struct bootp_packet {
464 u8 op, htype, hlen, hops;
467 u32 ciaddr, yiaddr, siaddr, giaddr;
468 unsigned char chaddr[16];
469 unsigned char sname[64];
470 unsigned char file[128];
471 /* vendor options go here if we need them */
475 * Search for config file by MAC address, then by IP address.
476 * Basically copying pxelinux's algorithm.
477 * http://syslinux.zytor.com/pxe.php#config
479 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
481 void *bootp_response = NULL;
483 struct bootp_packet *packet;
484 int i = 0, size, offset = 0, rc = 0;
486 struct boot_fspec_t fspec = *orig_fspec;
487 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
489 chosen = prom_finddevice("/chosen");
491 prom_printf("chosen=%d\n", chosen);
495 for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
496 propname = bootp_response_properties[i].name;
497 size = prom_getproplen(chosen, propname);
501 DEBUG_F("using /chosen/%s\n", propname);
502 offset = bootp_response_properties[i].offset;
509 if (sizeof(*packet) > size - offset) {
510 prom_printf("Malformed %s property?\n", propname);
514 bootp_response = malloc(size);
518 if (prom_getprop(chosen, propname, bootp_response, size) < 0)
521 packet = bootp_response + offset;
524 * First, try to match on mac address with the hardware type
528 /* 3 chars per byte in chaddr + 2 chars for htype + \0 */
529 fspec.file = malloc(packet->hlen * 3 + 2 + 1);
533 sprintf(fspec.file, "%02x", packet->htype);
535 for (i = 0; i < packet->hlen; i++) {
537 sprintf(tmp, "-%02x", packet->chaddr[i]);
538 strcat(fspec.file, tmp);
541 //DEBUG_F("----> mac addr: %s\n", fspec.file);
543 rc = load_config_file(&fspec);
549 * Now try to match on IP.
552 fspec.file = malloc(9);
553 sprintf(fspec.file, "%08X", packet->yiaddr);
555 while (strlen(fspec.file)) {
556 rc = load_config_file(&fspec);
559 /* Chop one digit off the end, try again */
560 fspec.file[strlen(fspec.file) - 1] = '\0';
564 if (rc) /* modify original only on success */
565 orig_fspec->file = fspec.file;
568 free(bootp_response);
572 void maintabfunc (void)
576 prom_printf("boot: %s", cbuff);
581 word_split(char **linep, char **paramsp)
596 while (*p != 0 && *p != ' ')
605 make_params(char *label, char *params)
608 static char buffer[2048];
613 p = cfg_get_strg(label, "literal");
625 p = cfg_get_strg(label, "root");
632 if (cfg_get_flag(label, "read-only")) {
636 if (cfg_get_flag(label, "read-write")) {
640 p = cfg_get_strg(label, "ramdisk");
642 strcpy (q, "ramdisk=");
647 p = cfg_get_strg(label, "initrd-size");
649 strcpy (q, "ramdisk_size=");
654 if (cfg_get_flag(label, "novideo")) {
655 strcpy (q, "video=ofonly");
659 p = cfg_get_strg (label, "append");
666 pause_after = cfg_get_flag (label, "pause-after");
667 p = cfg_get_strg(label, "pause-message");
676 void check_password(char *str)
680 prom_printf("\n%s", str);
681 for (i = 0; i < 3; i++) {
682 prom_printf ("\nPassword: ");
684 cmdedit ((void (*)(void)) 0, 1);
686 #ifdef USE_MD5_PASSWORDS
687 if (!strncmp (password, "$1$", 3)) {
688 if (!check_md5_password(passwdbuff, password))
691 else if (!strcmp (password, passwdbuff))
694 if (!strcmp (password, passwdbuff))
696 #endif /* USE_MD5_PASSWORDS */
699 prom_printf ("Incorrect password. Try again.");
702 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
703 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
704 " ||----w |\n || ||\n");
706 prom_interpret("reset-all");
709 int get_params(struct boot_param_t* params)
715 char *imagename = 0, *label;
720 static int first = 1;
721 static char imagepath[1024];
722 static char initrdpath[1024];
723 static char sysmappath[1024];
726 memset(params, 0, sizeof(*params));
728 params->kernel.part = -1;
729 params->rd.part = -1;
730 params->sysmap.part = -1;
737 imagename = bootargs;
738 word_split(&imagename, ¶ms->args);
739 timeout = DEFAULT_TIMEOUT;
741 prom_printf("Default supplied on the command line: %s ", imagename);
743 prom_printf("%s", params->args);
746 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
747 timeout = simple_strtol(q, NULL, 0);
750 prom_printf("boot: ");
755 end = beg + 100 * timeout;
757 c = prom_nbgetchar();
758 } while (c == -1 && prom_getms() <= end);
762 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
768 if (c != -1 && c != '\n' && c != '\r') {
771 } else if (c >= ' ') {
774 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
777 prom_printf("%s\n", cbuff);
782 if (c == '\n' || c == '\r') {
784 if (bootoncelabel[0] != 0)
785 imagename = bootoncelabel;
787 imagename = cfg_get_default();
790 prom_printf("%s", imagename);
792 prom_printf(" %s", params->args);
794 } else if (!singlekey) {
795 cmdedit(maintabfunc, 0);
797 strcpy(given_bootargs, cbuff);
798 given_bootargs_by_user = 1;
800 word_split(&imagename, ¶ms->args);
803 /* chrp gets this wrong, force it -- Cort */
804 if ( useconf && (!imagename || imagename[0] == 0 ))
805 imagename = cfg_get_default();
808 defdevice = boot.dev;
811 defdevice = cfg_get_strg(0, "device");
812 p = cfg_get_strg(0, "partition");
814 n = simple_strtol(p, &endp, 10);
815 if (endp != p && *endp == 0)
818 p = cfg_get_strg(0, "pause-message");
821 if (cfg_get_flag(0, "restricted"))
823 p = cfg_get_strg(imagename, "image");
827 defdevice = cfg_get_strg(label, "device");
828 if(!defdevice) defdevice=boot.dev;
829 p = cfg_get_strg(label, "partition");
831 n = simple_strtol(p, &endp, 10);
832 if (endp != p && *endp == 0)
835 if (cfg_get_flag(label, "restricted"))
838 if (params->args && password && restricted)
839 check_password ("To specify arguments for this image "
840 "you must enter the password.");
841 else if (password && !restricted)
842 check_password ("This image is restricted.");
844 params->args = make_params(label, params->args);
848 if (!strcmp (imagename, "help")) {
849 /* FIXME: defdevice shouldn't need to be reset all over the place */
850 if(!defdevice) defdevice = boot.dev;
852 "\nPress the tab key for a list of defined images.\n"
853 "The label marked with a \"*\" is is the default image, "
854 "press <return> to boot it.\n\n"
855 "To boot any other label simply type its name and press <return>.\n\n"
856 "To boot a kernel image which is not defined in the yaboot configuration \n"
857 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
858 "\"device:\" is the OpenFirmware device path to the disk the image \n"
859 "resides on, and \"partno\" is the partition number the image resides on.\n"
860 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
861 "device, if you only specify a filename you should not start it with a \",\"\n\n"
862 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
863 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
866 "To use an alternative config file rather than /etc/yaboot.conf, type on\n"
867 " Open FirmWare Prompt: \"boot conf=device:partition,/path/to/configfile\"\n"
868 "where \"device\" and \"partition\" are defined like above.\n\n", defdevice, defpart);
873 if (!strcmp (imagename, "halt")) {
875 check_password ("Restricted command.");
879 if (!strcmp (imagename, "bye")) {
881 check_password ("Restricted command.");
887 if (imagename[0] == '$') {
888 /* forth command string */
890 check_password ("OpenFirmware commands are restricted.");
891 prom_interpret(imagename+1);
895 strncpy(imagepath, imagename, 1024);
897 if (!label && password)
898 check_password ("To boot a custom image you must enter the password.");
900 if (!parse_device_path(imagepath, defdevice, defpart,
901 "/vmlinux", ¶ms->kernel)) {
902 prom_printf("%s: Unable to parse\n", imagepath);
905 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
906 params->kernel.part, params->kernel.file);
909 p = cfg_get_strg(label, "initrd");
911 DEBUG_F("Parsing initrd path <%s>\n", p);
912 strncpy(initrdpath, p, 1024);
913 if (!parse_device_path(initrdpath, defdevice, defpart,
914 "/root.bin", ¶ms->rd)) {
915 prom_printf("%s: Unable to parse\n", imagepath);
919 p = cfg_get_strg(label, "sysmap");
921 DEBUG_F("Parsing sysmap path <%s>\n", p);
922 strncpy(sysmappath, p, 1024);
923 if (!parse_device_path(sysmappath, defdevice, defpart,
924 "/boot/System.map", ¶ms->sysmap)) {
925 prom_printf("%s: Unable to parse\n", imagepath);
933 /* This is derived from quik core. To be changed to first parse the headers
934 * doing lazy-loading, and then claim the memory before loading the kernel
936 * We also need to add initrd support to this whole mecanism
941 #define MAX_HEADERS 32
943 struct boot_file_t file;
945 static struct boot_param_t params;
947 unsigned long initrd_size;
949 unsigned long sysmap_size;
950 kernel_entry_t kernel_entry;
951 struct bi_record* birec;
954 void *initrd_more,*initrd_want;
955 unsigned long initrd_read;
957 loadinfo.load_loc = 0;
965 if (get_params(¶ms))
967 if (!params.kernel.file)
970 prom_printf("Please wait, loading kernel...\n");
972 memset(&file, 0, sizeof(file));
974 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
975 && params.kernel.file[0] != '\\') {
976 loc=(char*)malloc(strlen(params.kernel.file)+3);
978 prom_printf ("malloc error\n");
981 strcpy(loc,boot.file);
982 strcat(loc,params.kernel.file);
983 free(params.kernel.file);
984 params.kernel.file=loc;
986 result = open_file(¶ms.kernel, &file);
987 if (result != FILE_ERR_OK) {
988 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
989 prom_perror(result, params.kernel.file);
993 /* Read the Elf e_ident, e_type and e_machine fields to
994 * determine Elf file type
996 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
997 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
998 file.fs->close(&file);
999 memset(&file, 0, sizeof(file));
1003 if (is_elf32(&loadinfo)) {
1004 if (!load_elf32(&file, &loadinfo)) {
1005 file.fs->close(&file);
1006 memset(&file, 0, sizeof(file));
1009 prom_printf(" Elf32 kernel loaded...\n");
1010 } else if (is_elf64(&loadinfo)) {
1011 if (!load_elf64(&file, &loadinfo)) {
1012 file.fs->close(&file);
1013 memset(&file, 0, sizeof(file));
1016 prom_printf(" Elf64 kernel loaded...\n");
1018 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1019 file.fs->close(&file);
1020 memset(&file, 0, sizeof(file));
1023 file.fs->close(&file);
1024 memset(&file, 0, sizeof(file));
1026 /* If sysmap, load it (only if booting a vmlinux).
1028 if (flat_vmlinux && params.sysmap.file) {
1029 prom_printf("Loading System.map ...\n");
1030 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1031 && params.sysmap.file[0] != '\\') {
1033 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1035 prom_printf ("malloc error\n");
1038 strcpy(loc,boot.file);
1039 strcat(loc,params.sysmap.file);
1040 free(params.sysmap.file);
1041 params.sysmap.file=loc;
1044 result = open_file(¶ms.sysmap, &file);
1045 if (result != FILE_ERR_OK) {
1046 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1047 prom_perror(result, params.sysmap.file);
1050 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1051 if (sysmap_base == (void *)-1) {
1052 prom_printf("Claim failed for sysmap memory\n");
1056 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1057 if (sysmap_size == 0)
1060 ((char *)sysmap_base)[sysmap_size++] = 0;
1062 file.fs->close(&file);
1063 memset(&file, 0, sizeof(file));
1066 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1067 sysmap_base, sysmap_size >> 10);
1068 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1070 prom_printf("System.map load failed !\n");
1075 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1076 * can't tell the size it will be so we claim an arbitrary amount
1079 if (flat_vmlinux && params.rd.file) {
1080 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1081 && params.kernel.file[0] != '\\')
1084 loc=(char*)malloc(strlen(params.rd.file)+3);
1086 prom_printf ("Malloc error\n");
1089 strcpy(loc,boot.file);
1090 strcat(loc,params.rd.file);
1091 free(params.rd.file);
1094 prom_printf("Loading ramdisk...\n");
1095 result = open_file(¶ms.rd, &file);
1096 if (result != FILE_ERR_OK) {
1097 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1098 prom_perror(result, params.rd.file);
1101 #define INITRD_CHUNKSIZE 0x100000
1102 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1103 if (initrd_base == (void *)-1) {
1104 prom_printf("Claim failed for initrd memory\n");
1107 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1108 if (initrd_size == 0)
1110 initrd_read = initrd_size;
1111 initrd_more = initrd_base;
1112 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1113 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1114 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1115 if (initrd_more != initrd_want) {
1116 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1120 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1121 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1122 initrd_size += initrd_read;
1125 file.fs->close(&file);
1126 memset(&file, 0, sizeof(file));
1129 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1130 initrd_base, initrd_size >> 10);
1132 prom_printf("ramdisk load failed !\n");
1137 DEBUG_F("setting kernel args to: %s\n", params.args);
1138 prom_setargs(params.args);
1139 DEBUG_F("flushing icache...");
1140 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1145 * Fill new boot infos (only if booting a vmlinux).
1147 * The birec is low on memory, probably inside the malloc pool,
1148 * so we don't write it earlier. At this point, we should not
1149 * use anything coming from the malloc pool.
1151 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1153 /* We make sure it's mapped. We map only 64k for now, it's
1154 * plenty enough we don't claim since this precise memory
1155 * range may already be claimed by the malloc pool.
1157 prom_map (birec, birec, 0x10000);
1158 DEBUG_F("birec at %p\n", birec);
1161 birec->tag = BI_FIRST;
1162 birec->size = sizeof(struct bi_record);
1163 birec = (struct bi_record *)((ulong)birec + birec->size);
1165 birec->tag = BI_BOOTLOADER_ID;
1166 sprintf( (char *)birec->data, "yaboot");
1167 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1168 birec = (struct bi_record *)((ulong)birec + birec->size);
1170 birec->tag = BI_MACHTYPE;
1171 birec->data[0] = _machine;
1172 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1173 birec = (struct bi_record *)((ulong)birec + birec->size);
1176 birec->tag = BI_SYSMAP;
1177 birec->data[0] = (ulong)sysmap_base;
1178 birec->data[1] = sysmap_size;
1179 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1180 birec = (struct bi_record *)((ulong)birec + birec->size);
1182 birec->tag = BI_LAST;
1183 birec->size = sizeof(struct bi_record);
1184 birec = (struct bi_record *)((ulong)birec + birec->size);
1187 /* compute the kernel's entry point. */
1188 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1190 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1191 DEBUG_F("kernel: arg1 = %p,\n"
1192 " arg2 = 0x%08lx,\n"
1196 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1198 DEBUG_F("Entering kernel...\n");
1200 /* call the kernel with our stack. */
1201 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1209 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1212 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1214 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1215 unsigned long addr, loadaddr;
1217 /* Read the rest of the Elf header... */
1218 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1219 prom_printf("\nCan't read Elf32 image header\n");
1223 DEBUG_F("Elf32 header:\n");
1224 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1225 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1226 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1227 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1228 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1229 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1230 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1231 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1232 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1233 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1235 loadinfo->entry = e->e_entry;
1237 if (e->e_phnum > MAX_HEADERS) {
1238 prom_printf ("Can only load kernels with one program header\n");
1242 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1244 prom_printf ("Malloc error\n");
1248 /* Now, we read the section header */
1249 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1250 prom_printf ("seek error\n");
1253 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1254 sizeof(Elf32_Phdr) * e->e_phnum) {
1255 prom_printf ("read error\n");
1259 /* Scan through the program header
1260 * HACK: We must return the _memory size of the kernel image, not the
1261 * file size (because we have to leave room before other boot
1262 * infos. This code works as a side effect of the fact that
1263 * we have one section and vaddr == p_paddr
1265 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1267 for (i = 0; i < e->e_phnum; ++i, ++p) {
1268 if (p->p_type != PT_LOAD || p->p_offset == 0)
1270 if (loadinfo->memsize == 0) {
1271 loadinfo->offset = p->p_offset;
1272 loadinfo->memsize = p->p_memsz;
1273 loadinfo->filesize = p->p_filesz;
1274 loadinfo->load_loc = p->p_vaddr;
1276 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1277 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1281 if (loadinfo->memsize == 0) {
1282 prom_printf("Can't find a loadable segment !\n");
1286 /* leave some room (1Mb) for boot infos */
1287 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1288 /* Claim OF memory */
1289 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1291 /* Determine whether we are trying to boot a vmlinux or some
1292 * other binary image (eg, zImage). We load vmlinux's at
1293 * KERNELADDR and all other binaries at their e_entry value.
1295 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1297 loadaddr = KERNELADDR;
1300 loadaddr = loadinfo->load_loc;
1303 /* On some systems, loadaddr may already be claimed, so try some
1304 * other nearby addresses before giving up.
1306 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1307 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1308 if (loadinfo->base != (void *)-1) break;
1310 if (loadinfo->base == (void *)-1) {
1311 prom_printf("Claim error, can't allocate kernel memory\n");
1315 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1316 loadinfo->base, loadinfo->memsize);
1317 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1318 loadaddr, loadinfo->memsize);
1320 /* Load the program segments... */
1322 for (i = 0; i < e->e_phnum; ++i, ++p) {
1323 unsigned long offset;
1324 if (p->p_type != PT_LOAD || p->p_offset == 0)
1327 /* Now, we skip to the image itself */
1328 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1329 prom_printf ("Seek error\n");
1330 prom_release(loadinfo->base, loadinfo->memsize);
1333 offset = p->p_vaddr - loadinfo->load_loc;
1334 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1335 prom_printf ("Read failed\n");
1336 prom_release(loadinfo->base, loadinfo->memsize);
1343 /* Return success at loading the Elf32 kernel */
1353 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1356 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1358 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1359 unsigned long addr, loadaddr;
1361 /* Read the rest of the Elf header... */
1362 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1363 prom_printf("\nCan't read Elf64 image header\n");
1367 DEBUG_F("Elf64 header:\n");
1368 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1369 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1370 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1371 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1372 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1373 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1374 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1375 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1376 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1377 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1379 loadinfo->entry = e->e_entry;
1381 if (e->e_phnum > MAX_HEADERS) {
1382 prom_printf ("Can only load kernels with one program header\n");
1386 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1388 prom_printf ("Malloc error\n");
1392 /* Now, we read the section header */
1393 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1394 prom_printf ("Seek error\n");
1397 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1398 sizeof(Elf64_Phdr) * e->e_phnum) {
1399 prom_printf ("Read error\n");
1403 /* Scan through the program header
1404 * HACK: We must return the _memory size of the kernel image, not the
1405 * file size (because we have to leave room before other boot
1406 * infos. This code works as a side effect of the fact that
1407 * we have one section and vaddr == p_paddr
1409 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1411 for (i = 0; i < e->e_phnum; ++i, ++p) {
1412 if (p->p_type != PT_LOAD || p->p_offset == 0)
1414 if (loadinfo->memsize == 0) {
1415 loadinfo->offset = p->p_offset;
1416 loadinfo->memsize = p->p_memsz;
1417 loadinfo->filesize = p->p_filesz;
1418 loadinfo->load_loc = p->p_vaddr;
1420 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1421 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1425 if (loadinfo->memsize == 0) {
1426 prom_printf("Can't find a loadable segment !\n");
1430 /* leave some room (1Mb) for boot infos */
1431 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1432 /* Claim OF memory */
1433 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1435 /* Determine whether we are trying to boot a vmlinux or some
1436 * other binary image (eg, zImage). We load vmlinux's at
1437 * KERNELADDR and all other binaries at their e_entry value.
1439 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1441 loadaddr = KERNELADDR;
1444 loadaddr = e->e_entry;
1447 /* On some systems, loadaddr may already be claimed, so try some
1448 * other nearby addresses before giving up.
1450 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1451 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1452 if (loadinfo->base != (void *)-1) break;
1454 if (loadinfo->base == (void *)-1) {
1455 prom_printf("Claim error, can't allocate kernel memory\n");
1459 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1460 loadinfo->base, loadinfo->memsize);
1461 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1462 loadaddr, loadinfo->memsize);
1464 /* Load the program segments... */
1466 for (i = 0; i < e->e_phnum; ++i, ++p) {
1467 unsigned long offset;
1468 if (p->p_type != PT_LOAD || p->p_offset == 0)
1471 /* Now, we skip to the image itself */
1472 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1473 prom_printf ("Seek error\n");
1474 prom_release(loadinfo->base, loadinfo->memsize);
1477 offset = p->p_vaddr - loadinfo->load_loc;
1478 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1479 prom_printf ("Read failed\n");
1480 prom_release(loadinfo->base, loadinfo->memsize);
1487 /* Return success at loading the Elf64 kernel */
1497 is_elf32(loadinfo_t *loadinfo)
1499 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
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] == ELFCLASS32 &&
1506 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1507 e->e_type == ET_EXEC &&
1508 e->e_machine == EM_PPC);
1512 is_elf64(loadinfo_t *loadinfo)
1514 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1516 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1517 e->e_ident[EI_MAG1] == ELFMAG1 &&
1518 e->e_ident[EI_MAG2] == ELFMAG2 &&
1519 e->e_ident[EI_MAG3] == ELFMAG3 &&
1520 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1521 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1522 e->e_type == ET_EXEC &&
1523 e->e_machine == EM_PPC64);
1529 #ifdef CONFIG_SET_COLORMAP
1530 static unsigned char default_colors[] = {
1549 prom_handle scrn = PROM_INVALID_HANDLE;
1551 /* Try Apple's mac-boot screen ihandle */
1552 result = (int)call_prom_return("interpret", 1, 2,
1553 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1554 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1556 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1558 /* Hrm... check to see if stdout is a display */
1559 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1560 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1561 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1562 DEBUG_F("got it ! stdout is a screen\n");
1565 /* Else, we try to open the package */
1566 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1567 DEBUG_F("Open screen result: %p\n", scrn);
1571 if (scrn == PROM_INVALID_HANDLE) {
1572 prom_printf("No screen device found !/n");
1576 prom_set_color(scrn, i, default_colors[i*3],
1577 default_colors[i*3+1], default_colors[i*3+2]);
1579 prom_printf("\x1b[1;37m\x1b[2;40m");
1581 for (i=0;i<16; i++) {
1582 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1583 ansi_color_table[i].index,
1584 ansi_color_table[i].value,
1585 ansi_color_table[i].name,
1586 ansi_color_table[i].name);
1587 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1588 ansi_color_table[i].index,
1589 ansi_color_table[i].value+10,
1590 ansi_color_table[i].name,
1591 ansi_color_table[i].name);
1593 prom_printf("\x1b[1;37m\x1b[2;40m");
1594 #endif /* COLOR_TEST */
1600 #endif /* CONFIG_SET_COLORMAP */
1608 char conf_path[1024];
1610 if (_machine == _MACH_Pmac)
1613 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1614 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1615 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1616 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1618 /* If conf= specified on command line, it overrides
1619 Usage: conf=device:partition,/path/to/conffile
1620 Example: On Open Firmware Prompt, type
1621 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1623 if (!strncmp(bootargs, "conf=", 5)) {
1624 DEBUG_F("Using conf argument in Open Firmware\n");
1625 char *end = strchr(bootargs,' ');
1629 strcpy(bootdevice, bootargs + 5);
1631 DEBUG_F("Using conf=%s\n", bootdevice);
1633 /* Remove conf=xxx from bootargs */
1635 memmove(bootargs, end+1, strlen(end+1)+1);
1639 if (bootdevice[0] == 0) {
1640 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1641 DEBUG_F("boot-device = %s\n", bootdevice);
1643 if (bootdevice[0] == 0) {
1644 prom_printf("Couldn't determine boot device\n");
1648 if (bootoncelabel[0] == 0) {
1649 prom_get_options("boot-once", bootoncelabel,
1650 sizeof(bootoncelabel));
1651 if (bootoncelabel[0] != 0)
1652 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1654 prom_set_options("boot-once", NULL, 0);
1656 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1657 prom_printf("%s: Unable to parse\n", bootdevice);
1660 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1661 boot.dev, boot.part, boot.file);
1664 if (_machine == _MACH_chrp)
1665 boot.file = "/etc/";
1666 else if (strlen(boot.file)) {
1667 if (!strncmp(boot.file, "\\\\", 2))
1671 p = last = boot.file;
1681 if (strlen(boot.file))
1682 strcat(boot.file, "\\");
1685 strcpy(conf_path, boot.file);
1686 strcat(conf_path, CONFIG_FILE_NAME);
1687 boot.file = conf_path;
1688 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1689 boot.dev, boot.part, boot.file);
1693 * If we're doing a netboot, first look for one which matches our
1696 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1697 prom_printf("Try to netboot\n");
1698 useconf = load_my_config_file(&boot);
1702 useconf = load_config_file(&boot);
1704 prom_printf("Welcome to yaboot version " VERSION "\n");
1705 prom_printf("Enter \"help\" to get some basic usage information\n");
1707 /* I am fed up with lusers using the wrong partition type and
1708 mailing me *when* it breaks */
1710 if (_machine == _MACH_Pmac) {
1711 char *entry = cfg_get_strg(0, "ptypewarning");
1714 warn = strcmp(entry,
1715 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1717 ptype = get_part_type(boot.dev, boot.part);
1718 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1719 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1720 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1728 prom_printf("Bye.\n");
1734 * c-file-style: "k&r"