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 bootlastlabel[BOOTLASTSZ] = {0};
118 char fw_nbr_reboots[FW_NBR_REBOOTSZ] = {0};
119 long fw_reboot_cnt = 0;
120 char *password = NULL;
121 struct boot_fspec_t boot;
122 int _machine = _MACH_Pmac;
125 #ifdef CONFIG_COLOR_TEXT
127 /* Color values for text ui */
128 static struct ansi_color_t {
132 } ansi_color_table[] = {
140 { "light-gray", 0, 37 },
141 { "dark-gray", 1, 30 },
142 { "light-blue", 1, 31 },
143 { "light-green", 1, 32 },
144 { "light-cyan", 1, 33 },
145 { "light-red", 1, 34 },
146 { "light-purple", 1, 35 },
152 /* Default colors for text ui */
155 #endif /* CONFIG_COLOR_TEXT */
159 static int test_data = 0;
161 static int pause_after;
162 static char *pause_message = "Type go<return> to continue.\n";
163 static char given_bootargs[1024];
164 static int given_bootargs_by_user = 0;
166 extern unsigned char linux_logo_red[];
167 extern unsigned char linux_logo_green[];
168 extern unsigned char linux_logo_blue[];
170 #define DEFAULT_TIMEOUT -1
172 /* Entry, currently called directly by crt0 (bss not inited) */
174 extern char* __bss_start;
178 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
181 void* malloc_base = NULL;
185 /* OF seems to do it, but I'm not very confident */
186 memset(&__bss_start, 0, &_end - &__bss_start);
188 /* Initialize OF interface */
189 prom_init ((prom_entry) r5);
191 /* Allocate some memory for malloc'ator */
192 for (addr = MALLOCADDR; addr <= MALLOCADDR * 16 ;addr+=0x100000) {
193 malloc_base = prom_claim((void *)addr, MALLOCSIZE, 0);
194 if (malloc_base != (void *)-1) break;
196 if (malloc_base == (void *)-1) {
197 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
198 MALLOCSIZE, MALLOCADDR);
201 malloc_init(malloc_base, MALLOCSIZE);
202 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
203 malloc_base, MALLOCSIZE);
205 /* A few useless DEBUG_F's */
206 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
207 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
208 DEBUG_F("test_data : %d (should be 0)\n", test_data);
209 DEBUG_F("&test_data : %p\n", &test_data);
210 DEBUG_F("&test_bss : %p\n", &test_bss);
211 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
213 /* ask the OF info if we're a chrp or pmac */
214 /* we need to set _machine before calling finish_device_tree */
215 root = prom_finddevice("/");
217 static char model[256];
218 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
219 !strncmp("bplan", model, 5))
220 _machine = _MACH_bplan;
221 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
222 !strncmp("chrp", model, 4))
223 _machine = _MACH_chrp;
225 if (prom_getprop(root, "model", model, 256 ) > 0 &&
226 !strncmp(model, "IBM", 3))
227 _machine = _MACH_chrp;
231 DEBUG_F("Running on _machine = %d\n", _machine);
235 result = yaboot_main();
237 /* Get rid of malloc pool */
239 prom_release(malloc_base, MALLOCSIZE);
240 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
250 #ifdef CONFIG_COLOR_TEXT
252 * Validify color for text ui
255 check_color_text_ui(char *color)
258 while(ansi_color_table[i].name) {
259 if (!strcmp(color, ansi_color_table[i].name))
265 #endif /* CONFIG_COLOR_TEXT */
268 void print_message_file(char *filename)
272 char *defdev = boot.dev;
273 int defpart = boot.part;
278 struct boot_file_t file;
279 struct boot_fspec_t msgfile;
281 defdev = cfg_get_strg(0, "device");
284 p = cfg_get_strg(0, "partition");
286 n = simple_strtol(p, &endp, 10);
287 if (endp != p && *endp == 0)
291 strncpy(msgpath, filename, sizeof(msgpath));
292 msgfile = boot; /* Copy all the original paramters */
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");
372 * set the default cf_option to label that has the same MAC addr
373 * it only works if there is a label with the MAC addr on yaboot.conf
375 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
376 /* change the variable bellow to get the MAC dinamicaly */
377 char * macaddr = NULL;
380 macaddr = prom_get_mac(prom_get_netinfo());
381 default_mac = cfg_set_default_by_mac(macaddr);
382 if (default_mac >= 1) {
383 prom_printf("Default label was changed to macaddr label.\n");
387 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
389 /* Now, we do the initialisations stored in the config file */
390 p = cfg_get_strg(0, "init-code");
394 password = cfg_get_strg(0, "password");
396 #ifdef CONFIG_COLOR_TEXT
397 p = cfg_get_strg(0, "fgcolor");
399 DEBUG_F("fgcolor=%s\n", p);
400 fgcolor = check_color_text_ui(p);
402 prom_printf("Invalid fgcolor: \"%s\".\n", p);
405 p = cfg_get_strg(0, "bgcolor");
407 DEBUG_F("bgcolor=%s\n", p);
408 bgcolor = check_color_text_ui(p);
410 prom_printf("Invalid bgcolor: \"%s\".\n", p);
414 sprintf(temp, "%x to background-color", bgcolor);
415 prom_interpret(temp);
422 sprintf(temp, "%x to foreground-color", fgcolor);
423 prom_interpret(temp);
425 #endif /* CONFIG_COLOR_TEXT */
427 p = cfg_get_strg(0, "init-message");
429 prom_printf("%s\n", p);
431 p = cfg_get_strg(0, "message");
433 print_message_file(p);
440 file.fs->close(&file);
449 * Search for config file by MAC address, then by IP address.
450 * Basically copying pxelinux's algorithm.
451 * http://syslinux.zytor.com/pxe.php#config
453 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
455 struct bootp_packet *packet;
457 struct boot_fspec_t fspec = *orig_fspec;
458 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
462 packet = prom_get_netinfo();
467 * First, try to match on mac address with the hardware type
471 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
472 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
476 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
477 strcat(fspec.file, prom_get_mac(packet));
479 rc = load_config_file(&fspec);
484 * Now try to match on IP.
486 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
487 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
489 for (flen = strlen(fspec.file),
490 minlen = strlen(cfgpath); flen > minlen; flen--) {
491 rc = load_config_file(&fspec);
494 /* Chop one digit off the end, try again */
495 fspec.file[flen - 1] = '\0';
499 if (rc) /* modify original only on success */
500 orig_fspec->file = fspec.file;
506 void maintabfunc (void)
510 prom_printf("boot: %s", cbuff);
515 word_split(char **linep, char **paramsp)
530 while (*p != 0 && *p != ' ')
539 make_params(char *label, char *params)
542 static char buffer[2048];
547 p = cfg_get_strg(label, "literal");
559 p = cfg_get_strg(label, "root");
566 if (cfg_get_flag(label, "read-only")) {
570 if (cfg_get_flag(label, "read-write")) {
574 p = cfg_get_strg(label, "ramdisk");
576 strcpy (q, "ramdisk=");
581 p = cfg_get_strg(label, "initrd-size");
583 strcpy (q, "ramdisk_size=");
588 if (cfg_get_flag(label, "novideo")) {
589 strcpy (q, "video=ofonly");
593 p = cfg_get_strg (label, "append");
600 pause_after = cfg_get_flag (label, "pause-after");
601 p = cfg_get_strg(label, "pause-message");
610 void check_password(char *str)
614 prom_printf("\n%s", str);
615 for (i = 0; i < 3; i++) {
616 prom_printf ("\nPassword: ");
618 cmdedit ((void (*)(void)) 0, 1);
620 #ifdef USE_MD5_PASSWORDS
621 if (!strncmp (password, "$1$", 3)) {
622 if (!check_md5_password(passwdbuff, password))
625 else if (!strcmp (password, passwdbuff))
628 if (!strcmp (password, passwdbuff))
630 #endif /* USE_MD5_PASSWORDS */
633 prom_printf ("Incorrect password. Try again.");
636 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
637 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
638 " ||----w |\n || ||\n");
640 prom_interpret("reset-all");
643 int get_params(struct boot_param_t* params)
647 char defdevice_bak[1024];
650 char *imagename = 0, *label;
655 static int first = 1;
656 static char imagepath[1024];
657 static char initrdpath[1024];
658 static char manualinitrd[1024];
659 static int definitrd = 1, hasarg = 0;
662 memset(params, 0, sizeof(*params));
664 params->kernel.part = -1;
665 params->rd.part = -1;
670 if (first && !fw_reboot_cnt) {
672 imagename = bootargs;
673 word_split(&imagename, ¶ms->args);
674 timeout = DEFAULT_TIMEOUT;
676 prom_printf("Default supplied on the command line: %s ", imagename);
678 prom_printf("%s", params->args);
681 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
682 timeout = simple_strtol(q, NULL, 0);
685 /* If this is a reboot due to FW detecting CAS changes then
686 * set timeout to 1. The last kernel booted will be booted
687 * again automatically. It should seem seamless to the user
692 prom_printf("boot: ");
697 end = beg + 100 * timeout;
699 c = prom_nbgetchar();
700 } while (c == -1 && prom_getms() <= end);
704 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
710 if (c != -1 && c != '\n' && c != '\r') {
713 } else if (c >= ' ') {
716 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
719 prom_printf("%s\n", cbuff);
724 if (c == '\n' || c == '\r') {
726 if (bootoncelabel[0] != 0)
727 imagename = bootoncelabel;
728 else if (bootlastlabel[0] != 0)
729 imagename = bootlastlabel;
731 imagename = cfg_get_default();
734 prom_printf("%s", imagename);
736 prom_printf(" %s", params->args);
738 } else if (!singlekey) {
739 cmdedit(maintabfunc, 0);
741 strcpy(given_bootargs, cbuff);
742 given_bootargs_by_user = 1;
744 word_split(&imagename, ¶ms->args);
747 /* initrd setup via cmd console */
748 /* first, check if the user uses it with some label */
749 if (!strncmp(params->args, "initrd=", 7)) {
750 DEBUG_F("params->args: %s\n", params->args);
753 /* after, check if there is the 'initrd=' in the imagename string */
754 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
756 /* return the value of definitrd to 1 */
760 /* args = "initrd=blah" */
771 /* copy the string after the '=' to manualinitrd */
772 strcpy(manualinitrd, args+7);
774 prom_printf("New initrd file specified: %s\n", manualinitrd);
776 prom_printf("ERROR: no initrd specified!\n");
780 /* set imagename with the default values of the config file */
781 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
782 imagename = cfg_get_default();
784 imagename = cfg_get_default();
787 /* chrp gets this wrong, force it -- Cort */
788 if ( useconf && (!imagename || imagename[0] == 0 ))
789 imagename = cfg_get_default();
791 /* write the imagename out so it can be reused on reboot if necessary */
792 prom_set_options("boot-last-label", imagename, strlen(imagename));
795 defdevice = boot.dev;
797 strcpy(defdevice_bak,defdevice);
800 defdevice = cfg_get_strg(0, "device");
801 p = cfg_get_strg(0, "partition");
803 n = simple_strtol(p, &endp, 10);
804 if (endp != p && *endp == 0)
807 p = cfg_get_strg(0, "pause-message");
810 if (cfg_get_flag(0, "restricted"))
812 p = cfg_get_strg(imagename, "image");
816 defdevice = cfg_get_strg(label, "device");
817 if(!defdevice) defdevice=boot.dev;
818 p = cfg_get_strg(label, "partition");
820 n = simple_strtol(p, &endp, 10);
821 if (endp != p && *endp == 0)
824 if (cfg_get_flag(label, "restricted"))
827 if (params->args && password && restricted)
828 check_password ("To specify arguments for this image "
829 "you must enter the password.");
830 else if (password && !restricted)
831 check_password ("This image is restricted.");
833 params->args = make_params(label, params->args);
837 if (!strcmp (imagename, "help")) {
838 /* FIXME: defdevice shouldn't need to be reset all over the place */
839 if(!defdevice) defdevice = boot.dev;
841 "\nPress the tab key for a list of defined images.\n"
842 "The label marked with a \"*\" is is the default image, "
843 "press <return> to boot it.\n\n"
844 "To boot any other label simply type its name and press <return>.\n\n"
845 "To boot a kernel image which is not defined in the yaboot configuration \n"
846 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
847 "\"device:\" is the OpenFirmware device path to the disk the image \n"
848 "resides on, and \"partno\" is the partition number the image resides on.\n"
849 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
850 "device, if you only specify a filename you should not start it with a \",\"\n\n"
851 "To boot a alternative initrd file rather than specified in the yaboot\n"
852 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
853 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
854 "kernel image. You can, also, specify a different initrd file to any other\n"
855 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
856 "and the specified initrd file will be loaded.\n\n"
857 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
858 "its device, partno and path, on Open Firmware Prompt:\n"
859 "boot conf=device:partno,/path/to/configfile\n."
860 "To reload the config file or load a new one, use the \"conf\" command\n"
861 "on Yaboot's prompt:\n"
862 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
863 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
864 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
869 if (!strcmp (imagename, "halt")) {
871 check_password ("Restricted command.");
875 if (!strcmp (imagename, "bye")) {
877 check_password ("Restricted command.");
883 if (!strncmp (imagename, "conf", 4)) {
885 // imagename = "conf file=blah dev=bleh part=blih"
886 DEBUG_F("Loading user-specified config file: %s\n",imagename);
888 check_password ("Restricted command.");
892 // args= "file=blah dev=bleh part=blih"
893 char *args = params->args;
897 // set a pointer to the first space in args
898 char *space = strchr(args,' ');
902 char temp[1024] = "0";
904 // copy next argument to temp
905 strncpy(temp, args, space-args);
907 // parse temp and set boot arguments
908 if (!strncmp (temp, "file=", 5)){
909 DEBUG_F("conf file: %s\n", temp+5);
910 strcpy(boot.file, temp+5);
911 } else if (!strncmp (temp, "device=", 7)){
912 DEBUG_F("conf device: %s\n", temp+7);
913 strcpy(boot.dev, temp+7);
914 } else if (!strncmp (temp, "partition=", 10)){
915 DEBUG_F("conf partition: %s\n", temp+10);
916 boot.part=simple_strtol(temp+10,NULL,10);
920 // set the pointer to the next space in args;
921 // set the loop control variable
922 if (strlen(space)>1){
923 // Go to the next argument
927 if (strchr(args,' ') == NULL)
928 space = &args[strlen(args)];
930 space = strchr(args,' ');
937 prom_printf("Loading config file...\n");
938 useconf = load_config_file(&boot);
940 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
941 timeout = simple_strtol(q, NULL, 0);
943 prom_printf("Restoring default values.\n");
944 strcpy(boot.file,"");
945 strcpy(boot.dev, defdevice_bak);
950 prom_printf("Current configuration:\n");
951 prom_printf("device: %s\n", boot.dev);
953 prom_printf("partition: auto\n");
955 prom_printf("partition: %d\n", boot.part);
956 if (strlen(boot.file))
957 prom_printf("file: %s\n", boot.file);
959 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
968 if (imagename[0] == '$') {
969 /* forth command string */
971 check_password ("OpenFirmware commands are restricted.");
972 prom_interpret(imagename+1);
976 strncpy(imagepath, imagename, 1024);
978 if (!label && password)
979 check_password ("To boot a custom image you must enter the password.");
981 params->kernel = boot; /* Copy all the original paramters */
982 if (!parse_device_path(imagepath, defdevice, defpart,
983 "/vmlinux", ¶ms->kernel)) {
984 prom_printf("%s: Unable to parse\n", imagepath);
987 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
989 p = cfg_get_strg(label, "initrd");
992 /* check if user seted to use a initrd file from boot console */
993 if (!definitrd && p != manualinitrd) {
994 if (manualinitrd[0] != "/" && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
995 strcpy(initrdpath, "/");
996 strcat(initrdpath, manualinitrd);
998 strncpy(initrdpath, manualinitrd, 1024);
1000 strncpy(initrdpath, p, 1024);
1002 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
1003 params->rd = boot; /* Copy all the original paramters */
1004 if (!parse_device_path(initrdpath, defdevice, defpart,
1005 "/root.bin", ¶ms->rd)) {
1006 prom_printf("%s: Unable to parse\n", imagepath);
1014 /* This is derived from quik core. To be changed to first parse the headers
1015 * doing lazy-loading, and then claim the memory before loading the kernel
1017 * We also need to add initrd support to this whole mecanism
1020 yaboot_text_ui(void)
1022 #define MAX_HEADERS 32
1024 struct boot_file_t file;
1026 static struct boot_param_t params;
1028 unsigned long initrd_size;
1029 kernel_entry_t kernel_entry;
1031 loadinfo_t loadinfo;
1032 void *initrd_more,*initrd_want;
1033 unsigned long initrd_read;
1035 loadinfo.load_loc = 0;
1041 if (get_params(¶ms))
1043 if (!params.kernel.file)
1046 prom_printf("Please wait, loading kernel...\n");
1048 memset(&file, 0, sizeof(file));
1050 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1051 && params.kernel.file[0] != '\\') {
1052 loc=(char*)malloc(strlen(params.kernel.file)+3);
1054 prom_printf ("malloc error\n");
1057 strcpy(loc,boot.file);
1058 strcat(loc,params.kernel.file);
1059 free(params.kernel.file);
1060 params.kernel.file=loc;
1062 result = open_file(¶ms.kernel, &file);
1063 if (result != FILE_ERR_OK) {
1064 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1065 prom_perror(result, params.kernel.file);
1069 /* Read the Elf e_ident, e_type and e_machine fields to
1070 * determine Elf file type
1072 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1073 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1074 file.fs->close(&file);
1075 memset(&file, 0, sizeof(file));
1079 if (is_elf32(&loadinfo)) {
1080 if (!load_elf32(&file, &loadinfo)) {
1081 file.fs->close(&file);
1082 memset(&file, 0, sizeof(file));
1085 prom_printf(" Elf32 kernel loaded...\n");
1086 } else if (is_elf64(&loadinfo)) {
1087 if (!load_elf64(&file, &loadinfo)) {
1088 file.fs->close(&file);
1089 memset(&file, 0, sizeof(file));
1092 prom_printf(" Elf64 kernel loaded...\n");
1094 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1095 file.fs->close(&file);
1096 memset(&file, 0, sizeof(file));
1099 file.fs->close(&file);
1100 memset(&file, 0, sizeof(file));
1102 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1103 * can't tell the size it will be so we claim an arbitrary amount
1106 if (flat_vmlinux && params.rd.file) {
1107 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1108 && params.kernel.file[0] != '\\')
1111 loc=(char*)malloc(strlen(params.rd.file)+3);
1113 prom_printf ("Malloc error\n");
1116 strcpy(loc,boot.file);
1117 strcat(loc,params.rd.file);
1118 free(params.rd.file);
1121 prom_printf("Loading ramdisk...\n");
1122 result = open_file(¶ms.rd, &file);
1123 if (result != FILE_ERR_OK) {
1124 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1125 prom_perror(result, params.rd.file);
1128 #define INITRD_CHUNKSIZE 0x100000
1129 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1130 if (initrd_base == (void *)-1) {
1131 prom_printf("Claim failed for initrd memory\n");
1134 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1135 if (initrd_size == 0)
1137 initrd_read = initrd_size;
1138 initrd_more = initrd_base;
1139 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1140 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1141 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1142 if (initrd_more != initrd_want) {
1143 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1147 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1148 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1149 initrd_size += initrd_read;
1152 file.fs->close(&file);
1153 memset(&file, 0, sizeof(file));
1156 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1157 initrd_base, initrd_size >> 10);
1159 prom_printf("ramdisk load failed !\n");
1164 DEBUG_F("setting kernel args to: %s\n", params.args);
1165 prom_setargs(params.args);
1166 DEBUG_F("flushing icache...");
1167 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1170 /* compute the kernel's entry point. */
1171 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1173 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1174 DEBUG_F("kernel: arg1 = %p,\n"
1175 " arg2 = 0x%08lx,\n"
1179 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1181 DEBUG_F("Entering kernel...\n");
1183 /* call the kernel with our stack. */
1184 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1192 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1195 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1197 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1198 unsigned long loadaddr;
1200 /* Read the rest of the Elf header... */
1201 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1202 prom_printf("\nCan't read Elf32 image header\n");
1206 DEBUG_F("Elf32 header:\n");
1207 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1208 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1209 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1210 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1211 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1212 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1213 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1214 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1215 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1216 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1218 loadinfo->entry = e->e_entry;
1220 if (e->e_phnum > MAX_HEADERS) {
1221 prom_printf ("Can only load kernels with one program header\n");
1225 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1227 prom_printf ("Malloc error\n");
1231 /* Now, we read the section header */
1232 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1233 prom_printf ("seek error\n");
1236 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1237 sizeof(Elf32_Phdr) * e->e_phnum) {
1238 prom_printf ("read error\n");
1242 /* Scan through the program header
1243 * HACK: We must return the _memory size of the kernel image, not the
1244 * file size (because we have to leave room before other boot
1245 * infos. This code works as a side effect of the fact that
1246 * we have one section and vaddr == p_paddr
1248 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1250 for (i = 0; i < e->e_phnum; ++i, ++p) {
1251 if (p->p_type != PT_LOAD || p->p_offset == 0)
1253 if (loadinfo->memsize == 0) {
1254 loadinfo->offset = p->p_offset;
1255 loadinfo->memsize = p->p_memsz;
1256 loadinfo->filesize = p->p_filesz;
1257 loadinfo->load_loc = p->p_vaddr;
1259 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1260 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1264 if (loadinfo->memsize == 0) {
1265 prom_printf("Can't find a loadable segment !\n");
1269 /* leave some room (1Mb) for boot infos */
1270 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1271 /* Claim OF memory */
1272 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1274 /* Determine whether we are trying to boot a vmlinux or some
1275 * other binary image (eg, zImage). We load vmlinux's at
1276 * KERNELADDR and all other binaries at their e_entry value.
1278 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1280 loadaddr = KERNELADDR;
1283 loadaddr = loadinfo->load_loc;
1286 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1287 if (loadinfo->base == (void *)-1) {
1288 prom_printf("Claim error, can't allocate kernel memory\n");
1292 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1293 loadinfo->base, loadinfo->memsize);
1294 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1295 loadaddr, loadinfo->memsize);
1297 /* Load the program segments... */
1299 for (i = 0; i < e->e_phnum; ++i, ++p) {
1300 unsigned long offset;
1301 if (p->p_type != PT_LOAD || p->p_offset == 0)
1304 /* Now, we skip to the image itself */
1305 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1306 prom_printf ("Seek error\n");
1307 prom_release(loadinfo->base, loadinfo->memsize);
1310 offset = p->p_vaddr - loadinfo->load_loc;
1311 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1312 prom_printf ("Read failed\n");
1313 prom_release(loadinfo->base, loadinfo->memsize);
1320 /* Return success at loading the Elf32 kernel */
1330 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1333 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1335 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1336 unsigned long loadaddr;
1338 /* Read the rest of the Elf header... */
1339 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1340 prom_printf("\nCan't read Elf64 image header\n");
1344 DEBUG_F("Elf64 header:\n");
1345 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1346 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1347 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1348 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1349 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1350 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1351 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1352 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1353 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1354 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1356 loadinfo->entry = e->e_entry;
1358 if (e->e_phnum > MAX_HEADERS) {
1359 prom_printf ("Can only load kernels with one program header\n");
1363 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1365 prom_printf ("Malloc error\n");
1369 /* Now, we read the section header */
1370 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1371 prom_printf ("Seek error\n");
1374 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1375 sizeof(Elf64_Phdr) * e->e_phnum) {
1376 prom_printf ("Read error\n");
1380 /* Scan through the program header
1381 * HACK: We must return the _memory size of the kernel image, not the
1382 * file size (because we have to leave room before other boot
1383 * infos. This code works as a side effect of the fact that
1384 * we have one section and vaddr == p_paddr
1386 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1388 for (i = 0; i < e->e_phnum; ++i, ++p) {
1389 if (p->p_type != PT_LOAD || p->p_offset == 0)
1391 if (loadinfo->memsize == 0) {
1392 loadinfo->offset = p->p_offset;
1393 loadinfo->memsize = p->p_memsz;
1394 loadinfo->filesize = p->p_filesz;
1395 loadinfo->load_loc = p->p_vaddr;
1397 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1398 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1402 if (loadinfo->memsize == 0) {
1403 prom_printf("Can't find a loadable segment !\n");
1407 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1408 /* Claim OF memory */
1409 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1411 /* Determine whether we are trying to boot a vmlinux or some
1412 * other binary image (eg, zImage). We load vmlinux's at
1413 * KERNELADDR and all other binaries at their e_entry value.
1415 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1417 loadaddr = KERNELADDR;
1420 loadaddr = e->e_entry;
1423 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1424 if (loadinfo->base == (void *)-1) {
1425 prom_printf("Claim error, can't allocate kernel memory\n");
1429 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1430 loadinfo->base, loadinfo->memsize);
1431 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1432 loadaddr, loadinfo->memsize);
1434 /* Load the program segments... */
1436 for (i = 0; i < e->e_phnum; ++i, ++p) {
1437 unsigned long offset;
1438 if (p->p_type != PT_LOAD || p->p_offset == 0)
1441 /* Now, we skip to the image itself */
1442 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1443 prom_printf ("Seek error\n");
1444 prom_release(loadinfo->base, loadinfo->memsize);
1447 offset = p->p_vaddr - loadinfo->load_loc;
1448 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1449 prom_printf ("Read failed\n");
1450 prom_release(loadinfo->base, loadinfo->memsize);
1457 /* Return success at loading the Elf64 kernel */
1467 is_elf32(loadinfo_t *loadinfo)
1469 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1471 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1472 e->e_ident[EI_MAG1] == ELFMAG1 &&
1473 e->e_ident[EI_MAG2] == ELFMAG2 &&
1474 e->e_ident[EI_MAG3] == ELFMAG3 &&
1475 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1476 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1477 e->e_type == ET_EXEC &&
1478 e->e_machine == EM_PPC);
1482 is_elf64(loadinfo_t *loadinfo)
1484 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
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] == ELFCLASS64 &&
1491 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1492 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1493 e->e_machine == EM_PPC64);
1499 #ifdef CONFIG_SET_COLORMAP
1500 static unsigned char default_colors[] = {
1519 prom_handle scrn = PROM_INVALID_HANDLE;
1521 /* Try Apple's mac-boot screen ihandle */
1522 result = (int)call_prom_return("interpret", 1, 2,
1523 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1524 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1526 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1528 /* Hrm... check to see if stdout is a display */
1529 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1530 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1531 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1532 DEBUG_F("got it ! stdout is a screen\n");
1535 /* Else, we try to open the package */
1536 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1537 DEBUG_F("Open screen result: %p\n", scrn);
1541 if (scrn == PROM_INVALID_HANDLE) {
1542 prom_printf("No screen device found !\n");
1546 prom_set_color(scrn, i, default_colors[i*3],
1547 default_colors[i*3+1], default_colors[i*3+2]);
1549 prom_printf("\x1b[1;37m\x1b[2;40m");
1551 for (i=0;i<16; i++) {
1552 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1553 ansi_color_table[i].index,
1554 ansi_color_table[i].value,
1555 ansi_color_table[i].name,
1556 ansi_color_table[i].name);
1557 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1558 ansi_color_table[i].index,
1559 ansi_color_table[i].value+10,
1560 ansi_color_table[i].name,
1561 ansi_color_table[i].name);
1563 prom_printf("\x1b[1;37m\x1b[2;40m");
1564 #endif /* COLOR_TEST */
1570 #endif /* CONFIG_SET_COLORMAP */
1579 char conf_path[1024];
1581 if (_machine == _MACH_Pmac)
1584 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1585 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1586 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1587 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1588 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1589 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1590 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1591 if (fw_reboot_cnt > 0L)
1592 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1594 /* If conf= specified on command line, it overrides
1595 Usage: conf=device:partition,/path/to/conffile
1596 Example: On Open Firmware Prompt, type
1597 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1599 if (!strncmp(bootargs, "conf=", 5)) {
1600 DEBUG_F("Using conf argument in Open Firmware\n");
1601 char *end = strchr(bootargs,' ');
1605 strcpy(bootdevice, bootargs + 5);
1607 DEBUG_F("Using conf=%s\n", bootdevice);
1609 /* Remove conf=xxx from bootargs */
1611 memmove(bootargs, end+1, strlen(end+1)+1);
1615 if (bootdevice[0] == 0) {
1616 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1617 DEBUG_F("boot-device = %s\n", bootdevice);
1619 if (bootdevice[0] == 0) {
1620 prom_printf("Couldn't determine boot device\n");
1624 if (bootoncelabel[0] == 0) {
1625 prom_get_options("boot-once", bootoncelabel,
1626 sizeof(bootoncelabel));
1627 if (bootoncelabel[0] != 0)
1628 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1630 prom_set_options("boot-once", NULL, 0);
1632 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1633 prom_printf("%s: Unable to parse\n", bootdevice);
1636 if (_machine == _MACH_bplan && !conf_given)
1638 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1639 boot.dev, boot.part, boot.file);
1642 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1643 boot.file = "/etc/";
1644 else if (strlen(boot.file)) {
1645 if (!strncmp(boot.file, "\\\\", 2))
1649 p = last = boot.file;
1659 if (strlen(boot.file))
1660 strcat(boot.file, "\\");
1663 strcpy(conf_path, boot.file);
1664 strcat(conf_path, CONFIG_FILE_NAME);
1665 boot.file = conf_path;
1666 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1667 boot.dev, boot.part, boot.file);
1671 * If we're doing a netboot, first look for one which matches our
1674 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1675 prom_printf("Try to netboot\n");
1676 useconf = load_my_config_file(&boot);
1680 useconf = load_config_file(&boot);
1682 prom_printf("Welcome to yaboot version " VERSION "\n");
1683 prom_printf("Enter \"help\" to get some basic usage information\n");
1685 /* I am fed up with lusers using the wrong partition type and
1686 mailing me *when* it breaks */
1688 if (_machine == _MACH_Pmac) {
1689 char *entry = cfg_get_strg(0, "ptypewarning");
1692 warn = strcmp(entry,
1693 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1695 ptype = get_part_type(boot.dev, boot.part);
1696 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1697 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1698 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1706 prom_printf("Bye.\n");
1712 * c-file-style: "k&r"