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 #define MESSAGE_FILE_MAX 2048
63 #ifdef USE_MD5_PASSWORDS
65 #endif /* USE_MD5_PASSWORDS */
67 /* align addr on a size boundry - adjust address up if needed -- Cort */
68 #define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1)))
70 /* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at.
71 * These are used to determine whether we are booting a vmlinux, in
72 * which case, it will be loaded at KERNELADDR. Otherwise (eg zImage),
73 * we load the binary where it was linked at (ie, e_entry field in
76 #define KERNEL_LINK_ADDR_PPC32 0xC0000000UL
77 #define KERNEL_LINK_ADDR_PPC64 0xC000000000000000ULL
79 #define INITRD_CHUNKSIZE 0x100000
87 unsigned long memsize;
88 unsigned long filesize;
90 unsigned long load_loc;
94 typedef void (*kernel_entry_t)( void *,
100 /* Imported functions */
101 extern unsigned long reloc_offset(void);
102 extern long flush_icache_range(unsigned long start, unsigned long stop);
104 /* Exported functions */
105 int yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
107 /* Local functions */
108 static int yaboot_main(void);
109 static int is_elf32(loadinfo_t *loadinfo);
110 static int is_elf64(loadinfo_t *loadinfo);
111 static int load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
112 static int load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
113 static void setup_display(void);
115 /* Locals & globals */
118 char bootdevice[BOOTDEVSZ];
119 char bootoncelabel[1024];
121 char bootlastlabel[BOOTLASTSZ] = {0};
122 char fw_nbr_reboots[FW_NBR_REBOOTSZ] = {0};
123 long fw_reboot_cnt = 0;
124 char *password = NULL;
125 struct boot_fspec_t boot;
126 int _machine = _MACH_Pmac;
129 #ifdef CONFIG_COLOR_TEXT
131 /* Color values for text ui */
132 static struct ansi_color_t {
136 } ansi_color_table[] = {
144 { "light-gray", 0, 37 },
145 { "dark-gray", 1, 30 },
146 { "light-blue", 1, 31 },
147 { "light-green", 1, 32 },
148 { "light-cyan", 1, 33 },
149 { "light-red", 1, 34 },
150 { "light-purple", 1, 35 },
156 /* Default colors for text ui */
159 #endif /* CONFIG_COLOR_TEXT */
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
173 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
176 void* malloc_base = NULL;
179 /* Initialize OF interface */
180 prom_init ((prom_entry) r5);
182 prom_print_available();
184 /* Allocate some memory for malloc'ator */
185 malloc_base = prom_claim_chunk_top(MALLOCSIZE, 0);
186 if (malloc_base == (void *)-1) {
187 prom_printf("Can't claim malloc buffer of %d bytes\n",
191 malloc_init(malloc_base, MALLOCSIZE);
192 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
193 malloc_base, MALLOCSIZE);
195 /* A few useless DEBUG_F's */
196 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
197 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
199 /* ask the OF info if we're a chrp or pmac */
200 /* we need to set _machine before calling finish_device_tree */
201 root = prom_finddevice("/");
203 static char model[256];
204 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
205 !strncmp("bplan", model, 5))
206 _machine = _MACH_bplan;
207 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
208 !strncmp("chrp", model, 4))
209 _machine = _MACH_chrp;
210 else if (prom_getprop(root, "compatible", model, 256 ) > 0 &&
211 strstr(model, "ibm,powernv"))
212 _machine = _MACH_chrp;
214 if (prom_getprop(root, "model", model, 256 ) > 0 &&
215 !strncmp(model, "IBM", 3))
216 _machine = _MACH_chrp;
220 DEBUG_F("Running on _machine = %d\n", _machine);
224 result = yaboot_main();
226 /* Get rid of malloc pool */
228 prom_release(malloc_base, MALLOCSIZE);
229 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
239 #ifdef CONFIG_COLOR_TEXT
241 * Validify color for text ui
244 check_color_text_ui(char *color)
247 while(ansi_color_table[i].name) {
248 if (!strcmp(color, ansi_color_table[i].name))
254 #endif /* CONFIG_COLOR_TEXT */
257 void print_message_file(char *filename)
261 char *defdev = boot.dev;
262 int defpart = boot.part;
267 struct boot_file_t file;
268 struct boot_fspec_t msgfile;
270 defdev = cfg_get_strg(0, "device");
273 p = cfg_get_strg(0, "partition");
275 n = simple_strtol(p, &endp, 10);
276 if (endp != p && *endp == 0)
280 strncpy(msgpath, filename, sizeof(msgpath));
281 msgfile = boot; /* Copy all the original paramters */
282 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
283 prom_printf("%s: Unable to parse\n", msgpath);
287 result = open_file(&msgfile, &file);
288 if (result != FILE_ERR_OK) {
289 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
290 prom_perror(result, msgfile.file);
295 msg = malloc(MESSAGE_FILE_MAX + 1);
299 memset(msg, 0, MESSAGE_FILE_MAX + 1);
301 if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
304 prom_printf("%s", msg);
308 file.fs->close(&file);
313 /* Currently, the config file must be at the root of the filesystem.
314 * todo: recognize the full path to myself and use it to load the
315 * config file. Handle the "\\" (blessed system folder)
318 load_config_file(struct boot_fspec_t *fspec)
320 char *conf_file = NULL, *p;
321 struct boot_file_t file;
322 int sz, opened = 0, result = 0;
324 /* Allocate a buffer for the config file */
325 conf_file = malloc(CONFIG_FILE_MAX);
327 prom_printf("Can't alloc config file buffer\n");
332 result = open_file(fspec, &file);
333 if (result != FILE_ERR_OK) {
334 prom_printf("%s:%d,", fspec->dev, fspec->part);
335 prom_perror(result, fspec->file);
336 prom_printf("Can't open config file\n");
342 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
344 prom_printf("Error, can't read config file\n");
347 prom_printf("Config file read, %d bytes\n", sz);
351 file.fs->close(&file);
354 /* Call the parsing code in cfg.c */
355 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
356 prom_printf ("Syntax error or read error config\n");
361 * set the default cf_option to label that has the same MAC addr
362 * it only works if there is a label with the MAC addr on yaboot.conf
364 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
365 /* change the variable bellow to get the MAC dinamicaly */
366 char * macaddr = NULL;
369 macaddr = prom_get_mac(prom_get_netinfo());
370 default_mac = cfg_set_default_by_mac(macaddr);
371 if (default_mac >= 1) {
372 prom_printf("Default label was changed to macaddr label.\n");
376 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
378 /* Now, we do the initialisations stored in the config file */
379 p = cfg_get_strg(0, "init-code");
383 password = cfg_get_strg(0, "password");
385 #ifdef CONFIG_COLOR_TEXT
386 p = cfg_get_strg(0, "fgcolor");
388 DEBUG_F("fgcolor=%s\n", p);
389 fgcolor = check_color_text_ui(p);
391 prom_printf("Invalid fgcolor: \"%s\".\n", p);
394 p = cfg_get_strg(0, "bgcolor");
396 DEBUG_F("bgcolor=%s\n", p);
397 bgcolor = check_color_text_ui(p);
399 prom_printf("Invalid bgcolor: \"%s\".\n", p);
403 sprintf(temp, "%x to background-color", bgcolor);
404 prom_interpret(temp);
411 sprintf(temp, "%x to foreground-color", fgcolor);
412 prom_interpret(temp);
414 #endif /* CONFIG_COLOR_TEXT */
416 p = cfg_get_strg(0, "init-message");
418 prom_printf("%s\n", p);
420 p = cfg_get_strg(0, "message");
422 print_message_file(p);
429 file.fs->close(&file);
438 * Search for config file by MAC address, then by IP address.
439 * Basically copying pxelinux's algorithm.
440 * http://syslinux.zytor.com/pxe.php#config
442 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
444 struct bootp_packet *packet;
446 struct boot_fspec_t fspec = *orig_fspec;
447 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
451 packet = prom_get_netinfo();
456 * First, try to match on mac address with the hardware type
460 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
461 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
465 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
466 strcat(fspec.file, prom_get_mac(packet));
468 rc = load_config_file(&fspec);
473 * Now try to match on IP.
475 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
476 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
478 for (flen = strlen(fspec.file),
479 minlen = strlen(cfgpath); flen > minlen; flen--) {
480 rc = load_config_file(&fspec);
483 /* Chop one digit off the end, try again */
484 fspec.file[flen - 1] = '\0';
488 if (rc) /* modify original only on success */
489 orig_fspec->file = fspec.file;
495 void maintabfunc (void)
499 prom_printf("boot: %s", cbuff);
504 word_split(char **linep, char **paramsp)
519 while (*p != 0 && *p != ' ')
528 make_params(char *label, char *params)
531 static char buffer[2048];
536 p = cfg_get_strg(label, "literal");
548 p = cfg_get_strg(label, "root");
555 if (cfg_get_flag(label, "read-only")) {
559 if (cfg_get_flag(label, "read-write")) {
563 p = cfg_get_strg(label, "ramdisk");
565 strcpy (q, "ramdisk=");
570 p = cfg_get_strg(label, "initrd-size");
572 strcpy (q, "ramdisk_size=");
577 if (cfg_get_flag(label, "novideo")) {
578 strcpy (q, "video=ofonly");
582 p = cfg_get_strg (label, "append");
589 pause_after = cfg_get_flag (label, "pause-after");
590 p = cfg_get_strg(label, "pause-message");
599 void check_password(char *str)
603 prom_printf("\n%s", str);
604 for (i = 0; i < 3; i++) {
605 prom_printf ("\nPassword: ");
607 cmdedit ((void (*)(void)) 0, 1);
609 #ifdef USE_MD5_PASSWORDS
610 if (!strncmp (password, "$1$", 3)) {
611 if (!check_md5_password((unsigned char*)passwdbuff, (unsigned char*)password))
614 else if (!strcmp (password, passwdbuff))
617 if (!strcmp (password, passwdbuff))
619 #endif /* USE_MD5_PASSWORDS */
622 prom_printf ("Incorrect password. Try again.");
625 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
626 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
627 " ||----w |\n || ||\n");
629 prom_interpret("reset-all");
632 int get_params(struct boot_param_t* params)
636 char defdevice_bak[1024];
639 char *imagename = 0, *label;
644 static int first = 1;
645 static char imagepath[1024];
646 static char initrdpath[1024];
647 static char manualinitrd[1024];
648 static int definitrd = 1, hasarg = 0;
651 memset(params, 0, sizeof(*params));
653 params->kernel.part = -1;
654 params->rd.part = -1;
659 if (first && !fw_reboot_cnt) {
661 imagename = bootargs;
662 word_split(&imagename, ¶ms->args);
663 timeout = DEFAULT_TIMEOUT;
665 prom_printf("Default supplied on the command line: %s ", imagename);
667 prom_printf("%s", params->args);
670 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
671 timeout = simple_strtol(q, NULL, 0);
674 /* If this is a reboot due to FW detecting CAS changes then
675 * set timeout to 1. The last kernel booted will be booted
676 * again automatically. It should seem seamless to the user
681 prom_printf("boot: ");
686 end = beg + 100 * timeout;
688 c = prom_nbgetchar();
689 } while (c == -1 && prom_getms() <= end);
693 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
699 if (c != -1 && c != '\n' && c != '\r') {
702 } else if (c >= ' ') {
705 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
708 prom_printf("%s\n", cbuff);
713 if (c == '\n' || c == '\r') {
715 if (bootoncelabel[0] != 0)
716 imagename = bootoncelabel;
717 else if (bootlastlabel[0] != 0) {
718 imagename = bootlastlabel;
719 word_split(&imagename, ¶ms->args);
721 imagename = cfg_get_default();
724 prom_printf("%s", imagename);
726 prom_printf(" %s", params->args);
728 } else if (!singlekey) {
729 cmdedit(maintabfunc, 0);
731 strcpy(given_bootargs, cbuff);
732 given_bootargs_by_user = 1;
734 word_split(&imagename, ¶ms->args);
737 /* initrd setup via cmd console */
738 /* first, check if the user uses it with some label */
739 if (!strncmp(params->args, "initrd=", 7)) {
740 DEBUG_F("params->args: %s\n", params->args);
743 /* after, check if there is the 'initrd=' in the imagename string */
744 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
746 /* return the value of definitrd to 1 */
750 /* args = "initrd=blah" */
761 /* copy the string after the '=' to manualinitrd */
762 strcpy(manualinitrd, args+7);
764 prom_printf("New initrd file specified: %s\n", manualinitrd);
766 prom_printf("ERROR: no initrd specified!\n");
770 /* set imagename with the default values of the config file */
771 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
772 imagename = cfg_get_default();
774 imagename = cfg_get_default();
777 /* chrp gets this wrong, force it -- Cort */
778 if ( useconf && (!imagename || imagename[0] == 0 ))
779 imagename = cfg_get_default();
781 /* write the imagename out so it can be reused on reboot if necessary */
782 strcpy(bootlastlabel, imagename);
783 if (params->args && params->args[0]) {
784 strcat(bootlastlabel, " ");
785 strcat(bootlastlabel, params->args);
787 prom_set_options("boot-last-label", bootlastlabel,
788 strlen(bootlastlabel) + 1);
791 defdevice = boot.dev;
793 strcpy(defdevice_bak,defdevice);
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 "To boot a alternative initrd file rather than specified in the yaboot\n"
848 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
849 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
850 "kernel image. You can, also, specify a different initrd file to any other\n"
851 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
852 "and the specified initrd file will be loaded.\n\n"
853 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
854 "its device, partno and path, on Open Firmware Prompt:\n"
855 "boot conf=device:partno,/path/to/configfile\n."
856 "To reload the config file or load a new one, use the \"conf\" command\n"
857 "on Yaboot's prompt:\n"
858 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
859 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
860 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
865 if (!strcmp (imagename, "halt")) {
867 check_password ("Restricted command.");
871 if (!strcmp (imagename, "bye")) {
873 check_password ("Restricted command.");
879 if (!strncmp (imagename, "conf", 4)) {
881 // imagename = "conf file=blah dev=bleh part=blih"
882 DEBUG_F("Loading user-specified config file: %s\n",imagename);
884 check_password ("Restricted command.");
888 // args= "file=blah dev=bleh part=blih"
889 char *args = params->args;
893 // set a pointer to the first space in args
894 char *space = strchr(args,' ');
898 char temp[1024] = "0";
900 // copy next argument to temp
901 strncpy(temp, args, space-args);
903 // parse temp and set boot arguments
904 if (!strncmp (temp, "file=", 5)){
905 DEBUG_F("conf file: %s\n", temp+5);
906 strcpy(boot.file, temp+5);
907 } else if (!strncmp (temp, "device=", 7)){
908 DEBUG_F("conf device: %s\n", temp+7);
909 strcpy(boot.dev, temp+7);
910 } else if (!strncmp (temp, "partition=", 10)){
911 DEBUG_F("conf partition: %s\n", temp+10);
912 boot.part=simple_strtol(temp+10,NULL,10);
916 // set the pointer to the next space in args;
917 // set the loop control variable
918 if (strlen(space)>1){
919 // Go to the next argument
923 if (strchr(args,' ') == NULL)
924 space = &args[strlen(args)];
926 space = strchr(args,' ');
933 prom_printf("Loading config file...\n");
934 useconf = load_config_file(&boot);
936 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
937 timeout = simple_strtol(q, NULL, 0);
939 prom_printf("Restoring default values.\n");
940 strcpy(boot.file,"");
941 strcpy(boot.dev, defdevice_bak);
946 prom_printf("Current configuration:\n");
947 prom_printf("device: %s\n", boot.dev);
949 prom_printf("partition: auto\n");
951 prom_printf("partition: %d\n", boot.part);
952 if (strlen(boot.file))
953 prom_printf("file: %s\n", boot.file);
955 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
964 if (imagename[0] == '$') {
965 /* forth command string */
967 check_password ("OpenFirmware commands are restricted.");
968 prom_interpret(imagename+1);
972 strncpy(imagepath, imagename, 1024);
974 if (!label && password)
975 check_password ("To boot a custom image you must enter the password.");
977 params->kernel = boot; /* Copy all the original paramters */
978 if (!parse_device_path(imagepath, defdevice, defpart,
979 "/vmlinux", ¶ms->kernel)) {
980 prom_printf("%s: Unable to parse\n", imagepath);
983 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
985 p = cfg_get_strg(label, "initrd");
988 /* check if user seted to use a initrd file from boot console */
989 if (!definitrd && p != manualinitrd) {
990 if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
991 strcpy(initrdpath, "/");
992 strcat(initrdpath, manualinitrd);
994 strncpy(initrdpath, manualinitrd, 1024);
996 strncpy(initrdpath, p, 1024);
998 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
999 params->rd = boot; /* Copy all the original paramters */
1000 if (!parse_device_path(initrdpath, defdevice, defpart,
1001 "/root.bin", ¶ms->rd)) {
1002 prom_printf("%s: Unable to parse\n", imagepath);
1010 /* This is derived from quik core. To be changed to first parse the headers
1011 * doing lazy-loading, and then claim the memory before loading the kernel
1013 * We also need to add initrd support to this whole mecanism
1016 yaboot_text_ui(void)
1018 struct boot_file_t file;
1020 static struct boot_param_t params;
1022 unsigned long initrd_size;
1023 kernel_entry_t kernel_entry;
1025 loadinfo_t loadinfo;
1026 void *initrd_more,*initrd_want;
1027 unsigned long initrd_read;
1028 unsigned int len = INITRD_CHUNKSIZE;
1030 loadinfo.load_loc = 0;
1036 if (get_params(¶ms))
1038 if (!params.kernel.file)
1041 prom_printf("Please wait, loading kernel...\n");
1043 memset(&file, 0, sizeof(file));
1045 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1046 && params.kernel.file[0] != '\\') {
1047 loc=(char*)malloc(strlen(params.kernel.file)+3);
1049 prom_printf ("malloc error\n");
1052 strcpy(loc,boot.file);
1053 strcat(loc,params.kernel.file);
1054 free(params.kernel.file);
1055 params.kernel.file=loc;
1057 result = open_file(¶ms.kernel, &file);
1058 if (result != FILE_ERR_OK) {
1059 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1060 prom_perror(result, params.kernel.file);
1064 /* Read the Elf e_ident, e_type and e_machine fields to
1065 * determine Elf file type
1067 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1068 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1069 file.fs->close(&file);
1070 memset(&file, 0, sizeof(file));
1074 if (is_elf32(&loadinfo)) {
1075 if (!load_elf32(&file, &loadinfo)) {
1076 file.fs->close(&file);
1077 memset(&file, 0, sizeof(file));
1080 prom_printf(" Elf32 kernel loaded...\n");
1081 } else if (is_elf64(&loadinfo)) {
1082 if (!load_elf64(&file, &loadinfo)) {
1083 file.fs->close(&file);
1084 memset(&file, 0, sizeof(file));
1087 prom_printf(" Elf64 kernel loaded...\n");
1089 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1090 file.fs->close(&file);
1091 memset(&file, 0, sizeof(file));
1094 file.fs->close(&file);
1095 memset(&file, 0, sizeof(file));
1097 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1098 * can't tell the size it will be so we claim an arbitrary amount
1101 if (flat_vmlinux && params.rd.file) {
1102 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1103 && params.kernel.file[0] != '\\')
1106 loc=(char*)malloc(strlen(params.rd.file)+3);
1108 prom_printf ("Malloc error\n");
1111 strcpy(loc,boot.file);
1112 strcat(loc,params.rd.file);
1113 free(params.rd.file);
1116 prom_printf("Loading ramdisk...\n");
1117 result = open_file(¶ms.rd, &file);
1118 if (result == FILE_ERR_OK && file.fs->ino_size) {
1119 result = file.fs->ino_size(&file, &len);
1121 if (result != FILE_ERR_OK) {
1122 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1123 prom_perror(result, params.rd.file);
1126 /* We add a bit to the actual size so the loop below
1127 * doesn't think there is more to load.
1131 initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0);
1132 if (initrd_base == (void *)-1) {
1133 prom_printf("Claim failed for initrd memory\n");
1136 initrd_size = file.fs->read(&file, len, initrd_base);
1137 if (initrd_size == 0)
1139 initrd_read = initrd_size;
1140 initrd_more = initrd_base;
1141 while (initrd_read == len ) { /* need to read more? */
1142 initrd_want = (void *)((unsigned long)initrd_more+len);
1143 initrd_more = prom_claim(initrd_want, len, 0);
1144 if (initrd_more != initrd_want) {
1145 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1149 initrd_read = file.fs->read(&file, len, initrd_more);
1150 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1151 initrd_size += initrd_read;
1154 file.fs->close(&file);
1155 memset(&file, 0, sizeof(file));
1158 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1159 initrd_base, initrd_size >> 10);
1161 prom_printf("ramdisk load failed !\n");
1166 DEBUG_F("setting kernel args to: %s\n", params.args);
1167 prom_setargs(params.args);
1168 DEBUG_F("flushing icache...");
1169 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
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 prom_print_available();
1187 /* call the kernel with our stack. */
1188 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1196 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1199 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1201 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1202 unsigned long loadaddr;
1204 /* Read the rest of the Elf header... */
1205 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1206 prom_printf("\nCan't read Elf32 image header\n");
1210 DEBUG_F("Elf32 header:\n");
1211 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1212 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1213 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1214 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1215 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1216 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1217 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1218 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1219 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1220 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1222 loadinfo->entry = e->e_entry;
1224 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1226 prom_printf ("Malloc error\n");
1230 /* Now, we read the section header */
1231 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1232 prom_printf ("seek error\n");
1235 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1236 sizeof(Elf32_Phdr) * e->e_phnum) {
1237 prom_printf ("read error\n");
1241 /* Scan through the program header
1242 * HACK: We must return the _memory size of the kernel image, not the
1243 * file size (because we have to leave room before other boot
1244 * infos. This code works as a side effect of the fact that
1245 * we have one section and vaddr == p_paddr
1247 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1249 for (i = 0; i < e->e_phnum; ++i, ++p) {
1250 if (p->p_type != PT_LOAD || p->p_offset == 0)
1252 if (loadinfo->memsize == 0) {
1253 loadinfo->offset = p->p_offset;
1254 loadinfo->memsize = p->p_memsz;
1255 loadinfo->filesize = p->p_filesz;
1256 loadinfo->load_loc = p->p_vaddr;
1258 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1259 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1263 if (loadinfo->memsize == 0) {
1264 prom_printf("Can't find a loadable segment !\n");
1268 /* leave some room (1Mb) for boot infos */
1269 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1270 /* Claim OF memory */
1271 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1273 /* Determine whether we are trying to boot a vmlinux or some
1274 * other binary image (eg, zImage). We load vmlinux's at
1275 * KERNELADDR and all other binaries at their e_entry value.
1277 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1279 loadaddr = KERNELADDR;
1282 loadaddr = loadinfo->load_loc;
1285 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1286 if (loadinfo->base == (void *)-1) {
1287 prom_printf("Claim error, can't allocate kernel memory\n");
1291 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1292 loadinfo->base, loadinfo->memsize);
1293 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1294 loadaddr, loadinfo->memsize);
1296 /* Load the program segments... */
1298 for (i = 0; i < e->e_phnum; ++i, ++p) {
1299 unsigned long offset;
1300 if (p->p_type != PT_LOAD || p->p_offset == 0)
1303 /* Now, we skip to the image itself */
1304 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1305 prom_printf ("Seek error\n");
1306 prom_release(loadinfo->base, loadinfo->memsize);
1309 offset = p->p_vaddr - loadinfo->load_loc;
1310 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1311 prom_printf ("Read failed\n");
1312 prom_release(loadinfo->base, loadinfo->memsize);
1319 /* Return success at loading the Elf32 kernel */
1329 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1332 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1334 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1335 unsigned long loadaddr;
1337 /* Read the rest of the Elf header... */
1338 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1339 prom_printf("\nCan't read Elf64 image header\n");
1343 DEBUG_F("Elf64 header:\n");
1344 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1345 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1346 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1347 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1348 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1349 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1350 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1351 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1352 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1353 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1355 loadinfo->entry = e->e_entry;
1357 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1359 prom_printf ("Malloc error\n");
1363 /* Now, we read the section header */
1364 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1365 prom_printf ("Seek error\n");
1368 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1369 sizeof(Elf64_Phdr) * e->e_phnum) {
1370 prom_printf ("Read error\n");
1374 /* Scan through the program header
1375 * HACK: We must return the _memory size of the kernel image, not the
1376 * file size (because we have to leave room before other boot
1377 * infos. This code works as a side effect of the fact that
1378 * we have one section and vaddr == p_paddr
1380 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1382 for (i = 0; i < e->e_phnum; ++i, ++p) {
1383 if (p->p_type != PT_LOAD || p->p_offset == 0)
1385 if (loadinfo->memsize == 0) {
1386 loadinfo->offset = p->p_offset;
1387 loadinfo->memsize = p->p_memsz;
1388 loadinfo->filesize = p->p_filesz;
1389 loadinfo->load_loc = p->p_vaddr;
1391 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1392 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1396 if (loadinfo->memsize == 0) {
1397 prom_printf("Can't find a loadable segment !\n");
1401 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1402 /* Claim OF memory */
1403 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1405 /* Determine whether we are trying to boot a vmlinux or some
1406 * other binary image (eg, zImage). We load vmlinux's at
1407 * KERNELADDR and all other binaries at their e_entry value.
1409 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1411 loadaddr = KERNELADDR;
1414 loadaddr = e->e_entry;
1417 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1418 if (loadinfo->base == (void *)-1) {
1419 prom_printf("Claim error, can't allocate kernel memory\n");
1423 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1424 loadinfo->base, loadinfo->memsize);
1425 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1426 loadaddr, loadinfo->memsize);
1428 /* Load the program segments... */
1430 for (i = 0; i < e->e_phnum; ++i, ++p) {
1431 unsigned long offset;
1432 if (p->p_type != PT_LOAD || p->p_offset == 0)
1435 /* Now, we skip to the image itself */
1436 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1437 prom_printf ("Seek error\n");
1438 prom_release(loadinfo->base, loadinfo->memsize);
1441 offset = p->p_vaddr - loadinfo->load_loc;
1442 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1443 prom_printf ("Read failed\n");
1444 prom_release(loadinfo->base, loadinfo->memsize);
1451 /* Return success at loading the Elf64 kernel */
1461 is_elf32(loadinfo_t *loadinfo)
1463 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1465 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1466 e->e_ident[EI_MAG1] == ELFMAG1 &&
1467 e->e_ident[EI_MAG2] == ELFMAG2 &&
1468 e->e_ident[EI_MAG3] == ELFMAG3 &&
1469 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1470 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1471 e->e_type == ET_EXEC &&
1472 e->e_machine == EM_PPC);
1476 is_elf64(loadinfo_t *loadinfo)
1478 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1480 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1481 e->e_ident[EI_MAG1] == ELFMAG1 &&
1482 e->e_ident[EI_MAG2] == ELFMAG2 &&
1483 e->e_ident[EI_MAG3] == ELFMAG3 &&
1484 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1485 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1486 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1487 e->e_machine == EM_PPC64);
1493 #ifdef CONFIG_SET_COLORMAP
1494 static unsigned char default_colors[] = {
1513 prom_handle scrn = PROM_INVALID_HANDLE;
1515 /* Try Apple's mac-boot screen ihandle */
1516 result = (int)call_prom_return("interpret", 1, 2,
1517 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1518 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1520 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1522 /* Hrm... check to see if stdout is a display */
1523 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1524 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1525 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1526 DEBUG_F("got it ! stdout is a screen\n");
1529 /* Else, we try to open the package */
1530 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1531 DEBUG_F("Open screen result: %p\n", scrn);
1535 if (scrn == PROM_INVALID_HANDLE) {
1536 prom_printf("No screen device found !\n");
1540 prom_set_color(scrn, i, default_colors[i*3],
1541 default_colors[i*3+1], default_colors[i*3+2]);
1543 prom_printf("\x1b[1;37m\x1b[2;40m");
1545 for (i=0;i<16; i++) {
1546 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1547 ansi_color_table[i].index,
1548 ansi_color_table[i].value,
1549 ansi_color_table[i].name,
1550 ansi_color_table[i].name);
1551 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1552 ansi_color_table[i].index,
1553 ansi_color_table[i].value+10,
1554 ansi_color_table[i].name,
1555 ansi_color_table[i].name);
1557 prom_printf("\x1b[1;37m\x1b[2;40m");
1558 #endif /* COLOR_TEST */
1564 #endif /* CONFIG_SET_COLORMAP */
1573 char conf_path[1024];
1575 if (_machine == _MACH_Pmac)
1578 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1579 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1580 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1581 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1582 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1583 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1584 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1585 if (fw_reboot_cnt > 0L)
1586 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1588 /* If conf= specified on command line, it overrides
1589 Usage: conf=device:partition,/path/to/conffile
1590 Example: On Open Firmware Prompt, type
1591 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1593 if (!strncmp(bootargs, "conf=", 5)) {
1594 DEBUG_F("Using conf argument in Open Firmware\n");
1595 char *end = strchr(bootargs,' ');
1599 strcpy(bootdevice, bootargs + 5);
1601 DEBUG_F("Using conf=%s\n", bootdevice);
1603 /* Remove conf=xxx from bootargs */
1605 memmove(bootargs, end+1, strlen(end+1)+1);
1609 if (bootdevice[0] == 0) {
1610 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1611 DEBUG_F("boot-device = %s\n", bootdevice);
1613 if (bootdevice[0] == 0) {
1614 prom_printf("Couldn't determine boot device\n");
1618 if (bootoncelabel[0] == 0) {
1619 prom_get_options("boot-once", bootoncelabel,
1620 sizeof(bootoncelabel));
1621 if (bootoncelabel[0] != 0)
1622 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1624 prom_set_options("boot-once", NULL, 0);
1626 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1627 prom_printf("%s: Unable to parse\n", bootdevice);
1630 if (_machine == _MACH_bplan && !conf_given)
1632 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1633 boot.dev, boot.part, boot.file);
1636 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1637 boot.file = "/etc/";
1638 else if (strlen(boot.file)) {
1639 if (!strncmp(boot.file, "\\\\", 2))
1643 p = last = boot.file;
1653 if (strlen(boot.file))
1654 strcat(boot.file, "\\");
1657 strcpy(conf_path, boot.file);
1658 strcat(conf_path, CONFIG_FILE_NAME);
1659 boot.file = conf_path;
1660 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1661 boot.dev, boot.part, boot.file);
1665 * If we're doing a netboot, first look for one which matches our
1668 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1669 prom_printf("Try to netboot\n");
1670 useconf = load_my_config_file(&boot);
1674 useconf = load_config_file(&boot);
1676 prom_printf("Welcome to yaboot version " VERSION "\n");
1677 prom_printf("Enter \"help\" to get some basic usage information\n");
1679 /* I am fed up with lusers using the wrong partition type and
1680 mailing me *when* it breaks */
1682 if (_machine == _MACH_Pmac) {
1683 char *entry = cfg_get_strg(0, "ptypewarning");
1686 warn = strcmp(entry,
1687 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1689 ptype = get_part_type(boot.dev, boot.part);
1690 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1691 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1692 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1700 prom_printf("Bye.\n");
1706 * c-file-style: "k&r"