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
85 unsigned long memsize;
86 unsigned long filesize;
88 unsigned long load_loc;
92 typedef void (*kernel_entry_t)( void *,
98 /* Imported functions */
99 extern unsigned long reloc_offset(void);
100 extern long flush_icache_range(unsigned long start, unsigned long stop);
102 /* Exported functions */
103 int yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
105 /* Local functions */
106 static int yaboot_main(void);
107 static int is_elf32(loadinfo_t *loadinfo);
108 static int is_elf64(loadinfo_t *loadinfo);
109 static int load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
110 static int load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
111 static void setup_display(void);
113 /* Locals & globals */
116 char bootdevice[BOOTDEVSZ];
117 char bootoncelabel[1024];
119 char bootlastlabel[BOOTLASTSZ] = {0};
120 char fw_nbr_reboots[FW_NBR_REBOOTSZ] = {0};
121 long fw_reboot_cnt = 0;
122 char *password = NULL;
123 struct boot_fspec_t boot;
124 int _machine = _MACH_Pmac;
127 #ifdef CONFIG_COLOR_TEXT
129 /* Color values for text ui */
130 static struct ansi_color_t {
134 } ansi_color_table[] = {
142 { "light-gray", 0, 37 },
143 { "dark-gray", 1, 30 },
144 { "light-blue", 1, 31 },
145 { "light-green", 1, 32 },
146 { "light-cyan", 1, 33 },
147 { "light-red", 1, 34 },
148 { "light-purple", 1, 35 },
154 /* Default colors for text ui */
157 #endif /* CONFIG_COLOR_TEXT */
159 static int pause_after;
160 static char *pause_message = "Type go<return> to continue.\n";
161 static char given_bootargs[1024];
162 static int given_bootargs_by_user = 0;
164 extern unsigned char linux_logo_red[];
165 extern unsigned char linux_logo_green[];
166 extern unsigned char linux_logo_blue[];
168 #define DEFAULT_TIMEOUT -1
171 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
174 void* malloc_base = NULL;
177 /* Initialize OF interface */
178 prom_init ((prom_entry) r5);
180 prom_print_available();
182 /* Allocate some memory for malloc'ator */
183 malloc_base = prom_claim_chunk_top(MALLOCSIZE, 0);
184 if (malloc_base == (void *)-1) {
185 prom_printf("Can't claim malloc buffer of %d bytes\n",
189 malloc_init(malloc_base, MALLOCSIZE);
190 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
191 malloc_base, MALLOCSIZE);
193 /* A few useless DEBUG_F's */
194 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
195 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
197 /* ask the OF info if we're a chrp or pmac */
198 /* we need to set _machine before calling finish_device_tree */
199 root = prom_finddevice("/");
201 static char model[256];
202 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
203 !strncmp("bplan", model, 5))
204 _machine = _MACH_bplan;
205 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
206 !strncmp("chrp", model, 4))
207 _machine = _MACH_chrp;
208 else if (prom_getprop(root, "compatible", model, 256 ) > 0 &&
209 strstr(model, "ibm,powernv"))
210 _machine = _MACH_chrp;
212 if (prom_getprop(root, "model", model, 256 ) > 0 &&
213 !strncmp(model, "IBM", 3))
214 _machine = _MACH_chrp;
218 DEBUG_F("Running on _machine = %d\n", _machine);
222 result = yaboot_main();
224 /* Get rid of malloc pool */
226 prom_release(malloc_base, MALLOCSIZE);
227 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
237 #ifdef CONFIG_COLOR_TEXT
239 * Validify color for text ui
242 check_color_text_ui(char *color)
245 while(ansi_color_table[i].name) {
246 if (!strcmp(color, ansi_color_table[i].name))
252 #endif /* CONFIG_COLOR_TEXT */
255 void print_message_file(char *filename)
259 char *defdev = boot.dev;
260 int defpart = boot.part;
265 struct boot_file_t file;
266 struct boot_fspec_t msgfile;
268 defdev = cfg_get_strg(0, "device");
271 p = cfg_get_strg(0, "partition");
273 n = simple_strtol(p, &endp, 10);
274 if (endp != p && *endp == 0)
278 strncpy(msgpath, filename, sizeof(msgpath));
279 msgfile = boot; /* Copy all the original paramters */
280 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
281 prom_printf("%s: Unable to parse\n", msgpath);
285 result = open_file(&msgfile, &file);
286 if (result != FILE_ERR_OK) {
287 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
288 prom_perror(result, msgfile.file);
293 msg = malloc(MESSAGE_FILE_MAX + 1);
297 memset(msg, 0, MESSAGE_FILE_MAX + 1);
299 if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
302 prom_printf("%s", msg);
306 file.fs->close(&file);
311 /* Currently, the config file must be at the root of the filesystem.
312 * todo: recognize the full path to myself and use it to load the
313 * config file. Handle the "\\" (blessed system folder)
316 load_config_file(struct boot_fspec_t *fspec)
318 char *conf_file = NULL, *p;
319 struct boot_file_t file;
320 int sz, opened = 0, result = 0;
322 /* Allocate a buffer for the config file */
323 conf_file = malloc(CONFIG_FILE_MAX);
325 prom_printf("Can't alloc config file buffer\n");
330 result = open_file(fspec, &file);
331 if (result != FILE_ERR_OK) {
332 prom_printf("%s:%d,", fspec->dev, fspec->part);
333 prom_perror(result, fspec->file);
334 prom_printf("Can't open config file\n");
340 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
342 prom_printf("Error, can't read config file\n");
345 prom_printf("Config file read, %d bytes\n", sz);
349 file.fs->close(&file);
352 /* Call the parsing code in cfg.c */
353 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
354 prom_printf ("Syntax error or read error config\n");
359 * set the default cf_option to label that has the same MAC addr
360 * it only works if there is a label with the MAC addr on yaboot.conf
362 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
363 /* change the variable bellow to get the MAC dinamicaly */
364 char * macaddr = NULL;
367 macaddr = prom_get_mac(prom_get_netinfo());
368 default_mac = cfg_set_default_by_mac(macaddr);
369 if (default_mac >= 1) {
370 prom_printf("Default label was changed to macaddr label.\n");
374 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
376 /* Now, we do the initialisations stored in the config file */
377 p = cfg_get_strg(0, "init-code");
381 password = cfg_get_strg(0, "password");
383 #ifdef CONFIG_COLOR_TEXT
384 p = cfg_get_strg(0, "fgcolor");
386 DEBUG_F("fgcolor=%s\n", p);
387 fgcolor = check_color_text_ui(p);
389 prom_printf("Invalid fgcolor: \"%s\".\n", p);
392 p = cfg_get_strg(0, "bgcolor");
394 DEBUG_F("bgcolor=%s\n", p);
395 bgcolor = check_color_text_ui(p);
397 prom_printf("Invalid bgcolor: \"%s\".\n", p);
401 sprintf(temp, "%x to background-color", bgcolor);
402 prom_interpret(temp);
409 sprintf(temp, "%x to foreground-color", fgcolor);
410 prom_interpret(temp);
412 #endif /* CONFIG_COLOR_TEXT */
414 p = cfg_get_strg(0, "init-message");
416 prom_printf("%s\n", p);
418 p = cfg_get_strg(0, "message");
420 print_message_file(p);
427 file.fs->close(&file);
436 * Search for config file by MAC address, then by IP address.
437 * Basically copying pxelinux's algorithm.
438 * http://syslinux.zytor.com/pxe.php#config
440 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
442 struct bootp_packet *packet;
444 struct boot_fspec_t fspec = *orig_fspec;
445 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
449 packet = prom_get_netinfo();
454 * First, try to match on mac address with the hardware type
458 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
459 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
463 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
464 strcat(fspec.file, prom_get_mac(packet));
466 rc = load_config_file(&fspec);
471 * Now try to match on IP.
473 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
474 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
476 for (flen = strlen(fspec.file),
477 minlen = strlen(cfgpath); flen > minlen; flen--) {
478 rc = load_config_file(&fspec);
481 /* Chop one digit off the end, try again */
482 fspec.file[flen - 1] = '\0';
486 if (rc) /* modify original only on success */
487 orig_fspec->file = fspec.file;
493 void maintabfunc (void)
497 prom_printf("boot: %s", cbuff);
502 word_split(char **linep, char **paramsp)
517 while (*p != 0 && *p != ' ')
526 make_params(char *label, char *params)
529 static char buffer[2048];
534 p = cfg_get_strg(label, "literal");
546 p = cfg_get_strg(label, "root");
553 if (cfg_get_flag(label, "read-only")) {
557 if (cfg_get_flag(label, "read-write")) {
561 p = cfg_get_strg(label, "ramdisk");
563 strcpy (q, "ramdisk=");
568 p = cfg_get_strg(label, "initrd-size");
570 strcpy (q, "ramdisk_size=");
575 if (cfg_get_flag(label, "novideo")) {
576 strcpy (q, "video=ofonly");
580 p = cfg_get_strg (label, "append");
587 pause_after = cfg_get_flag (label, "pause-after");
588 p = cfg_get_strg(label, "pause-message");
597 void check_password(char *str)
601 prom_printf("\n%s", str);
602 for (i = 0; i < 3; i++) {
603 prom_printf ("\nPassword: ");
605 cmdedit ((void (*)(void)) 0, 1);
607 #ifdef USE_MD5_PASSWORDS
608 if (!strncmp (password, "$1$", 3)) {
609 if (!check_md5_password((unsigned char*)passwdbuff, (unsigned char*)password))
612 else if (!strcmp (password, passwdbuff))
615 if (!strcmp (password, passwdbuff))
617 #endif /* USE_MD5_PASSWORDS */
620 prom_printf ("Incorrect password. Try again.");
623 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
624 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
625 " ||----w |\n || ||\n");
627 prom_interpret("reset-all");
630 int get_params(struct boot_param_t* params)
634 char defdevice_bak[1024];
637 char *imagename = 0, *label;
642 static int first = 1;
643 static char imagepath[1024];
644 static char initrdpath[1024];
645 static char manualinitrd[1024];
646 static int definitrd = 1, hasarg = 0;
649 memset(params, 0, sizeof(*params));
651 params->kernel.part = -1;
652 params->rd.part = -1;
657 if (first && !fw_reboot_cnt) {
659 imagename = bootargs;
660 word_split(&imagename, ¶ms->args);
661 timeout = DEFAULT_TIMEOUT;
663 prom_printf("Default supplied on the command line: %s ", imagename);
665 prom_printf("%s", params->args);
668 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
669 timeout = simple_strtol(q, NULL, 0);
672 /* If this is a reboot due to FW detecting CAS changes then
673 * set timeout to 1. The last kernel booted will be booted
674 * again automatically. It should seem seamless to the user
679 prom_printf("boot: ");
684 end = beg + 100 * timeout;
686 c = prom_nbgetchar();
687 } while (c == -1 && prom_getms() <= end);
691 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
697 if (c != -1 && c != '\n' && c != '\r') {
700 } else if (c >= ' ') {
703 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
706 prom_printf("%s\n", cbuff);
711 if (c == '\n' || c == '\r') {
713 if (bootoncelabel[0] != 0)
714 imagename = bootoncelabel;
715 else if (bootlastlabel[0] != 0) {
716 imagename = bootlastlabel;
717 word_split(&imagename, ¶ms->args);
719 imagename = cfg_get_default();
722 prom_printf("%s", imagename);
724 prom_printf(" %s", params->args);
726 } else if (!singlekey) {
727 cmdedit(maintabfunc, 0);
729 strcpy(given_bootargs, cbuff);
730 given_bootargs_by_user = 1;
732 word_split(&imagename, ¶ms->args);
735 /* initrd setup via cmd console */
736 /* first, check if the user uses it with some label */
737 if (!strncmp(params->args, "initrd=", 7)) {
738 DEBUG_F("params->args: %s\n", params->args);
741 /* after, check if there is the 'initrd=' in the imagename string */
742 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
744 /* return the value of definitrd to 1 */
748 /* args = "initrd=blah" */
759 /* copy the string after the '=' to manualinitrd */
760 strcpy(manualinitrd, args+7);
762 prom_printf("New initrd file specified: %s\n", manualinitrd);
764 prom_printf("ERROR: no initrd specified!\n");
768 /* set imagename with the default values of the config file */
769 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
770 imagename = cfg_get_default();
772 imagename = cfg_get_default();
775 /* chrp gets this wrong, force it -- Cort */
776 if ( useconf && (!imagename || imagename[0] == 0 ))
777 imagename = cfg_get_default();
779 /* write the imagename out so it can be reused on reboot if necessary */
780 strcpy(bootlastlabel, imagename);
781 if (params->args && params->args[0]) {
782 strcat(bootlastlabel, " ");
783 strcat(bootlastlabel, params->args);
785 prom_set_options("boot-last-label", bootlastlabel,
786 strlen(bootlastlabel) + 1);
789 defdevice = boot.dev;
791 strcpy(defdevice_bak,defdevice);
794 defdevice = cfg_get_strg(0, "device");
795 p = cfg_get_strg(0, "partition");
797 n = simple_strtol(p, &endp, 10);
798 if (endp != p && *endp == 0)
801 p = cfg_get_strg(0, "pause-message");
804 if (cfg_get_flag(0, "restricted"))
806 p = cfg_get_strg(imagename, "image");
810 defdevice = cfg_get_strg(label, "device");
811 if(!defdevice) defdevice=boot.dev;
812 p = cfg_get_strg(label, "partition");
814 n = simple_strtol(p, &endp, 10);
815 if (endp != p && *endp == 0)
818 if (cfg_get_flag(label, "restricted"))
821 if (params->args && password && restricted)
822 check_password ("To specify arguments for this image "
823 "you must enter the password.");
824 else if (password && !restricted)
825 check_password ("This image is restricted.");
827 params->args = make_params(label, params->args);
831 if (!strcmp (imagename, "help")) {
832 /* FIXME: defdevice shouldn't need to be reset all over the place */
833 if(!defdevice) defdevice = boot.dev;
835 "\nPress the tab key for a list of defined images.\n"
836 "The label marked with a \"*\" is is the default image, "
837 "press <return> to boot it.\n\n"
838 "To boot any other label simply type its name and press <return>.\n\n"
839 "To boot a kernel image which is not defined in the yaboot configuration \n"
840 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
841 "\"device:\" is the OpenFirmware device path to the disk the image \n"
842 "resides on, and \"partno\" is the partition number the image resides on.\n"
843 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
844 "device, if you only specify a filename you should not start it with a \",\"\n\n"
845 "To boot a alternative initrd file rather than specified in the yaboot\n"
846 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
847 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
848 "kernel image. You can, also, specify a different initrd file to any other\n"
849 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
850 "and the specified initrd file will be loaded.\n\n"
851 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
852 "its device, partno and path, on Open Firmware Prompt:\n"
853 "boot conf=device:partno,/path/to/configfile\n."
854 "To reload the config file or load a new one, use the \"conf\" command\n"
855 "on Yaboot's prompt:\n"
856 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
857 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
858 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
863 if (!strcmp (imagename, "halt")) {
865 check_password ("Restricted command.");
869 if (!strcmp (imagename, "bye")) {
871 check_password ("Restricted command.");
877 if (!strncmp (imagename, "conf", 4)) {
879 // imagename = "conf file=blah dev=bleh part=blih"
880 DEBUG_F("Loading user-specified config file: %s\n",imagename);
882 check_password ("Restricted command.");
886 // args= "file=blah dev=bleh part=blih"
887 char *args = params->args;
891 // set a pointer to the first space in args
892 char *space = strchr(args,' ');
896 char temp[1024] = "0";
898 // copy next argument to temp
899 strncpy(temp, args, space-args);
901 // parse temp and set boot arguments
902 if (!strncmp (temp, "file=", 5)){
903 DEBUG_F("conf file: %s\n", temp+5);
904 strcpy(boot.file, temp+5);
905 } else if (!strncmp (temp, "device=", 7)){
906 DEBUG_F("conf device: %s\n", temp+7);
907 strcpy(boot.dev, temp+7);
908 } else if (!strncmp (temp, "partition=", 10)){
909 DEBUG_F("conf partition: %s\n", temp+10);
910 boot.part=simple_strtol(temp+10,NULL,10);
914 // set the pointer to the next space in args;
915 // set the loop control variable
916 if (strlen(space)>1){
917 // Go to the next argument
921 if (strchr(args,' ') == NULL)
922 space = &args[strlen(args)];
924 space = strchr(args,' ');
931 prom_printf("Loading config file...\n");
932 useconf = load_config_file(&boot);
934 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
935 timeout = simple_strtol(q, NULL, 0);
937 prom_printf("Restoring default values.\n");
938 strcpy(boot.file,"");
939 strcpy(boot.dev, defdevice_bak);
944 prom_printf("Current configuration:\n");
945 prom_printf("device: %s\n", boot.dev);
947 prom_printf("partition: auto\n");
949 prom_printf("partition: %d\n", boot.part);
950 if (strlen(boot.file))
951 prom_printf("file: %s\n", boot.file);
953 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
962 if (imagename[0] == '$') {
963 /* forth command string */
965 check_password ("OpenFirmware commands are restricted.");
966 prom_interpret(imagename+1);
970 strncpy(imagepath, imagename, 1024);
972 if (!label && password)
973 check_password ("To boot a custom image you must enter the password.");
975 params->kernel = boot; /* Copy all the original paramters */
976 if (!parse_device_path(imagepath, defdevice, defpart,
977 "/vmlinux", ¶ms->kernel)) {
978 prom_printf("%s: Unable to parse\n", imagepath);
981 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
983 p = cfg_get_strg(label, "initrd");
986 /* check if user seted to use a initrd file from boot console */
987 if (!definitrd && p != manualinitrd) {
988 if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
989 strcpy(initrdpath, "/");
990 strcat(initrdpath, manualinitrd);
992 strncpy(initrdpath, manualinitrd, 1024);
994 strncpy(initrdpath, p, 1024);
996 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
997 params->rd = boot; /* Copy all the original paramters */
998 if (!parse_device_path(initrdpath, defdevice, defpart,
999 "/root.bin", ¶ms->rd)) {
1000 prom_printf("%s: Unable to parse\n", imagepath);
1008 /* This is derived from quik core. To be changed to first parse the headers
1009 * doing lazy-loading, and then claim the memory before loading the kernel
1011 * We also need to add initrd support to this whole mecanism
1014 yaboot_text_ui(void)
1016 struct boot_file_t file;
1018 static struct boot_param_t params;
1020 unsigned long initrd_size;
1021 kernel_entry_t kernel_entry;
1023 loadinfo_t loadinfo;
1024 void *initrd_more,*initrd_want;
1025 unsigned long initrd_read;
1027 loadinfo.load_loc = 0;
1033 if (get_params(¶ms))
1035 if (!params.kernel.file)
1038 prom_printf("Please wait, loading kernel...\n");
1040 memset(&file, 0, sizeof(file));
1042 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1043 && params.kernel.file[0] != '\\') {
1044 loc=(char*)malloc(strlen(params.kernel.file)+3);
1046 prom_printf ("malloc error\n");
1049 strcpy(loc,boot.file);
1050 strcat(loc,params.kernel.file);
1051 free(params.kernel.file);
1052 params.kernel.file=loc;
1054 result = open_file(¶ms.kernel, &file);
1055 if (result != FILE_ERR_OK) {
1056 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1057 prom_perror(result, params.kernel.file);
1061 /* Read the Elf e_ident, e_type and e_machine fields to
1062 * determine Elf file type
1064 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1065 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1066 file.fs->close(&file);
1067 memset(&file, 0, sizeof(file));
1071 if (is_elf32(&loadinfo)) {
1072 if (!load_elf32(&file, &loadinfo)) {
1073 file.fs->close(&file);
1074 memset(&file, 0, sizeof(file));
1077 prom_printf(" Elf32 kernel loaded...\n");
1078 } else if (is_elf64(&loadinfo)) {
1079 if (!load_elf64(&file, &loadinfo)) {
1080 file.fs->close(&file);
1081 memset(&file, 0, sizeof(file));
1084 prom_printf(" Elf64 kernel loaded...\n");
1086 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1087 file.fs->close(&file);
1088 memset(&file, 0, sizeof(file));
1091 file.fs->close(&file);
1092 memset(&file, 0, sizeof(file));
1094 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1095 * can't tell the size it will be so we claim an arbitrary amount
1098 if (flat_vmlinux && params.rd.file) {
1099 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1100 && params.kernel.file[0] != '\\')
1103 loc=(char*)malloc(strlen(params.rd.file)+3);
1105 prom_printf ("Malloc error\n");
1108 strcpy(loc,boot.file);
1109 strcat(loc,params.rd.file);
1110 free(params.rd.file);
1113 prom_printf("Loading ramdisk...\n");
1114 result = open_file(¶ms.rd, &file);
1115 if (result != FILE_ERR_OK) {
1116 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1117 prom_perror(result, params.rd.file);
1120 #define INITRD_CHUNKSIZE 0x100000
1121 unsigned int len = INITRD_CHUNKSIZE;
1123 /* We add a bit to the actual size so the loop below doesn't think
1124 * there is more to load.
1126 if (file.fs->ino_size && file.fs->ino_size(&file) > 0)
1127 len = file.fs->ino_size(&file) + 0x1000;
1129 initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0);
1130 if (initrd_base == (void *)-1) {
1131 prom_printf("Claim failed for initrd memory\n");
1134 initrd_size = file.fs->read(&file, len, initrd_base);
1135 if (initrd_size == 0)
1137 initrd_read = initrd_size;
1138 initrd_more = initrd_base;
1139 while (initrd_read == len ) { /* need to read more? */
1140 initrd_want = (void *)((unsigned long)initrd_more+len);
1141 initrd_more = prom_claim(initrd_want, len, 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, len, 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 prom_print_available();
1185 /* call the kernel with our stack. */
1186 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1194 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1197 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1199 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1200 unsigned long loadaddr;
1202 /* Read the rest of the Elf header... */
1203 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1204 prom_printf("\nCan't read Elf32 image header\n");
1208 DEBUG_F("Elf32 header:\n");
1209 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1210 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1211 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1212 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1213 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1214 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1215 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1216 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1217 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1218 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1220 loadinfo->entry = e->e_entry;
1222 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1224 prom_printf ("Malloc error\n");
1228 /* Now, we read the section header */
1229 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1230 prom_printf ("seek error\n");
1233 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1234 sizeof(Elf32_Phdr) * e->e_phnum) {
1235 prom_printf ("read error\n");
1239 /* Scan through the program header
1240 * HACK: We must return the _memory size of the kernel image, not the
1241 * file size (because we have to leave room before other boot
1242 * infos. This code works as a side effect of the fact that
1243 * we have one section and vaddr == p_paddr
1245 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1247 for (i = 0; i < e->e_phnum; ++i, ++p) {
1248 if (p->p_type != PT_LOAD || p->p_offset == 0)
1250 if (loadinfo->memsize == 0) {
1251 loadinfo->offset = p->p_offset;
1252 loadinfo->memsize = p->p_memsz;
1253 loadinfo->filesize = p->p_filesz;
1254 loadinfo->load_loc = p->p_vaddr;
1256 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1257 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1261 if (loadinfo->memsize == 0) {
1262 prom_printf("Can't find a loadable segment !\n");
1266 /* leave some room (1Mb) for boot infos */
1267 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1268 /* Claim OF memory */
1269 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1271 /* Determine whether we are trying to boot a vmlinux or some
1272 * other binary image (eg, zImage). We load vmlinux's at
1273 * KERNELADDR and all other binaries at their e_entry value.
1275 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1277 loadaddr = KERNELADDR;
1280 loadaddr = loadinfo->load_loc;
1283 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1284 if (loadinfo->base == (void *)-1) {
1285 prom_printf("Claim error, can't allocate kernel memory\n");
1289 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1290 loadinfo->base, loadinfo->memsize);
1291 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1292 loadaddr, loadinfo->memsize);
1294 /* Load the program segments... */
1296 for (i = 0; i < e->e_phnum; ++i, ++p) {
1297 unsigned long offset;
1298 if (p->p_type != PT_LOAD || p->p_offset == 0)
1301 /* Now, we skip to the image itself */
1302 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1303 prom_printf ("Seek error\n");
1304 prom_release(loadinfo->base, loadinfo->memsize);
1307 offset = p->p_vaddr - loadinfo->load_loc;
1308 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1309 prom_printf ("Read failed\n");
1310 prom_release(loadinfo->base, loadinfo->memsize);
1317 /* Return success at loading the Elf32 kernel */
1327 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1330 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1332 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1333 unsigned long loadaddr;
1335 /* Read the rest of the Elf header... */
1336 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1337 prom_printf("\nCan't read Elf64 image header\n");
1341 DEBUG_F("Elf64 header:\n");
1342 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1343 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1344 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1345 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1346 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1347 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1348 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1349 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1350 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1351 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1353 loadinfo->entry = e->e_entry;
1355 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1357 prom_printf ("Malloc error\n");
1361 /* Now, we read the section header */
1362 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1363 prom_printf ("Seek error\n");
1366 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1367 sizeof(Elf64_Phdr) * e->e_phnum) {
1368 prom_printf ("Read error\n");
1372 /* Scan through the program header
1373 * HACK: We must return the _memory size of the kernel image, not the
1374 * file size (because we have to leave room before other boot
1375 * infos. This code works as a side effect of the fact that
1376 * we have one section and vaddr == p_paddr
1378 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1380 for (i = 0; i < e->e_phnum; ++i, ++p) {
1381 if (p->p_type != PT_LOAD || p->p_offset == 0)
1383 if (loadinfo->memsize == 0) {
1384 loadinfo->offset = p->p_offset;
1385 loadinfo->memsize = p->p_memsz;
1386 loadinfo->filesize = p->p_filesz;
1387 loadinfo->load_loc = p->p_vaddr;
1389 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1390 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1394 if (loadinfo->memsize == 0) {
1395 prom_printf("Can't find a loadable segment !\n");
1399 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1400 /* Claim OF memory */
1401 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1403 /* Determine whether we are trying to boot a vmlinux or some
1404 * other binary image (eg, zImage). We load vmlinux's at
1405 * KERNELADDR and all other binaries at their e_entry value.
1407 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1409 loadaddr = KERNELADDR;
1412 loadaddr = e->e_entry;
1415 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1416 if (loadinfo->base == (void *)-1) {
1417 prom_printf("Claim error, can't allocate kernel memory\n");
1421 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1422 loadinfo->base, loadinfo->memsize);
1423 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1424 loadaddr, loadinfo->memsize);
1426 /* Load the program segments... */
1428 for (i = 0; i < e->e_phnum; ++i, ++p) {
1429 unsigned long offset;
1430 if (p->p_type != PT_LOAD || p->p_offset == 0)
1433 /* Now, we skip to the image itself */
1434 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1435 prom_printf ("Seek error\n");
1436 prom_release(loadinfo->base, loadinfo->memsize);
1439 offset = p->p_vaddr - loadinfo->load_loc;
1440 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1441 prom_printf ("Read failed\n");
1442 prom_release(loadinfo->base, loadinfo->memsize);
1449 /* Return success at loading the Elf64 kernel */
1459 is_elf32(loadinfo_t *loadinfo)
1461 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1463 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1464 e->e_ident[EI_MAG1] == ELFMAG1 &&
1465 e->e_ident[EI_MAG2] == ELFMAG2 &&
1466 e->e_ident[EI_MAG3] == ELFMAG3 &&
1467 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1468 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1469 e->e_type == ET_EXEC &&
1470 e->e_machine == EM_PPC);
1474 is_elf64(loadinfo_t *loadinfo)
1476 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1478 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1479 e->e_ident[EI_MAG1] == ELFMAG1 &&
1480 e->e_ident[EI_MAG2] == ELFMAG2 &&
1481 e->e_ident[EI_MAG3] == ELFMAG3 &&
1482 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1483 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1484 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1485 e->e_machine == EM_PPC64);
1491 #ifdef CONFIG_SET_COLORMAP
1492 static unsigned char default_colors[] = {
1511 prom_handle scrn = PROM_INVALID_HANDLE;
1513 /* Try Apple's mac-boot screen ihandle */
1514 result = (int)call_prom_return("interpret", 1, 2,
1515 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1516 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1518 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1520 /* Hrm... check to see if stdout is a display */
1521 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1522 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1523 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1524 DEBUG_F("got it ! stdout is a screen\n");
1527 /* Else, we try to open the package */
1528 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1529 DEBUG_F("Open screen result: %p\n", scrn);
1533 if (scrn == PROM_INVALID_HANDLE) {
1534 prom_printf("No screen device found !\n");
1538 prom_set_color(scrn, i, default_colors[i*3],
1539 default_colors[i*3+1], default_colors[i*3+2]);
1541 prom_printf("\x1b[1;37m\x1b[2;40m");
1543 for (i=0;i<16; i++) {
1544 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1545 ansi_color_table[i].index,
1546 ansi_color_table[i].value,
1547 ansi_color_table[i].name,
1548 ansi_color_table[i].name);
1549 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1550 ansi_color_table[i].index,
1551 ansi_color_table[i].value+10,
1552 ansi_color_table[i].name,
1553 ansi_color_table[i].name);
1555 prom_printf("\x1b[1;37m\x1b[2;40m");
1556 #endif /* COLOR_TEST */
1562 #endif /* CONFIG_SET_COLORMAP */
1571 char conf_path[1024];
1573 if (_machine == _MACH_Pmac)
1576 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1577 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1578 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1579 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1580 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1581 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1582 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1583 if (fw_reboot_cnt > 0L)
1584 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1586 /* If conf= specified on command line, it overrides
1587 Usage: conf=device:partition,/path/to/conffile
1588 Example: On Open Firmware Prompt, type
1589 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1591 if (!strncmp(bootargs, "conf=", 5)) {
1592 DEBUG_F("Using conf argument in Open Firmware\n");
1593 char *end = strchr(bootargs,' ');
1597 strcpy(bootdevice, bootargs + 5);
1599 DEBUG_F("Using conf=%s\n", bootdevice);
1601 /* Remove conf=xxx from bootargs */
1603 memmove(bootargs, end+1, strlen(end+1)+1);
1607 if (bootdevice[0] == 0) {
1608 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1609 DEBUG_F("boot-device = %s\n", bootdevice);
1611 if (bootdevice[0] == 0) {
1612 prom_printf("Couldn't determine boot device\n");
1616 if (bootoncelabel[0] == 0) {
1617 prom_get_options("boot-once", bootoncelabel,
1618 sizeof(bootoncelabel));
1619 if (bootoncelabel[0] != 0)
1620 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1622 prom_set_options("boot-once", NULL, 0);
1624 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1625 prom_printf("%s: Unable to parse\n", bootdevice);
1628 if (_machine == _MACH_bplan && !conf_given)
1630 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1631 boot.dev, boot.part, boot.file);
1634 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1635 boot.file = "/etc/";
1636 else if (strlen(boot.file)) {
1637 if (!strncmp(boot.file, "\\\\", 2))
1641 p = last = boot.file;
1651 if (strlen(boot.file))
1652 strcat(boot.file, "\\");
1655 strcpy(conf_path, boot.file);
1656 strcat(conf_path, CONFIG_FILE_NAME);
1657 boot.file = conf_path;
1658 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1659 boot.dev, boot.part, boot.file);
1663 * If we're doing a netboot, first look for one which matches our
1666 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1667 prom_printf("Try to netboot\n");
1668 useconf = load_my_config_file(&boot);
1672 useconf = load_config_file(&boot);
1674 prom_printf("Welcome to yaboot version " VERSION "\n");
1675 prom_printf("Enter \"help\" to get some basic usage information\n");
1677 /* I am fed up with lusers using the wrong partition type and
1678 mailing me *when* it breaks */
1680 if (_machine == _MACH_Pmac) {
1681 char *entry = cfg_get_strg(0, "ptypewarning");
1684 warn = strcmp(entry,
1685 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1687 ptype = get_part_type(boot.dev, boot.part);
1688 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1689 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1690 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1698 prom_printf("Bye.\n");
1704 * c-file-style: "k&r"