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;
177 static struct first_info *quik_fip = NULL;
180 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
183 void* malloc_base = NULL;
187 /* OF seems to do it, but I'm not very confident */
188 memset(&__bss_start, 0, &_end - &__bss_start);
190 /* Check for quik first stage bootloader (but I don't think we are
191 * compatible with it anyway, I'll look into backporting to older OF
194 if (r5 == 0xdeadbeef) {
196 quik_fip = (struct first_info *)r4;
199 /* Initialize OF interface */
200 prom_init ((prom_entry) r5);
202 /* Allocate some memory for malloc'ator */
203 for (addr = MALLOCADDR; addr <= MALLOCADDR * 16 ;addr+=0x100000) {
204 malloc_base = prom_claim((void *)addr, MALLOCSIZE, 0);
205 if (malloc_base != (void *)-1) break;
207 if (malloc_base == (void *)-1) {
208 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
209 MALLOCSIZE, MALLOCADDR);
212 malloc_init(malloc_base, MALLOCSIZE);
213 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
214 malloc_base, MALLOCSIZE);
216 /* A few useless DEBUG_F's */
217 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
218 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
219 DEBUG_F("test_data : %d (should be 0)\n", test_data);
220 DEBUG_F("&test_data : %p\n", &test_data);
221 DEBUG_F("&test_bss : %p\n", &test_bss);
222 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
224 /* ask the OF info if we're a chrp or pmac */
225 /* we need to set _machine before calling finish_device_tree */
226 root = prom_finddevice("/");
228 static char model[256];
229 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
230 !strncmp("bplan", model, 5))
231 _machine = _MACH_bplan;
232 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
233 !strncmp("chrp", model, 4))
234 _machine = _MACH_chrp;
236 if (prom_getprop(root, "model", model, 256 ) > 0 &&
237 !strncmp(model, "IBM", 3))
238 _machine = _MACH_chrp;
242 DEBUG_F("Running on _machine = %d\n", _machine);
246 result = yaboot_main();
248 /* Get rid of malloc pool */
250 prom_release(malloc_base, MALLOCSIZE);
251 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
261 #ifdef CONFIG_COLOR_TEXT
263 * Validify color for text ui
266 check_color_text_ui(char *color)
269 while(ansi_color_table[i].name) {
270 if (!strcmp(color, ansi_color_table[i].name))
276 #endif /* CONFIG_COLOR_TEXT */
279 void print_message_file(char *filename)
283 char *defdev = boot.dev;
284 int defpart = boot.part;
289 struct boot_file_t file;
290 struct boot_fspec_t msgfile;
292 defdev = cfg_get_strg(0, "device");
295 p = cfg_get_strg(0, "partition");
297 n = simple_strtol(p, &endp, 10);
298 if (endp != p && *endp == 0)
302 strncpy(msgpath, filename, sizeof(msgpath));
303 msgfile = boot; /* Copy all the original paramters */
304 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
305 prom_printf("%s: Unable to parse\n", msgpath);
309 result = open_file(&msgfile, &file);
310 if (result != FILE_ERR_OK) {
311 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
312 prom_perror(result, msgfile.file);
321 memset(msg, 0, 2001);
323 if (file.fs->read(&file, 2000, msg) <= 0)
326 prom_printf("%s", msg);
330 file.fs->close(&file);
335 /* Currently, the config file must be at the root of the filesystem.
336 * todo: recognize the full path to myself and use it to load the
337 * config file. Handle the "\\" (blessed system folder)
340 load_config_file(struct boot_fspec_t *fspec)
342 char *conf_file = NULL, *p;
343 struct boot_file_t file;
344 int sz, opened = 0, result = 0;
346 /* Allocate a buffer for the config file */
347 conf_file = malloc(CONFIG_FILE_MAX);
349 prom_printf("Can't alloc config file buffer\n");
354 result = open_file(fspec, &file);
355 if (result != FILE_ERR_OK) {
356 prom_printf("%s:%d,", fspec->dev, fspec->part);
357 prom_perror(result, fspec->file);
358 prom_printf("Can't open config file\n");
364 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
366 prom_printf("Error, can't read config file\n");
369 prom_printf("Config file read, %d bytes\n", sz);
373 file.fs->close(&file);
376 /* Call the parsing code in cfg.c */
377 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
378 prom_printf ("Syntax error or read error config\n");
383 * set the default cf_option to label that has the same MAC addr
384 * it only works if there is a label with the MAC addr on yaboot.conf
386 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
387 /* change the variable bellow to get the MAC dinamicaly */
388 char * macaddr = NULL;
391 macaddr = prom_get_mac(prom_get_netinfo());
392 default_mac = cfg_set_default_by_mac(macaddr);
393 if (default_mac >= 1) {
394 prom_printf("Default label was changed to macaddr label.\n");
398 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
400 /* Now, we do the initialisations stored in the config file */
401 p = cfg_get_strg(0, "init-code");
405 password = cfg_get_strg(0, "password");
407 #ifdef CONFIG_COLOR_TEXT
408 p = cfg_get_strg(0, "fgcolor");
410 DEBUG_F("fgcolor=%s\n", p);
411 fgcolor = check_color_text_ui(p);
413 prom_printf("Invalid fgcolor: \"%s\".\n", p);
416 p = cfg_get_strg(0, "bgcolor");
418 DEBUG_F("bgcolor=%s\n", p);
419 bgcolor = check_color_text_ui(p);
421 prom_printf("Invalid bgcolor: \"%s\".\n", p);
425 sprintf(temp, "%x to background-color", bgcolor);
426 prom_interpret(temp);
433 sprintf(temp, "%x to foreground-color", fgcolor);
434 prom_interpret(temp);
436 #endif /* CONFIG_COLOR_TEXT */
438 p = cfg_get_strg(0, "init-message");
440 prom_printf("%s\n", p);
442 p = cfg_get_strg(0, "message");
444 print_message_file(p);
451 file.fs->close(&file);
460 * Search for config file by MAC address, then by IP address.
461 * Basically copying pxelinux's algorithm.
462 * http://syslinux.zytor.com/pxe.php#config
464 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
466 struct bootp_packet *packet;
468 struct boot_fspec_t fspec = *orig_fspec;
469 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
473 packet = prom_get_netinfo();
478 * First, try to match on mac address with the hardware type
482 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
483 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
487 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
488 strcat(fspec.file, prom_get_mac(packet));
490 rc = load_config_file(&fspec);
495 * Now try to match on IP.
497 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
498 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
500 for (flen = strlen(fspec.file),
501 minlen = strlen(cfgpath); flen > minlen; flen--) {
502 rc = load_config_file(&fspec);
505 /* Chop one digit off the end, try again */
506 fspec.file[flen - 1] = '\0';
510 if (rc) /* modify original only on success */
511 orig_fspec->file = fspec.file;
517 void maintabfunc (void)
521 prom_printf("boot: %s", cbuff);
526 word_split(char **linep, char **paramsp)
541 while (*p != 0 && *p != ' ')
550 make_params(char *label, char *params)
553 static char buffer[2048];
558 p = cfg_get_strg(label, "literal");
570 p = cfg_get_strg(label, "root");
577 if (cfg_get_flag(label, "read-only")) {
581 if (cfg_get_flag(label, "read-write")) {
585 p = cfg_get_strg(label, "ramdisk");
587 strcpy (q, "ramdisk=");
592 p = cfg_get_strg(label, "initrd-size");
594 strcpy (q, "ramdisk_size=");
599 if (cfg_get_flag(label, "novideo")) {
600 strcpy (q, "video=ofonly");
604 p = cfg_get_strg (label, "append");
611 pause_after = cfg_get_flag (label, "pause-after");
612 p = cfg_get_strg(label, "pause-message");
621 void check_password(char *str)
625 prom_printf("\n%s", str);
626 for (i = 0; i < 3; i++) {
627 prom_printf ("\nPassword: ");
629 cmdedit ((void (*)(void)) 0, 1);
631 #ifdef USE_MD5_PASSWORDS
632 if (!strncmp (password, "$1$", 3)) {
633 if (!check_md5_password(passwdbuff, password))
636 else if (!strcmp (password, passwdbuff))
639 if (!strcmp (password, passwdbuff))
641 #endif /* USE_MD5_PASSWORDS */
644 prom_printf ("Incorrect password. Try again.");
647 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
648 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
649 " ||----w |\n || ||\n");
651 prom_interpret("reset-all");
654 int get_params(struct boot_param_t* params)
658 char defdevice_bak[1024];
661 char *imagename = 0, *label;
666 static int first = 1;
667 static char imagepath[1024];
668 static char initrdpath[1024];
669 static char manualinitrd[1024];
670 static int definitrd = 1, hasarg = 0;
673 memset(params, 0, sizeof(*params));
675 params->kernel.part = -1;
676 params->rd.part = -1;
681 if (first && !fw_reboot_cnt) {
683 imagename = bootargs;
684 word_split(&imagename, ¶ms->args);
685 timeout = DEFAULT_TIMEOUT;
687 prom_printf("Default supplied on the command line: %s ", imagename);
689 prom_printf("%s", params->args);
692 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
693 timeout = simple_strtol(q, NULL, 0);
696 /* If this is a reboot due to FW detecting CAS changes then
697 * set timeout to 1. The last kernel booted will be booted
698 * again automatically. It should seem seamless to the user
703 prom_printf("boot: ");
708 end = beg + 100 * timeout;
710 c = prom_nbgetchar();
711 } while (c == -1 && prom_getms() <= end);
715 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
721 if (c != -1 && c != '\n' && c != '\r') {
724 } else if (c >= ' ') {
727 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
730 prom_printf("%s\n", cbuff);
735 if (c == '\n' || c == '\r') {
737 if (bootoncelabel[0] != 0)
738 imagename = bootoncelabel;
739 else if (bootlastlabel[0] != 0)
740 imagename = bootlastlabel;
742 imagename = cfg_get_default();
745 prom_printf("%s", imagename);
747 prom_printf(" %s", params->args);
749 } else if (!singlekey) {
750 cmdedit(maintabfunc, 0);
752 strcpy(given_bootargs, cbuff);
753 given_bootargs_by_user = 1;
755 word_split(&imagename, ¶ms->args);
758 /* initrd setup via cmd console */
759 /* first, check if the user uses it with some label */
760 if (!strncmp(params->args, "initrd=", 7)) {
761 DEBUG_F("params->args: %s\n", params->args);
764 /* after, check if there is the 'initrd=' in the imagename string */
765 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
767 /* return the value of definitrd to 1 */
771 /* args = "initrd=blah" */
782 /* copy the string after the '=' to manualinitrd */
783 strcpy(manualinitrd, args+7);
785 prom_printf("New initrd file specified: %s\n", manualinitrd);
787 prom_printf("ERROR: no initrd specified!\n");
791 /* set imagename with the default values of the config file */
792 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
793 imagename = cfg_get_default();
795 imagename = cfg_get_default();
798 /* chrp gets this wrong, force it -- Cort */
799 if ( useconf && (!imagename || imagename[0] == 0 ))
800 imagename = cfg_get_default();
802 /* write the imagename out so it can be reused on reboot if necessary */
803 prom_set_options("boot-last-label", imagename, strlen(imagename));
806 defdevice = boot.dev;
808 strcpy(defdevice_bak,defdevice);
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 "To boot a alternative initrd file rather than specified in the yaboot\n"
863 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
864 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
865 "kernel image. You can, also, specify a different initrd file to any other\n"
866 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
867 "and the specified initrd file will be loaded.\n\n"
868 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
869 "its device, partno and path, on Open Firmware Prompt:\n"
870 "boot conf=device:partno,/path/to/configfile\n."
871 "To reload the config file or load a new one, use the \"conf\" command\n"
872 "on Yaboot's prompt:\n"
873 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
874 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
875 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
880 if (!strcmp (imagename, "halt")) {
882 check_password ("Restricted command.");
886 if (!strcmp (imagename, "bye")) {
888 check_password ("Restricted command.");
894 if (!strncmp (imagename, "conf", 4)) {
896 // imagename = "conf file=blah dev=bleh part=blih"
897 DEBUG_F("Loading user-specified config file: %s\n",imagename);
899 check_password ("Restricted command.");
903 // args= "file=blah dev=bleh part=blih"
904 char *args = params->args;
908 // set a pointer to the first space in args
909 char *space = strchr(args,' ');
913 char temp[1024] = "0";
915 // copy next argument to temp
916 strncpy(temp, args, space-args);
918 // parse temp and set boot arguments
919 if (!strncmp (temp, "file=", 5)){
920 DEBUG_F("conf file: %s\n", temp+5);
921 strcpy(boot.file, temp+5);
922 } else if (!strncmp (temp, "device=", 7)){
923 DEBUG_F("conf device: %s\n", temp+7);
924 strcpy(boot.dev, temp+7);
925 } else if (!strncmp (temp, "partition=", 10)){
926 DEBUG_F("conf partition: %s\n", temp+10);
927 boot.part=simple_strtol(temp+10,NULL,10);
931 // set the pointer to the next space in args;
932 // set the loop control variable
933 if (strlen(space)>1){
934 // Go to the next argument
938 if (strchr(args,' ') == NULL)
939 space = &args[strlen(args)];
941 space = strchr(args,' ');
948 prom_printf("Loading config file...\n");
949 useconf = load_config_file(&boot);
951 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
952 timeout = simple_strtol(q, NULL, 0);
954 prom_printf("Restoring default values.\n");
955 strcpy(boot.file,"");
956 strcpy(boot.dev, defdevice_bak);
961 prom_printf("Current configuration:\n");
962 prom_printf("device: %s\n", boot.dev);
964 prom_printf("partition: auto\n");
966 prom_printf("partition: %d\n", boot.part);
967 if (strlen(boot.file))
968 prom_printf("file: %s\n", boot.file);
970 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
979 if (imagename[0] == '$') {
980 /* forth command string */
982 check_password ("OpenFirmware commands are restricted.");
983 prom_interpret(imagename+1);
987 strncpy(imagepath, imagename, 1024);
989 if (!label && password)
990 check_password ("To boot a custom image you must enter the password.");
992 params->kernel = boot; /* Copy all the original paramters */
993 if (!parse_device_path(imagepath, defdevice, defpart,
994 "/vmlinux", ¶ms->kernel)) {
995 prom_printf("%s: Unable to parse\n", imagepath);
998 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
1000 p = cfg_get_strg(label, "initrd");
1003 /* check if user seted to use a initrd file from boot console */
1004 if (!definitrd && p != manualinitrd) {
1005 if (manualinitrd[0] != "/" && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
1006 strcpy(initrdpath, "/");
1007 strcat(initrdpath, manualinitrd);
1009 strncpy(initrdpath, manualinitrd, 1024);
1011 strncpy(initrdpath, p, 1024);
1013 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
1014 params->rd = boot; /* Copy all the original paramters */
1015 if (!parse_device_path(initrdpath, defdevice, defpart,
1016 "/root.bin", ¶ms->rd)) {
1017 prom_printf("%s: Unable to parse\n", imagepath);
1025 /* This is derived from quik core. To be changed to first parse the headers
1026 * doing lazy-loading, and then claim the memory before loading the kernel
1028 * We also need to add initrd support to this whole mecanism
1031 yaboot_text_ui(void)
1033 #define MAX_HEADERS 32
1035 struct boot_file_t file;
1037 static struct boot_param_t params;
1039 unsigned long initrd_size;
1040 kernel_entry_t kernel_entry;
1042 loadinfo_t loadinfo;
1043 void *initrd_more,*initrd_want;
1044 unsigned long initrd_read;
1046 loadinfo.load_loc = 0;
1052 if (get_params(¶ms))
1054 if (!params.kernel.file)
1057 prom_printf("Please wait, loading kernel...\n");
1059 memset(&file, 0, sizeof(file));
1061 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1062 && params.kernel.file[0] != '\\') {
1063 loc=(char*)malloc(strlen(params.kernel.file)+3);
1065 prom_printf ("malloc error\n");
1068 strcpy(loc,boot.file);
1069 strcat(loc,params.kernel.file);
1070 free(params.kernel.file);
1071 params.kernel.file=loc;
1073 result = open_file(¶ms.kernel, &file);
1074 if (result != FILE_ERR_OK) {
1075 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1076 prom_perror(result, params.kernel.file);
1080 /* Read the Elf e_ident, e_type and e_machine fields to
1081 * determine Elf file type
1083 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1084 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1085 file.fs->close(&file);
1086 memset(&file, 0, sizeof(file));
1090 if (is_elf32(&loadinfo)) {
1091 if (!load_elf32(&file, &loadinfo)) {
1092 file.fs->close(&file);
1093 memset(&file, 0, sizeof(file));
1096 prom_printf(" Elf32 kernel loaded...\n");
1097 } else if (is_elf64(&loadinfo)) {
1098 if (!load_elf64(&file, &loadinfo)) {
1099 file.fs->close(&file);
1100 memset(&file, 0, sizeof(file));
1103 prom_printf(" Elf64 kernel loaded...\n");
1105 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1106 file.fs->close(&file);
1107 memset(&file, 0, sizeof(file));
1110 file.fs->close(&file);
1111 memset(&file, 0, sizeof(file));
1113 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1114 * can't tell the size it will be so we claim an arbitrary amount
1117 if (flat_vmlinux && params.rd.file) {
1118 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1119 && params.kernel.file[0] != '\\')
1122 loc=(char*)malloc(strlen(params.rd.file)+3);
1124 prom_printf ("Malloc error\n");
1127 strcpy(loc,boot.file);
1128 strcat(loc,params.rd.file);
1129 free(params.rd.file);
1132 prom_printf("Loading ramdisk...\n");
1133 result = open_file(¶ms.rd, &file);
1134 if (result != FILE_ERR_OK) {
1135 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1136 prom_perror(result, params.rd.file);
1139 #define INITRD_CHUNKSIZE 0x100000
1140 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1141 if (initrd_base == (void *)-1) {
1142 prom_printf("Claim failed for initrd memory\n");
1145 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1146 if (initrd_size == 0)
1148 initrd_read = initrd_size;
1149 initrd_more = initrd_base;
1150 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1151 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1152 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1153 if (initrd_more != initrd_want) {
1154 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1158 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1159 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1160 initrd_size += initrd_read;
1163 file.fs->close(&file);
1164 memset(&file, 0, sizeof(file));
1167 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1168 initrd_base, initrd_size >> 10);
1170 prom_printf("ramdisk load failed !\n");
1175 DEBUG_F("setting kernel args to: %s\n", params.args);
1176 prom_setargs(params.args);
1177 DEBUG_F("flushing icache...");
1178 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1181 /* compute the kernel's entry point. */
1182 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1184 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1185 DEBUG_F("kernel: arg1 = %p,\n"
1186 " arg2 = 0x%08lx,\n"
1190 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1192 DEBUG_F("Entering kernel...\n");
1194 /* call the kernel with our stack. */
1195 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1203 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1206 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1208 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1209 unsigned long loadaddr;
1211 /* Read the rest of the Elf header... */
1212 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1213 prom_printf("\nCan't read Elf32 image header\n");
1217 DEBUG_F("Elf32 header:\n");
1218 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1219 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1220 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1221 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1222 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1223 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1224 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1225 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1226 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1227 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1229 loadinfo->entry = e->e_entry;
1231 if (e->e_phnum > MAX_HEADERS) {
1232 prom_printf ("Can only load kernels with one program header\n");
1236 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1238 prom_printf ("Malloc error\n");
1242 /* Now, we read the section header */
1243 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1244 prom_printf ("seek error\n");
1247 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1248 sizeof(Elf32_Phdr) * e->e_phnum) {
1249 prom_printf ("read error\n");
1253 /* Scan through the program header
1254 * HACK: We must return the _memory size of the kernel image, not the
1255 * file size (because we have to leave room before other boot
1256 * infos. This code works as a side effect of the fact that
1257 * we have one section and vaddr == p_paddr
1259 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1261 for (i = 0; i < e->e_phnum; ++i, ++p) {
1262 if (p->p_type != PT_LOAD || p->p_offset == 0)
1264 if (loadinfo->memsize == 0) {
1265 loadinfo->offset = p->p_offset;
1266 loadinfo->memsize = p->p_memsz;
1267 loadinfo->filesize = p->p_filesz;
1268 loadinfo->load_loc = p->p_vaddr;
1270 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1271 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1275 if (loadinfo->memsize == 0) {
1276 prom_printf("Can't find a loadable segment !\n");
1280 /* leave some room (1Mb) for boot infos */
1281 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1282 /* Claim OF memory */
1283 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1285 /* Determine whether we are trying to boot a vmlinux or some
1286 * other binary image (eg, zImage). We load vmlinux's at
1287 * KERNELADDR and all other binaries at their e_entry value.
1289 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1291 loadaddr = KERNELADDR;
1294 loadaddr = loadinfo->load_loc;
1297 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1298 if (loadinfo->base == (void *)-1) {
1299 prom_printf("Claim error, can't allocate kernel memory\n");
1303 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1304 loadinfo->base, loadinfo->memsize);
1305 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1306 loadaddr, loadinfo->memsize);
1308 /* Load the program segments... */
1310 for (i = 0; i < e->e_phnum; ++i, ++p) {
1311 unsigned long offset;
1312 if (p->p_type != PT_LOAD || p->p_offset == 0)
1315 /* Now, we skip to the image itself */
1316 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1317 prom_printf ("Seek error\n");
1318 prom_release(loadinfo->base, loadinfo->memsize);
1321 offset = p->p_vaddr - loadinfo->load_loc;
1322 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1323 prom_printf ("Read failed\n");
1324 prom_release(loadinfo->base, loadinfo->memsize);
1331 /* Return success at loading the Elf32 kernel */
1341 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1344 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1346 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1347 unsigned long loadaddr;
1349 /* Read the rest of the Elf header... */
1350 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1351 prom_printf("\nCan't read Elf64 image header\n");
1355 DEBUG_F("Elf64 header:\n");
1356 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1357 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1358 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1359 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1360 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1361 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1362 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1363 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1364 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1365 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1367 loadinfo->entry = e->e_entry;
1369 if (e->e_phnum > MAX_HEADERS) {
1370 prom_printf ("Can only load kernels with one program header\n");
1374 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1376 prom_printf ("Malloc error\n");
1380 /* Now, we read the section header */
1381 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1382 prom_printf ("Seek error\n");
1385 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1386 sizeof(Elf64_Phdr) * e->e_phnum) {
1387 prom_printf ("Read error\n");
1391 /* Scan through the program header
1392 * HACK: We must return the _memory size of the kernel image, not the
1393 * file size (because we have to leave room before other boot
1394 * infos. This code works as a side effect of the fact that
1395 * we have one section and vaddr == p_paddr
1397 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1399 for (i = 0; i < e->e_phnum; ++i, ++p) {
1400 if (p->p_type != PT_LOAD || p->p_offset == 0)
1402 if (loadinfo->memsize == 0) {
1403 loadinfo->offset = p->p_offset;
1404 loadinfo->memsize = p->p_memsz;
1405 loadinfo->filesize = p->p_filesz;
1406 loadinfo->load_loc = p->p_vaddr;
1408 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1409 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1413 if (loadinfo->memsize == 0) {
1414 prom_printf("Can't find a loadable segment !\n");
1418 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1419 /* Claim OF memory */
1420 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1422 /* Determine whether we are trying to boot a vmlinux or some
1423 * other binary image (eg, zImage). We load vmlinux's at
1424 * KERNELADDR and all other binaries at their e_entry value.
1426 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1428 loadaddr = KERNELADDR;
1431 loadaddr = e->e_entry;
1434 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1435 if (loadinfo->base == (void *)-1) {
1436 prom_printf("Claim error, can't allocate kernel memory\n");
1440 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1441 loadinfo->base, loadinfo->memsize);
1442 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1443 loadaddr, loadinfo->memsize);
1445 /* Load the program segments... */
1447 for (i = 0; i < e->e_phnum; ++i, ++p) {
1448 unsigned long offset;
1449 if (p->p_type != PT_LOAD || p->p_offset == 0)
1452 /* Now, we skip to the image itself */
1453 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1454 prom_printf ("Seek error\n");
1455 prom_release(loadinfo->base, loadinfo->memsize);
1458 offset = p->p_vaddr - loadinfo->load_loc;
1459 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1460 prom_printf ("Read failed\n");
1461 prom_release(loadinfo->base, loadinfo->memsize);
1468 /* Return success at loading the Elf64 kernel */
1478 is_elf32(loadinfo_t *loadinfo)
1480 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1482 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1483 e->e_ident[EI_MAG1] == ELFMAG1 &&
1484 e->e_ident[EI_MAG2] == ELFMAG2 &&
1485 e->e_ident[EI_MAG3] == ELFMAG3 &&
1486 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1487 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1488 e->e_type == ET_EXEC &&
1489 e->e_machine == EM_PPC);
1493 is_elf64(loadinfo_t *loadinfo)
1495 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1497 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1498 e->e_ident[EI_MAG1] == ELFMAG1 &&
1499 e->e_ident[EI_MAG2] == ELFMAG2 &&
1500 e->e_ident[EI_MAG3] == ELFMAG3 &&
1501 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1502 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1503 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1504 e->e_machine == EM_PPC64);
1510 #ifdef CONFIG_SET_COLORMAP
1511 static unsigned char default_colors[] = {
1530 prom_handle scrn = PROM_INVALID_HANDLE;
1532 /* Try Apple's mac-boot screen ihandle */
1533 result = (int)call_prom_return("interpret", 1, 2,
1534 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1535 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1537 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1539 /* Hrm... check to see if stdout is a display */
1540 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1541 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1542 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1543 DEBUG_F("got it ! stdout is a screen\n");
1546 /* Else, we try to open the package */
1547 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1548 DEBUG_F("Open screen result: %p\n", scrn);
1552 if (scrn == PROM_INVALID_HANDLE) {
1553 prom_printf("No screen device found !\n");
1557 prom_set_color(scrn, i, default_colors[i*3],
1558 default_colors[i*3+1], default_colors[i*3+2]);
1560 prom_printf("\x1b[1;37m\x1b[2;40m");
1562 for (i=0;i<16; i++) {
1563 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1564 ansi_color_table[i].index,
1565 ansi_color_table[i].value,
1566 ansi_color_table[i].name,
1567 ansi_color_table[i].name);
1568 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1569 ansi_color_table[i].index,
1570 ansi_color_table[i].value+10,
1571 ansi_color_table[i].name,
1572 ansi_color_table[i].name);
1574 prom_printf("\x1b[1;37m\x1b[2;40m");
1575 #endif /* COLOR_TEST */
1581 #endif /* CONFIG_SET_COLORMAP */
1590 char conf_path[1024];
1592 if (_machine == _MACH_Pmac)
1595 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1596 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1597 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1598 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1599 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1600 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1601 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1602 if (fw_reboot_cnt > 0L)
1603 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1605 /* If conf= specified on command line, it overrides
1606 Usage: conf=device:partition,/path/to/conffile
1607 Example: On Open Firmware Prompt, type
1608 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1610 if (!strncmp(bootargs, "conf=", 5)) {
1611 DEBUG_F("Using conf argument in Open Firmware\n");
1612 char *end = strchr(bootargs,' ');
1616 strcpy(bootdevice, bootargs + 5);
1618 DEBUG_F("Using conf=%s\n", bootdevice);
1620 /* Remove conf=xxx from bootargs */
1622 memmove(bootargs, end+1, strlen(end+1)+1);
1626 if (bootdevice[0] == 0) {
1627 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1628 DEBUG_F("boot-device = %s\n", bootdevice);
1630 if (bootdevice[0] == 0) {
1631 prom_printf("Couldn't determine boot device\n");
1635 if (bootoncelabel[0] == 0) {
1636 prom_get_options("boot-once", bootoncelabel,
1637 sizeof(bootoncelabel));
1638 if (bootoncelabel[0] != 0)
1639 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1641 prom_set_options("boot-once", NULL, 0);
1643 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1644 prom_printf("%s: Unable to parse\n", bootdevice);
1647 if (_machine == _MACH_bplan && !conf_given)
1649 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1650 boot.dev, boot.part, boot.file);
1653 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1654 boot.file = "/etc/";
1655 else if (strlen(boot.file)) {
1656 if (!strncmp(boot.file, "\\\\", 2))
1660 p = last = boot.file;
1670 if (strlen(boot.file))
1671 strcat(boot.file, "\\");
1674 strcpy(conf_path, boot.file);
1675 strcat(conf_path, CONFIG_FILE_NAME);
1676 boot.file = conf_path;
1677 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1678 boot.dev, boot.part, boot.file);
1682 * If we're doing a netboot, first look for one which matches our
1685 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1686 prom_printf("Try to netboot\n");
1687 useconf = load_my_config_file(&boot);
1691 useconf = load_config_file(&boot);
1693 prom_printf("Welcome to yaboot version " VERSION "\n");
1694 prom_printf("Enter \"help\" to get some basic usage information\n");
1696 /* I am fed up with lusers using the wrong partition type and
1697 mailing me *when* it breaks */
1699 if (_machine == _MACH_Pmac) {
1700 char *entry = cfg_get_strg(0, "ptypewarning");
1703 warn = strcmp(entry,
1704 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1706 ptype = get_part_type(boot.dev, boot.part);
1707 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1708 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1709 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1717 prom_printf("Bye.\n");
1723 * c-file-style: "k&r"