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;
209 if (prom_getprop(root, "model", model, 256 ) > 0 &&
210 !strncmp(model, "IBM", 3))
211 _machine = _MACH_chrp;
215 DEBUG_F("Running on _machine = %d\n", _machine);
219 result = yaboot_main();
221 /* Get rid of malloc pool */
223 prom_release(malloc_base, MALLOCSIZE);
224 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
234 #ifdef CONFIG_COLOR_TEXT
236 * Validify color for text ui
239 check_color_text_ui(char *color)
242 while(ansi_color_table[i].name) {
243 if (!strcmp(color, ansi_color_table[i].name))
249 #endif /* CONFIG_COLOR_TEXT */
252 void print_message_file(char *filename)
256 char *defdev = boot.dev;
257 int defpart = boot.part;
262 struct boot_file_t file;
263 struct boot_fspec_t msgfile;
265 defdev = cfg_get_strg(0, "device");
268 p = cfg_get_strg(0, "partition");
270 n = simple_strtol(p, &endp, 10);
271 if (endp != p && *endp == 0)
275 strncpy(msgpath, filename, sizeof(msgpath));
276 msgfile = boot; /* Copy all the original paramters */
277 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
278 prom_printf("%s: Unable to parse\n", msgpath);
282 result = open_file(&msgfile, &file);
283 if (result != FILE_ERR_OK) {
284 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
285 prom_perror(result, msgfile.file);
290 msg = malloc(MESSAGE_FILE_MAX + 1);
294 memset(msg, 0, MESSAGE_FILE_MAX + 1);
296 if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
299 prom_printf("%s", msg);
303 file.fs->close(&file);
308 /* Currently, the config file must be at the root of the filesystem.
309 * todo: recognize the full path to myself and use it to load the
310 * config file. Handle the "\\" (blessed system folder)
313 load_config_file(struct boot_fspec_t *fspec)
315 char *conf_file = NULL, *p;
316 struct boot_file_t file;
317 int sz, opened = 0, result = 0;
319 /* Allocate a buffer for the config file */
320 conf_file = malloc(CONFIG_FILE_MAX);
322 prom_printf("Can't alloc config file buffer\n");
327 result = open_file(fspec, &file);
328 if (result != FILE_ERR_OK) {
329 prom_printf("%s:%d,", fspec->dev, fspec->part);
330 prom_perror(result, fspec->file);
331 prom_printf("Can't open config file\n");
337 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
339 prom_printf("Error, can't read config file\n");
342 prom_printf("Config file read, %d bytes\n", sz);
346 file.fs->close(&file);
349 /* Call the parsing code in cfg.c */
350 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
351 prom_printf ("Syntax error or read error config\n");
356 * set the default cf_option to label that has the same MAC addr
357 * it only works if there is a label with the MAC addr on yaboot.conf
359 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
360 /* change the variable bellow to get the MAC dinamicaly */
361 char * macaddr = NULL;
364 macaddr = prom_get_mac(prom_get_netinfo());
365 default_mac = cfg_set_default_by_mac(macaddr);
366 if (default_mac >= 1) {
367 prom_printf("Default label was changed to macaddr label.\n");
371 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
373 /* Now, we do the initialisations stored in the config file */
374 p = cfg_get_strg(0, "init-code");
378 password = cfg_get_strg(0, "password");
380 #ifdef CONFIG_COLOR_TEXT
381 p = cfg_get_strg(0, "fgcolor");
383 DEBUG_F("fgcolor=%s\n", p);
384 fgcolor = check_color_text_ui(p);
386 prom_printf("Invalid fgcolor: \"%s\".\n", p);
389 p = cfg_get_strg(0, "bgcolor");
391 DEBUG_F("bgcolor=%s\n", p);
392 bgcolor = check_color_text_ui(p);
394 prom_printf("Invalid bgcolor: \"%s\".\n", p);
398 sprintf(temp, "%x to background-color", bgcolor);
399 prom_interpret(temp);
406 sprintf(temp, "%x to foreground-color", fgcolor);
407 prom_interpret(temp);
409 #endif /* CONFIG_COLOR_TEXT */
411 p = cfg_get_strg(0, "init-message");
413 prom_printf("%s\n", p);
415 p = cfg_get_strg(0, "message");
417 print_message_file(p);
424 file.fs->close(&file);
433 * Search for config file by MAC address, then by IP address.
434 * Basically copying pxelinux's algorithm.
435 * http://syslinux.zytor.com/pxe.php#config
437 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
439 struct bootp_packet *packet;
441 struct boot_fspec_t fspec = *orig_fspec;
442 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
446 packet = prom_get_netinfo();
451 * First, try to match on mac address with the hardware type
455 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
456 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
460 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
461 strcat(fspec.file, prom_get_mac(packet));
463 rc = load_config_file(&fspec);
468 * Now try to match on IP.
470 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
471 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
473 for (flen = strlen(fspec.file),
474 minlen = strlen(cfgpath); flen > minlen; flen--) {
475 rc = load_config_file(&fspec);
478 /* Chop one digit off the end, try again */
479 fspec.file[flen - 1] = '\0';
483 if (rc) /* modify original only on success */
484 orig_fspec->file = fspec.file;
490 void maintabfunc (void)
494 prom_printf("boot: %s", cbuff);
499 word_split(char **linep, char **paramsp)
514 while (*p != 0 && *p != ' ')
523 make_params(char *label, char *params)
526 static char buffer[2048];
531 p = cfg_get_strg(label, "literal");
543 p = cfg_get_strg(label, "root");
550 if (cfg_get_flag(label, "read-only")) {
554 if (cfg_get_flag(label, "read-write")) {
558 p = cfg_get_strg(label, "ramdisk");
560 strcpy (q, "ramdisk=");
565 p = cfg_get_strg(label, "initrd-size");
567 strcpy (q, "ramdisk_size=");
572 if (cfg_get_flag(label, "novideo")) {
573 strcpy (q, "video=ofonly");
577 p = cfg_get_strg (label, "append");
584 pause_after = cfg_get_flag (label, "pause-after");
585 p = cfg_get_strg(label, "pause-message");
594 void check_password(char *str)
598 prom_printf("\n%s", str);
599 for (i = 0; i < 3; i++) {
600 prom_printf ("\nPassword: ");
602 cmdedit ((void (*)(void)) 0, 1);
604 #ifdef USE_MD5_PASSWORDS
605 if (!strncmp (password, "$1$", 3)) {
606 if (!check_md5_password((unsigned char*)passwdbuff, (unsigned char*)password))
609 else if (!strcmp (password, passwdbuff))
612 if (!strcmp (password, passwdbuff))
614 #endif /* USE_MD5_PASSWORDS */
617 prom_printf ("Incorrect password. Try again.");
620 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
621 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
622 " ||----w |\n || ||\n");
624 prom_interpret("reset-all");
627 int get_params(struct boot_param_t* params)
631 char defdevice_bak[1024];
634 char *imagename = 0, *label;
639 static int first = 1;
640 static char imagepath[1024];
641 static char initrdpath[1024];
642 static char manualinitrd[1024];
643 static int definitrd = 1, hasarg = 0;
646 memset(params, 0, sizeof(*params));
648 params->kernel.part = -1;
649 params->rd.part = -1;
654 if (first && !fw_reboot_cnt) {
656 imagename = bootargs;
657 word_split(&imagename, ¶ms->args);
658 timeout = DEFAULT_TIMEOUT;
660 prom_printf("Default supplied on the command line: %s ", imagename);
662 prom_printf("%s", params->args);
665 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
666 timeout = simple_strtol(q, NULL, 0);
669 /* If this is a reboot due to FW detecting CAS changes then
670 * set timeout to 1. The last kernel booted will be booted
671 * again automatically. It should seem seamless to the user
676 prom_printf("boot: ");
681 end = beg + 100 * timeout;
683 c = prom_nbgetchar();
684 } while (c == -1 && prom_getms() <= end);
688 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
694 if (c != -1 && c != '\n' && c != '\r') {
697 } else if (c >= ' ') {
700 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
703 prom_printf("%s\n", cbuff);
708 if (c == '\n' || c == '\r') {
710 if (bootoncelabel[0] != 0)
711 imagename = bootoncelabel;
712 else if (bootlastlabel[0] != 0) {
713 imagename = bootlastlabel;
714 word_split(&imagename, ¶ms->args);
716 imagename = cfg_get_default();
719 prom_printf("%s", imagename);
721 prom_printf(" %s", params->args);
723 } else if (!singlekey) {
724 cmdedit(maintabfunc, 0);
726 strcpy(given_bootargs, cbuff);
727 given_bootargs_by_user = 1;
729 word_split(&imagename, ¶ms->args);
732 /* initrd setup via cmd console */
733 /* first, check if the user uses it with some label */
734 if (!strncmp(params->args, "initrd=", 7)) {
735 DEBUG_F("params->args: %s\n", params->args);
738 /* after, check if there is the 'initrd=' in the imagename string */
739 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
741 /* return the value of definitrd to 1 */
745 /* args = "initrd=blah" */
756 /* copy the string after the '=' to manualinitrd */
757 strcpy(manualinitrd, args+7);
759 prom_printf("New initrd file specified: %s\n", manualinitrd);
761 prom_printf("ERROR: no initrd specified!\n");
765 /* set imagename with the default values of the config file */
766 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
767 imagename = cfg_get_default();
769 imagename = cfg_get_default();
772 /* chrp gets this wrong, force it -- Cort */
773 if ( useconf && (!imagename || imagename[0] == 0 ))
774 imagename = cfg_get_default();
776 /* write the imagename out so it can be reused on reboot if necessary */
777 strcpy(bootlastlabel, imagename);
778 if (params->args && params->args[0]) {
779 strcat(bootlastlabel, " ");
780 strcat(bootlastlabel, params->args);
782 prom_set_options("boot-last-label", bootlastlabel,
783 strlen(bootlastlabel) + 1);
786 defdevice = boot.dev;
788 strcpy(defdevice_bak,defdevice);
791 defdevice = cfg_get_strg(0, "device");
792 p = cfg_get_strg(0, "partition");
794 n = simple_strtol(p, &endp, 10);
795 if (endp != p && *endp == 0)
798 p = cfg_get_strg(0, "pause-message");
801 if (cfg_get_flag(0, "restricted"))
803 p = cfg_get_strg(imagename, "image");
807 defdevice = cfg_get_strg(label, "device");
808 if(!defdevice) defdevice=boot.dev;
809 p = cfg_get_strg(label, "partition");
811 n = simple_strtol(p, &endp, 10);
812 if (endp != p && *endp == 0)
815 if (cfg_get_flag(label, "restricted"))
818 if (params->args && password && restricted)
819 check_password ("To specify arguments for this image "
820 "you must enter the password.");
821 else if (password && !restricted)
822 check_password ("This image is restricted.");
824 params->args = make_params(label, params->args);
828 if (!strcmp (imagename, "help")) {
829 /* FIXME: defdevice shouldn't need to be reset all over the place */
830 if(!defdevice) defdevice = boot.dev;
832 "\nPress the tab key for a list of defined images.\n"
833 "The label marked with a \"*\" is is the default image, "
834 "press <return> to boot it.\n\n"
835 "To boot any other label simply type its name and press <return>.\n\n"
836 "To boot a kernel image which is not defined in the yaboot configuration \n"
837 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
838 "\"device:\" is the OpenFirmware device path to the disk the image \n"
839 "resides on, and \"partno\" is the partition number the image resides on.\n"
840 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
841 "device, if you only specify a filename you should not start it with a \",\"\n\n"
842 "To boot a alternative initrd file rather than specified in the yaboot\n"
843 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
844 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
845 "kernel image. You can, also, specify a different initrd file to any other\n"
846 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
847 "and the specified initrd file will be loaded.\n\n"
848 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
849 "its device, partno and path, on Open Firmware Prompt:\n"
850 "boot conf=device:partno,/path/to/configfile\n."
851 "To reload the config file or load a new one, use the \"conf\" command\n"
852 "on Yaboot's prompt:\n"
853 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
854 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
855 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
860 if (!strcmp (imagename, "halt")) {
862 check_password ("Restricted command.");
866 if (!strcmp (imagename, "bye")) {
868 check_password ("Restricted command.");
874 if (!strncmp (imagename, "conf", 4)) {
876 // imagename = "conf file=blah dev=bleh part=blih"
877 DEBUG_F("Loading user-specified config file: %s\n",imagename);
879 check_password ("Restricted command.");
883 // args= "file=blah dev=bleh part=blih"
884 char *args = params->args;
888 // set a pointer to the first space in args
889 char *space = strchr(args,' ');
893 char temp[1024] = "0";
895 // copy next argument to temp
896 strncpy(temp, args, space-args);
898 // parse temp and set boot arguments
899 if (!strncmp (temp, "file=", 5)){
900 DEBUG_F("conf file: %s\n", temp+5);
901 strcpy(boot.file, temp+5);
902 } else if (!strncmp (temp, "device=", 7)){
903 DEBUG_F("conf device: %s\n", temp+7);
904 strcpy(boot.dev, temp+7);
905 } else if (!strncmp (temp, "partition=", 10)){
906 DEBUG_F("conf partition: %s\n", temp+10);
907 boot.part=simple_strtol(temp+10,NULL,10);
911 // set the pointer to the next space in args;
912 // set the loop control variable
913 if (strlen(space)>1){
914 // Go to the next argument
918 if (strchr(args,' ') == NULL)
919 space = &args[strlen(args)];
921 space = strchr(args,' ');
928 prom_printf("Loading config file...\n");
929 useconf = load_config_file(&boot);
931 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
932 timeout = simple_strtol(q, NULL, 0);
934 prom_printf("Restoring default values.\n");
935 strcpy(boot.file,"");
936 strcpy(boot.dev, defdevice_bak);
941 prom_printf("Current configuration:\n");
942 prom_printf("device: %s\n", boot.dev);
944 prom_printf("partition: auto\n");
946 prom_printf("partition: %d\n", boot.part);
947 if (strlen(boot.file))
948 prom_printf("file: %s\n", boot.file);
950 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
959 if (imagename[0] == '$') {
960 /* forth command string */
962 check_password ("OpenFirmware commands are restricted.");
963 prom_interpret(imagename+1);
967 strncpy(imagepath, imagename, 1024);
969 if (!label && password)
970 check_password ("To boot a custom image you must enter the password.");
972 params->kernel = boot; /* Copy all the original paramters */
973 if (!parse_device_path(imagepath, defdevice, defpart,
974 "/vmlinux", ¶ms->kernel)) {
975 prom_printf("%s: Unable to parse\n", imagepath);
978 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
980 p = cfg_get_strg(label, "initrd");
983 /* check if user seted to use a initrd file from boot console */
984 if (!definitrd && p != manualinitrd) {
985 if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
986 strcpy(initrdpath, "/");
987 strcat(initrdpath, manualinitrd);
989 strncpy(initrdpath, manualinitrd, 1024);
991 strncpy(initrdpath, p, 1024);
993 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
994 params->rd = boot; /* Copy all the original paramters */
995 if (!parse_device_path(initrdpath, defdevice, defpart,
996 "/root.bin", ¶ms->rd)) {
997 prom_printf("%s: Unable to parse\n", imagepath);
1005 /* This is derived from quik core. To be changed to first parse the headers
1006 * doing lazy-loading, and then claim the memory before loading the kernel
1008 * We also need to add initrd support to this whole mecanism
1011 yaboot_text_ui(void)
1013 struct boot_file_t file;
1015 static struct boot_param_t params;
1017 unsigned long initrd_size;
1018 kernel_entry_t kernel_entry;
1020 loadinfo_t loadinfo;
1021 void *initrd_more,*initrd_want;
1022 unsigned long initrd_read;
1024 loadinfo.load_loc = 0;
1030 if (get_params(¶ms))
1032 if (!params.kernel.file)
1035 prom_printf("Please wait, loading kernel...\n");
1037 memset(&file, 0, sizeof(file));
1039 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1040 && params.kernel.file[0] != '\\') {
1041 loc=(char*)malloc(strlen(params.kernel.file)+3);
1043 prom_printf ("malloc error\n");
1046 strcpy(loc,boot.file);
1047 strcat(loc,params.kernel.file);
1048 free(params.kernel.file);
1049 params.kernel.file=loc;
1051 result = open_file(¶ms.kernel, &file);
1052 if (result != FILE_ERR_OK) {
1053 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1054 prom_perror(result, params.kernel.file);
1058 /* Read the Elf e_ident, e_type and e_machine fields to
1059 * determine Elf file type
1061 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1062 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1063 file.fs->close(&file);
1064 memset(&file, 0, sizeof(file));
1068 if (is_elf32(&loadinfo)) {
1069 if (!load_elf32(&file, &loadinfo)) {
1070 file.fs->close(&file);
1071 memset(&file, 0, sizeof(file));
1074 prom_printf(" Elf32 kernel loaded...\n");
1075 } else if (is_elf64(&loadinfo)) {
1076 if (!load_elf64(&file, &loadinfo)) {
1077 file.fs->close(&file);
1078 memset(&file, 0, sizeof(file));
1081 prom_printf(" Elf64 kernel loaded...\n");
1083 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1084 file.fs->close(&file);
1085 memset(&file, 0, sizeof(file));
1088 file.fs->close(&file);
1089 memset(&file, 0, sizeof(file));
1091 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1092 * can't tell the size it will be so we claim an arbitrary amount
1095 if (flat_vmlinux && params.rd.file) {
1096 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1097 && params.kernel.file[0] != '\\')
1100 loc=(char*)malloc(strlen(params.rd.file)+3);
1102 prom_printf ("Malloc error\n");
1105 strcpy(loc,boot.file);
1106 strcat(loc,params.rd.file);
1107 free(params.rd.file);
1110 prom_printf("Loading ramdisk...\n");
1111 result = open_file(¶ms.rd, &file);
1112 if (result != FILE_ERR_OK) {
1113 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1114 prom_perror(result, params.rd.file);
1117 #define INITRD_CHUNKSIZE 0x100000
1118 unsigned int len = INITRD_CHUNKSIZE;
1120 /* We add a bit to the actual size so the loop below doesn't think
1121 * there is more to load.
1123 if (file.fs->ino_size && file.fs->ino_size(&file) > 0)
1124 len = file.fs->ino_size(&file) + 0x1000;
1126 initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0);
1127 if (initrd_base == (void *)-1) {
1128 prom_printf("Claim failed for initrd memory\n");
1131 initrd_size = file.fs->read(&file, len, initrd_base);
1132 if (initrd_size == 0)
1134 initrd_read = initrd_size;
1135 initrd_more = initrd_base;
1136 while (initrd_read == len ) { /* need to read more? */
1137 initrd_want = (void *)((unsigned long)initrd_more+len);
1138 initrd_more = prom_claim(initrd_want, len, 0);
1139 if (initrd_more != initrd_want) {
1140 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1144 initrd_read = file.fs->read(&file, len, initrd_more);
1145 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1146 initrd_size += initrd_read;
1149 file.fs->close(&file);
1150 memset(&file, 0, sizeof(file));
1153 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1154 initrd_base, initrd_size >> 10);
1156 prom_printf("ramdisk load failed !\n");
1161 DEBUG_F("setting kernel args to: %s\n", params.args);
1162 prom_setargs(params.args);
1163 DEBUG_F("flushing icache...");
1164 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1167 /* compute the kernel's entry point. */
1168 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1170 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1171 DEBUG_F("kernel: arg1 = %p,\n"
1172 " arg2 = 0x%08lx,\n"
1176 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1178 DEBUG_F("Entering kernel...\n");
1180 prom_print_available();
1182 /* call the kernel with our stack. */
1183 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1191 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1194 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1196 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1197 unsigned long loadaddr;
1199 /* Read the rest of the Elf header... */
1200 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1201 prom_printf("\nCan't read Elf32 image header\n");
1205 DEBUG_F("Elf32 header:\n");
1206 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1207 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1208 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1209 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1210 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1211 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1212 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1213 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1214 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1215 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1217 loadinfo->entry = e->e_entry;
1219 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1221 prom_printf ("Malloc error\n");
1225 /* Now, we read the section header */
1226 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1227 prom_printf ("seek error\n");
1230 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1231 sizeof(Elf32_Phdr) * e->e_phnum) {
1232 prom_printf ("read error\n");
1236 /* Scan through the program header
1237 * HACK: We must return the _memory size of the kernel image, not the
1238 * file size (because we have to leave room before other boot
1239 * infos. This code works as a side effect of the fact that
1240 * we have one section and vaddr == p_paddr
1242 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1244 for (i = 0; i < e->e_phnum; ++i, ++p) {
1245 if (p->p_type != PT_LOAD || p->p_offset == 0)
1247 if (loadinfo->memsize == 0) {
1248 loadinfo->offset = p->p_offset;
1249 loadinfo->memsize = p->p_memsz;
1250 loadinfo->filesize = p->p_filesz;
1251 loadinfo->load_loc = p->p_vaddr;
1253 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1254 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1258 if (loadinfo->memsize == 0) {
1259 prom_printf("Can't find a loadable segment !\n");
1263 /* leave some room (1Mb) for boot infos */
1264 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1265 /* Claim OF memory */
1266 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1268 /* Determine whether we are trying to boot a vmlinux or some
1269 * other binary image (eg, zImage). We load vmlinux's at
1270 * KERNELADDR and all other binaries at their e_entry value.
1272 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1274 loadaddr = KERNELADDR;
1277 loadaddr = loadinfo->load_loc;
1280 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1281 if (loadinfo->base == (void *)-1) {
1282 prom_printf("Claim error, can't allocate kernel memory\n");
1286 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1287 loadinfo->base, loadinfo->memsize);
1288 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1289 loadaddr, loadinfo->memsize);
1291 /* Load the program segments... */
1293 for (i = 0; i < e->e_phnum; ++i, ++p) {
1294 unsigned long offset;
1295 if (p->p_type != PT_LOAD || p->p_offset == 0)
1298 /* Now, we skip to the image itself */
1299 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1300 prom_printf ("Seek error\n");
1301 prom_release(loadinfo->base, loadinfo->memsize);
1304 offset = p->p_vaddr - loadinfo->load_loc;
1305 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1306 prom_printf ("Read failed\n");
1307 prom_release(loadinfo->base, loadinfo->memsize);
1314 /* Return success at loading the Elf32 kernel */
1324 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1327 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1329 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1330 unsigned long loadaddr;
1332 /* Read the rest of the Elf header... */
1333 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1334 prom_printf("\nCan't read Elf64 image header\n");
1338 DEBUG_F("Elf64 header:\n");
1339 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1340 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1341 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1342 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1343 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1344 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1345 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1346 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1347 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1348 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1350 loadinfo->entry = e->e_entry;
1352 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1354 prom_printf ("Malloc error\n");
1358 /* Now, we read the section header */
1359 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1360 prom_printf ("Seek error\n");
1363 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1364 sizeof(Elf64_Phdr) * e->e_phnum) {
1365 prom_printf ("Read error\n");
1369 /* Scan through the program header
1370 * HACK: We must return the _memory size of the kernel image, not the
1371 * file size (because we have to leave room before other boot
1372 * infos. This code works as a side effect of the fact that
1373 * we have one section and vaddr == p_paddr
1375 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1377 for (i = 0; i < e->e_phnum; ++i, ++p) {
1378 if (p->p_type != PT_LOAD || p->p_offset == 0)
1380 if (loadinfo->memsize == 0) {
1381 loadinfo->offset = p->p_offset;
1382 loadinfo->memsize = p->p_memsz;
1383 loadinfo->filesize = p->p_filesz;
1384 loadinfo->load_loc = p->p_vaddr;
1386 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1387 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1391 if (loadinfo->memsize == 0) {
1392 prom_printf("Can't find a loadable segment !\n");
1396 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1397 /* Claim OF memory */
1398 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1400 /* Determine whether we are trying to boot a vmlinux or some
1401 * other binary image (eg, zImage). We load vmlinux's at
1402 * KERNELADDR and all other binaries at their e_entry value.
1404 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1406 loadaddr = KERNELADDR;
1409 loadaddr = e->e_entry;
1412 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1413 if (loadinfo->base == (void *)-1) {
1414 prom_printf("Claim error, can't allocate kernel memory\n");
1418 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1419 loadinfo->base, loadinfo->memsize);
1420 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1421 loadaddr, loadinfo->memsize);
1423 /* Load the program segments... */
1425 for (i = 0; i < e->e_phnum; ++i, ++p) {
1426 unsigned long offset;
1427 if (p->p_type != PT_LOAD || p->p_offset == 0)
1430 /* Now, we skip to the image itself */
1431 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1432 prom_printf ("Seek error\n");
1433 prom_release(loadinfo->base, loadinfo->memsize);
1436 offset = p->p_vaddr - loadinfo->load_loc;
1437 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1438 prom_printf ("Read failed\n");
1439 prom_release(loadinfo->base, loadinfo->memsize);
1446 /* Return success at loading the Elf64 kernel */
1456 is_elf32(loadinfo_t *loadinfo)
1458 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1460 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1461 e->e_ident[EI_MAG1] == ELFMAG1 &&
1462 e->e_ident[EI_MAG2] == ELFMAG2 &&
1463 e->e_ident[EI_MAG3] == ELFMAG3 &&
1464 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1465 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1466 e->e_type == ET_EXEC &&
1467 e->e_machine == EM_PPC);
1471 is_elf64(loadinfo_t *loadinfo)
1473 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1475 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1476 e->e_ident[EI_MAG1] == ELFMAG1 &&
1477 e->e_ident[EI_MAG2] == ELFMAG2 &&
1478 e->e_ident[EI_MAG3] == ELFMAG3 &&
1479 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1480 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1481 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1482 e->e_machine == EM_PPC64);
1488 #ifdef CONFIG_SET_COLORMAP
1489 static unsigned char default_colors[] = {
1508 prom_handle scrn = PROM_INVALID_HANDLE;
1510 /* Try Apple's mac-boot screen ihandle */
1511 result = (int)call_prom_return("interpret", 1, 2,
1512 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1513 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1515 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1517 /* Hrm... check to see if stdout is a display */
1518 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1519 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1520 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1521 DEBUG_F("got it ! stdout is a screen\n");
1524 /* Else, we try to open the package */
1525 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1526 DEBUG_F("Open screen result: %p\n", scrn);
1530 if (scrn == PROM_INVALID_HANDLE) {
1531 prom_printf("No screen device found !\n");
1535 prom_set_color(scrn, i, default_colors[i*3],
1536 default_colors[i*3+1], default_colors[i*3+2]);
1538 prom_printf("\x1b[1;37m\x1b[2;40m");
1540 for (i=0;i<16; i++) {
1541 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1542 ansi_color_table[i].index,
1543 ansi_color_table[i].value,
1544 ansi_color_table[i].name,
1545 ansi_color_table[i].name);
1546 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1547 ansi_color_table[i].index,
1548 ansi_color_table[i].value+10,
1549 ansi_color_table[i].name,
1550 ansi_color_table[i].name);
1552 prom_printf("\x1b[1;37m\x1b[2;40m");
1553 #endif /* COLOR_TEST */
1559 #endif /* CONFIG_SET_COLORMAP */
1568 char conf_path[1024];
1570 if (_machine == _MACH_Pmac)
1573 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1574 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1575 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1576 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1577 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1578 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1579 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1580 if (fw_reboot_cnt > 0L)
1581 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1583 /* If conf= specified on command line, it overrides
1584 Usage: conf=device:partition,/path/to/conffile
1585 Example: On Open Firmware Prompt, type
1586 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1588 if (!strncmp(bootargs, "conf=", 5)) {
1589 DEBUG_F("Using conf argument in Open Firmware\n");
1590 char *end = strchr(bootargs,' ');
1594 strcpy(bootdevice, bootargs + 5);
1596 DEBUG_F("Using conf=%s\n", bootdevice);
1598 /* Remove conf=xxx from bootargs */
1600 memmove(bootargs, end+1, strlen(end+1)+1);
1604 if (bootdevice[0] == 0) {
1605 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1606 DEBUG_F("boot-device = %s\n", bootdevice);
1608 if (bootdevice[0] == 0) {
1609 prom_printf("Couldn't determine boot device\n");
1613 if (bootoncelabel[0] == 0) {
1614 prom_get_options("boot-once", bootoncelabel,
1615 sizeof(bootoncelabel));
1616 if (bootoncelabel[0] != 0)
1617 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1619 prom_set_options("boot-once", NULL, 0);
1621 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1622 prom_printf("%s: Unable to parse\n", bootdevice);
1625 if (_machine == _MACH_bplan && !conf_given)
1627 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1628 boot.dev, boot.part, boot.file);
1631 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1632 boot.file = "/etc/";
1633 else if (strlen(boot.file)) {
1634 if (!strncmp(boot.file, "\\\\", 2))
1638 p = last = boot.file;
1648 if (strlen(boot.file))
1649 strcat(boot.file, "\\");
1652 strcpy(conf_path, boot.file);
1653 strcat(conf_path, CONFIG_FILE_NAME);
1654 boot.file = conf_path;
1655 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1656 boot.dev, boot.part, boot.file);
1660 * If we're doing a netboot, first look for one which matches our
1663 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1664 prom_printf("Try to netboot\n");
1665 useconf = load_my_config_file(&boot);
1669 useconf = load_config_file(&boot);
1671 prom_printf("Welcome to yaboot version " VERSION "\n");
1672 prom_printf("Enter \"help\" to get some basic usage information\n");
1674 /* I am fed up with lusers using the wrong partition type and
1675 mailing me *when* it breaks */
1677 if (_machine == _MACH_Pmac) {
1678 char *entry = cfg_get_strg(0, "ptypewarning");
1681 warn = strcmp(entry,
1682 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1684 ptype = get_part_type(boot.dev, boot.part);
1685 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1686 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1687 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1695 prom_printf("Bye.\n");
1701 * c-file-style: "k&r"