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 /* Allocate some memory for malloc'ator */
181 malloc_base = prom_claim_chunk((void *)MALLOCADDR, MALLOCSIZE, 0);
182 if (malloc_base == (void *)-1) {
183 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
184 MALLOCSIZE, MALLOCADDR);
187 malloc_init(malloc_base, MALLOCSIZE);
188 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
189 malloc_base, MALLOCSIZE);
191 /* A few useless DEBUG_F's */
192 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
193 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
195 /* ask the OF info if we're a chrp or pmac */
196 /* we need to set _machine before calling finish_device_tree */
197 root = prom_finddevice("/");
199 static char model[256];
200 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
201 !strncmp("bplan", model, 5))
202 _machine = _MACH_bplan;
203 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
204 !strncmp("chrp", model, 4))
205 _machine = _MACH_chrp;
207 if (prom_getprop(root, "model", model, 256 ) > 0 &&
208 !strncmp(model, "IBM", 3))
209 _machine = _MACH_chrp;
213 DEBUG_F("Running on _machine = %d\n", _machine);
217 result = yaboot_main();
219 /* Get rid of malloc pool */
221 prom_release(malloc_base, MALLOCSIZE);
222 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
232 #ifdef CONFIG_COLOR_TEXT
234 * Validify color for text ui
237 check_color_text_ui(char *color)
240 while(ansi_color_table[i].name) {
241 if (!strcmp(color, ansi_color_table[i].name))
247 #endif /* CONFIG_COLOR_TEXT */
250 void print_message_file(char *filename)
254 char *defdev = boot.dev;
255 int defpart = boot.part;
260 struct boot_file_t file;
261 struct boot_fspec_t msgfile;
263 defdev = cfg_get_strg(0, "device");
266 p = cfg_get_strg(0, "partition");
268 n = simple_strtol(p, &endp, 10);
269 if (endp != p && *endp == 0)
273 strncpy(msgpath, filename, sizeof(msgpath));
274 msgfile = boot; /* Copy all the original paramters */
275 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
276 prom_printf("%s: Unable to parse\n", msgpath);
280 result = open_file(&msgfile, &file);
281 if (result != FILE_ERR_OK) {
282 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
283 prom_perror(result, msgfile.file);
288 msg = malloc(MESSAGE_FILE_MAX + 1);
292 memset(msg, 0, MESSAGE_FILE_MAX + 1);
294 if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
297 prom_printf("%s", msg);
301 file.fs->close(&file);
306 /* Currently, the config file must be at the root of the filesystem.
307 * todo: recognize the full path to myself and use it to load the
308 * config file. Handle the "\\" (blessed system folder)
311 load_config_file(struct boot_fspec_t *fspec)
313 char *conf_file = NULL, *p;
314 struct boot_file_t file;
315 int sz, opened = 0, result = 0;
317 /* Allocate a buffer for the config file */
318 conf_file = malloc(CONFIG_FILE_MAX);
320 prom_printf("Can't alloc config file buffer\n");
325 result = open_file(fspec, &file);
326 if (result != FILE_ERR_OK) {
327 prom_printf("%s:%d,", fspec->dev, fspec->part);
328 prom_perror(result, fspec->file);
329 prom_printf("Can't open config file\n");
335 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
337 prom_printf("Error, can't read config file\n");
340 prom_printf("Config file read, %d bytes\n", sz);
344 file.fs->close(&file);
347 /* Call the parsing code in cfg.c */
348 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
349 prom_printf ("Syntax error or read error config\n");
354 * set the default cf_option to label that has the same MAC addr
355 * it only works if there is a label with the MAC addr on yaboot.conf
357 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
358 /* change the variable bellow to get the MAC dinamicaly */
359 char * macaddr = NULL;
362 macaddr = prom_get_mac(prom_get_netinfo());
363 default_mac = cfg_set_default_by_mac(macaddr);
364 if (default_mac >= 1) {
365 prom_printf("Default label was changed to macaddr label.\n");
369 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
371 /* Now, we do the initialisations stored in the config file */
372 p = cfg_get_strg(0, "init-code");
376 password = cfg_get_strg(0, "password");
378 #ifdef CONFIG_COLOR_TEXT
379 p = cfg_get_strg(0, "fgcolor");
381 DEBUG_F("fgcolor=%s\n", p);
382 fgcolor = check_color_text_ui(p);
384 prom_printf("Invalid fgcolor: \"%s\".\n", p);
387 p = cfg_get_strg(0, "bgcolor");
389 DEBUG_F("bgcolor=%s\n", p);
390 bgcolor = check_color_text_ui(p);
392 prom_printf("Invalid bgcolor: \"%s\".\n", p);
396 sprintf(temp, "%x to background-color", bgcolor);
397 prom_interpret(temp);
404 sprintf(temp, "%x to foreground-color", fgcolor);
405 prom_interpret(temp);
407 #endif /* CONFIG_COLOR_TEXT */
409 p = cfg_get_strg(0, "init-message");
411 prom_printf("%s\n", p);
413 p = cfg_get_strg(0, "message");
415 print_message_file(p);
422 file.fs->close(&file);
431 * Search for config file by MAC address, then by IP address.
432 * Basically copying pxelinux's algorithm.
433 * http://syslinux.zytor.com/pxe.php#config
435 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
437 struct bootp_packet *packet;
439 struct boot_fspec_t fspec = *orig_fspec;
440 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
444 packet = prom_get_netinfo();
449 * First, try to match on mac address with the hardware type
453 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
454 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
458 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
459 strcat(fspec.file, prom_get_mac(packet));
461 rc = load_config_file(&fspec);
466 * Now try to match on IP.
468 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
469 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
471 for (flen = strlen(fspec.file),
472 minlen = strlen(cfgpath); flen > minlen; flen--) {
473 rc = load_config_file(&fspec);
476 /* Chop one digit off the end, try again */
477 fspec.file[flen - 1] = '\0';
481 if (rc) /* modify original only on success */
482 orig_fspec->file = fspec.file;
488 void maintabfunc (void)
492 prom_printf("boot: %s", cbuff);
497 word_split(char **linep, char **paramsp)
512 while (*p != 0 && *p != ' ')
521 make_params(char *label, char *params)
524 static char buffer[2048];
529 p = cfg_get_strg(label, "literal");
541 p = cfg_get_strg(label, "root");
548 if (cfg_get_flag(label, "read-only")) {
552 if (cfg_get_flag(label, "read-write")) {
556 p = cfg_get_strg(label, "ramdisk");
558 strcpy (q, "ramdisk=");
563 p = cfg_get_strg(label, "initrd-size");
565 strcpy (q, "ramdisk_size=");
570 if (cfg_get_flag(label, "novideo")) {
571 strcpy (q, "video=ofonly");
575 p = cfg_get_strg (label, "append");
582 pause_after = cfg_get_flag (label, "pause-after");
583 p = cfg_get_strg(label, "pause-message");
592 void check_password(char *str)
596 prom_printf("\n%s", str);
597 for (i = 0; i < 3; i++) {
598 prom_printf ("\nPassword: ");
600 cmdedit ((void (*)(void)) 0, 1);
602 #ifdef USE_MD5_PASSWORDS
603 if (!strncmp (password, "$1$", 3)) {
604 if (!check_md5_password(passwdbuff, password))
607 else if (!strcmp (password, passwdbuff))
610 if (!strcmp (password, passwdbuff))
612 #endif /* USE_MD5_PASSWORDS */
615 prom_printf ("Incorrect password. Try again.");
618 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
619 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
620 " ||----w |\n || ||\n");
622 prom_interpret("reset-all");
625 int get_params(struct boot_param_t* params)
629 char defdevice_bak[1024];
632 char *imagename = 0, *label;
637 static int first = 1;
638 static char imagepath[1024];
639 static char initrdpath[1024];
640 static char manualinitrd[1024];
641 static int definitrd = 1, hasarg = 0;
644 memset(params, 0, sizeof(*params));
646 params->kernel.part = -1;
647 params->rd.part = -1;
652 if (first && !fw_reboot_cnt) {
654 imagename = bootargs;
655 word_split(&imagename, ¶ms->args);
656 timeout = DEFAULT_TIMEOUT;
658 prom_printf("Default supplied on the command line: %s ", imagename);
660 prom_printf("%s", params->args);
663 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
664 timeout = simple_strtol(q, NULL, 0);
667 /* If this is a reboot due to FW detecting CAS changes then
668 * set timeout to 1. The last kernel booted will be booted
669 * again automatically. It should seem seamless to the user
674 prom_printf("boot: ");
679 end = beg + 100 * timeout;
681 c = prom_nbgetchar();
682 } while (c == -1 && prom_getms() <= end);
686 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
692 if (c != -1 && c != '\n' && c != '\r') {
695 } else if (c >= ' ') {
698 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
701 prom_printf("%s\n", cbuff);
706 if (c == '\n' || c == '\r') {
708 if (bootoncelabel[0] != 0)
709 imagename = bootoncelabel;
710 else if (bootlastlabel[0] != 0)
711 imagename = bootlastlabel;
713 imagename = cfg_get_default();
716 prom_printf("%s", imagename);
718 prom_printf(" %s", params->args);
720 } else if (!singlekey) {
721 cmdedit(maintabfunc, 0);
723 strcpy(given_bootargs, cbuff);
724 given_bootargs_by_user = 1;
726 word_split(&imagename, ¶ms->args);
729 /* initrd setup via cmd console */
730 /* first, check if the user uses it with some label */
731 if (!strncmp(params->args, "initrd=", 7)) {
732 DEBUG_F("params->args: %s\n", params->args);
735 /* after, check if there is the 'initrd=' in the imagename string */
736 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
738 /* return the value of definitrd to 1 */
742 /* args = "initrd=blah" */
753 /* copy the string after the '=' to manualinitrd */
754 strcpy(manualinitrd, args+7);
756 prom_printf("New initrd file specified: %s\n", manualinitrd);
758 prom_printf("ERROR: no initrd specified!\n");
762 /* set imagename with the default values of the config file */
763 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
764 imagename = cfg_get_default();
766 imagename = cfg_get_default();
769 /* chrp gets this wrong, force it -- Cort */
770 if ( useconf && (!imagename || imagename[0] == 0 ))
771 imagename = cfg_get_default();
773 /* write the imagename out so it can be reused on reboot if necessary */
774 prom_set_options("boot-last-label", imagename, strlen(imagename));
777 defdevice = boot.dev;
779 strcpy(defdevice_bak,defdevice);
782 defdevice = cfg_get_strg(0, "device");
783 p = cfg_get_strg(0, "partition");
785 n = simple_strtol(p, &endp, 10);
786 if (endp != p && *endp == 0)
789 p = cfg_get_strg(0, "pause-message");
792 if (cfg_get_flag(0, "restricted"))
794 p = cfg_get_strg(imagename, "image");
798 defdevice = cfg_get_strg(label, "device");
799 if(!defdevice) defdevice=boot.dev;
800 p = cfg_get_strg(label, "partition");
802 n = simple_strtol(p, &endp, 10);
803 if (endp != p && *endp == 0)
806 if (cfg_get_flag(label, "restricted"))
809 if (params->args && password && restricted)
810 check_password ("To specify arguments for this image "
811 "you must enter the password.");
812 else if (password && !restricted)
813 check_password ("This image is restricted.");
815 params->args = make_params(label, params->args);
819 if (!strcmp (imagename, "help")) {
820 /* FIXME: defdevice shouldn't need to be reset all over the place */
821 if(!defdevice) defdevice = boot.dev;
823 "\nPress the tab key for a list of defined images.\n"
824 "The label marked with a \"*\" is is the default image, "
825 "press <return> to boot it.\n\n"
826 "To boot any other label simply type its name and press <return>.\n\n"
827 "To boot a kernel image which is not defined in the yaboot configuration \n"
828 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
829 "\"device:\" is the OpenFirmware device path to the disk the image \n"
830 "resides on, and \"partno\" is the partition number the image resides on.\n"
831 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
832 "device, if you only specify a filename you should not start it with a \",\"\n\n"
833 "To boot a alternative initrd file rather than specified in the yaboot\n"
834 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
835 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
836 "kernel image. You can, also, specify a different initrd file to any other\n"
837 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
838 "and the specified initrd file will be loaded.\n\n"
839 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
840 "its device, partno and path, on Open Firmware Prompt:\n"
841 "boot conf=device:partno,/path/to/configfile\n."
842 "To reload the config file or load a new one, use the \"conf\" command\n"
843 "on Yaboot's prompt:\n"
844 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
845 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
846 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
851 if (!strcmp (imagename, "halt")) {
853 check_password ("Restricted command.");
857 if (!strcmp (imagename, "bye")) {
859 check_password ("Restricted command.");
865 if (!strncmp (imagename, "conf", 4)) {
867 // imagename = "conf file=blah dev=bleh part=blih"
868 DEBUG_F("Loading user-specified config file: %s\n",imagename);
870 check_password ("Restricted command.");
874 // args= "file=blah dev=bleh part=blih"
875 char *args = params->args;
879 // set a pointer to the first space in args
880 char *space = strchr(args,' ');
884 char temp[1024] = "0";
886 // copy next argument to temp
887 strncpy(temp, args, space-args);
889 // parse temp and set boot arguments
890 if (!strncmp (temp, "file=", 5)){
891 DEBUG_F("conf file: %s\n", temp+5);
892 strcpy(boot.file, temp+5);
893 } else if (!strncmp (temp, "device=", 7)){
894 DEBUG_F("conf device: %s\n", temp+7);
895 strcpy(boot.dev, temp+7);
896 } else if (!strncmp (temp, "partition=", 10)){
897 DEBUG_F("conf partition: %s\n", temp+10);
898 boot.part=simple_strtol(temp+10,NULL,10);
902 // set the pointer to the next space in args;
903 // set the loop control variable
904 if (strlen(space)>1){
905 // Go to the next argument
909 if (strchr(args,' ') == NULL)
910 space = &args[strlen(args)];
912 space = strchr(args,' ');
919 prom_printf("Loading config file...\n");
920 useconf = load_config_file(&boot);
922 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
923 timeout = simple_strtol(q, NULL, 0);
925 prom_printf("Restoring default values.\n");
926 strcpy(boot.file,"");
927 strcpy(boot.dev, defdevice_bak);
932 prom_printf("Current configuration:\n");
933 prom_printf("device: %s\n", boot.dev);
935 prom_printf("partition: auto\n");
937 prom_printf("partition: %d\n", boot.part);
938 if (strlen(boot.file))
939 prom_printf("file: %s\n", boot.file);
941 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
950 if (imagename[0] == '$') {
951 /* forth command string */
953 check_password ("OpenFirmware commands are restricted.");
954 prom_interpret(imagename+1);
958 strncpy(imagepath, imagename, 1024);
960 if (!label && password)
961 check_password ("To boot a custom image you must enter the password.");
963 params->kernel = boot; /* Copy all the original paramters */
964 if (!parse_device_path(imagepath, defdevice, defpart,
965 "/vmlinux", ¶ms->kernel)) {
966 prom_printf("%s: Unable to parse\n", imagepath);
969 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
971 p = cfg_get_strg(label, "initrd");
974 /* check if user seted to use a initrd file from boot console */
975 if (!definitrd && p != manualinitrd) {
976 if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
977 strcpy(initrdpath, "/");
978 strcat(initrdpath, manualinitrd);
980 strncpy(initrdpath, manualinitrd, 1024);
982 strncpy(initrdpath, p, 1024);
984 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
985 params->rd = boot; /* Copy all the original paramters */
986 if (!parse_device_path(initrdpath, defdevice, defpart,
987 "/root.bin", ¶ms->rd)) {
988 prom_printf("%s: Unable to parse\n", imagepath);
996 /* This is derived from quik core. To be changed to first parse the headers
997 * doing lazy-loading, and then claim the memory before loading the kernel
999 * We also need to add initrd support to this whole mecanism
1002 yaboot_text_ui(void)
1004 struct boot_file_t file;
1006 static struct boot_param_t params;
1008 unsigned long initrd_size;
1009 kernel_entry_t kernel_entry;
1011 loadinfo_t loadinfo;
1012 void *initrd_more,*initrd_want;
1013 unsigned long initrd_read;
1015 loadinfo.load_loc = 0;
1021 if (get_params(¶ms))
1023 if (!params.kernel.file)
1026 prom_printf("Please wait, loading kernel...\n");
1028 memset(&file, 0, sizeof(file));
1030 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1031 && params.kernel.file[0] != '\\') {
1032 loc=(char*)malloc(strlen(params.kernel.file)+3);
1034 prom_printf ("malloc error\n");
1037 strcpy(loc,boot.file);
1038 strcat(loc,params.kernel.file);
1039 free(params.kernel.file);
1040 params.kernel.file=loc;
1042 result = open_file(¶ms.kernel, &file);
1043 if (result != FILE_ERR_OK) {
1044 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1045 prom_perror(result, params.kernel.file);
1049 /* Read the Elf e_ident, e_type and e_machine fields to
1050 * determine Elf file type
1052 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1053 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1054 file.fs->close(&file);
1055 memset(&file, 0, sizeof(file));
1059 if (is_elf32(&loadinfo)) {
1060 if (!load_elf32(&file, &loadinfo)) {
1061 file.fs->close(&file);
1062 memset(&file, 0, sizeof(file));
1065 prom_printf(" Elf32 kernel loaded...\n");
1066 } else if (is_elf64(&loadinfo)) {
1067 if (!load_elf64(&file, &loadinfo)) {
1068 file.fs->close(&file);
1069 memset(&file, 0, sizeof(file));
1072 prom_printf(" Elf64 kernel loaded...\n");
1074 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1075 file.fs->close(&file);
1076 memset(&file, 0, sizeof(file));
1079 file.fs->close(&file);
1080 memset(&file, 0, sizeof(file));
1082 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1083 * can't tell the size it will be so we claim an arbitrary amount
1086 if (flat_vmlinux && params.rd.file) {
1087 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1088 && params.kernel.file[0] != '\\')
1091 loc=(char*)malloc(strlen(params.rd.file)+3);
1093 prom_printf ("Malloc error\n");
1096 strcpy(loc,boot.file);
1097 strcat(loc,params.rd.file);
1098 free(params.rd.file);
1101 prom_printf("Loading ramdisk...\n");
1102 result = open_file(¶ms.rd, &file);
1103 if (result != FILE_ERR_OK) {
1104 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1105 prom_perror(result, params.rd.file);
1108 #define INITRD_CHUNKSIZE 0x100000
1109 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1110 if (initrd_base == (void *)-1) {
1111 prom_printf("Claim failed for initrd memory\n");
1114 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1115 if (initrd_size == 0)
1117 initrd_read = initrd_size;
1118 initrd_more = initrd_base;
1119 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1120 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1121 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1122 if (initrd_more != initrd_want) {
1123 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1127 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1128 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1129 initrd_size += initrd_read;
1132 file.fs->close(&file);
1133 memset(&file, 0, sizeof(file));
1136 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1137 initrd_base, initrd_size >> 10);
1139 prom_printf("ramdisk load failed !\n");
1144 DEBUG_F("setting kernel args to: %s\n", params.args);
1145 prom_setargs(params.args);
1146 DEBUG_F("flushing icache...");
1147 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1150 /* compute the kernel's entry point. */
1151 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1153 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1154 DEBUG_F("kernel: arg1 = %p,\n"
1155 " arg2 = 0x%08lx,\n"
1159 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1161 DEBUG_F("Entering kernel...\n");
1163 /* call the kernel with our stack. */
1164 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1172 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1175 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1177 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1178 unsigned long loadaddr;
1180 /* Read the rest of the Elf header... */
1181 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1182 prom_printf("\nCan't read Elf32 image header\n");
1186 DEBUG_F("Elf32 header:\n");
1187 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1188 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1189 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1190 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1191 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1192 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1193 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1194 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1195 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1196 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1198 loadinfo->entry = e->e_entry;
1200 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1202 prom_printf ("Malloc error\n");
1206 /* Now, we read the section header */
1207 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1208 prom_printf ("seek error\n");
1211 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1212 sizeof(Elf32_Phdr) * e->e_phnum) {
1213 prom_printf ("read error\n");
1217 /* Scan through the program header
1218 * HACK: We must return the _memory size of the kernel image, not the
1219 * file size (because we have to leave room before other boot
1220 * infos. This code works as a side effect of the fact that
1221 * we have one section and vaddr == p_paddr
1223 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1225 for (i = 0; i < e->e_phnum; ++i, ++p) {
1226 if (p->p_type != PT_LOAD || p->p_offset == 0)
1228 if (loadinfo->memsize == 0) {
1229 loadinfo->offset = p->p_offset;
1230 loadinfo->memsize = p->p_memsz;
1231 loadinfo->filesize = p->p_filesz;
1232 loadinfo->load_loc = p->p_vaddr;
1234 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1235 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1239 if (loadinfo->memsize == 0) {
1240 prom_printf("Can't find a loadable segment !\n");
1244 /* leave some room (1Mb) for boot infos */
1245 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1246 /* Claim OF memory */
1247 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1249 /* Determine whether we are trying to boot a vmlinux or some
1250 * other binary image (eg, zImage). We load vmlinux's at
1251 * KERNELADDR and all other binaries at their e_entry value.
1253 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1255 loadaddr = KERNELADDR;
1258 loadaddr = loadinfo->load_loc;
1261 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1262 if (loadinfo->base == (void *)-1) {
1263 prom_printf("Claim error, can't allocate kernel memory\n");
1267 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1268 loadinfo->base, loadinfo->memsize);
1269 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1270 loadaddr, loadinfo->memsize);
1272 /* Load the program segments... */
1274 for (i = 0; i < e->e_phnum; ++i, ++p) {
1275 unsigned long offset;
1276 if (p->p_type != PT_LOAD || p->p_offset == 0)
1279 /* Now, we skip to the image itself */
1280 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1281 prom_printf ("Seek error\n");
1282 prom_release(loadinfo->base, loadinfo->memsize);
1285 offset = p->p_vaddr - loadinfo->load_loc;
1286 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1287 prom_printf ("Read failed\n");
1288 prom_release(loadinfo->base, loadinfo->memsize);
1295 /* Return success at loading the Elf32 kernel */
1305 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1308 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1310 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1311 unsigned long loadaddr;
1313 /* Read the rest of the Elf header... */
1314 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1315 prom_printf("\nCan't read Elf64 image header\n");
1319 DEBUG_F("Elf64 header:\n");
1320 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1321 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1322 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1323 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1324 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1325 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1326 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1327 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1328 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1329 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1331 loadinfo->entry = e->e_entry;
1333 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1335 prom_printf ("Malloc error\n");
1339 /* Now, we read the section header */
1340 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1341 prom_printf ("Seek error\n");
1344 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1345 sizeof(Elf64_Phdr) * e->e_phnum) {
1346 prom_printf ("Read error\n");
1350 /* Scan through the program header
1351 * HACK: We must return the _memory size of the kernel image, not the
1352 * file size (because we have to leave room before other boot
1353 * infos. This code works as a side effect of the fact that
1354 * we have one section and vaddr == p_paddr
1356 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1358 for (i = 0; i < e->e_phnum; ++i, ++p) {
1359 if (p->p_type != PT_LOAD || p->p_offset == 0)
1361 if (loadinfo->memsize == 0) {
1362 loadinfo->offset = p->p_offset;
1363 loadinfo->memsize = p->p_memsz;
1364 loadinfo->filesize = p->p_filesz;
1365 loadinfo->load_loc = p->p_vaddr;
1367 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1368 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1372 if (loadinfo->memsize == 0) {
1373 prom_printf("Can't find a loadable segment !\n");
1377 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1378 /* Claim OF memory */
1379 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1381 /* Determine whether we are trying to boot a vmlinux or some
1382 * other binary image (eg, zImage). We load vmlinux's at
1383 * KERNELADDR and all other binaries at their e_entry value.
1385 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1387 loadaddr = KERNELADDR;
1390 loadaddr = e->e_entry;
1393 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1394 if (loadinfo->base == (void *)-1) {
1395 prom_printf("Claim error, can't allocate kernel memory\n");
1399 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1400 loadinfo->base, loadinfo->memsize);
1401 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1402 loadaddr, loadinfo->memsize);
1404 /* Load the program segments... */
1406 for (i = 0; i < e->e_phnum; ++i, ++p) {
1407 unsigned long offset;
1408 if (p->p_type != PT_LOAD || p->p_offset == 0)
1411 /* Now, we skip to the image itself */
1412 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1413 prom_printf ("Seek error\n");
1414 prom_release(loadinfo->base, loadinfo->memsize);
1417 offset = p->p_vaddr - loadinfo->load_loc;
1418 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1419 prom_printf ("Read failed\n");
1420 prom_release(loadinfo->base, loadinfo->memsize);
1427 /* Return success at loading the Elf64 kernel */
1437 is_elf32(loadinfo_t *loadinfo)
1439 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1441 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1442 e->e_ident[EI_MAG1] == ELFMAG1 &&
1443 e->e_ident[EI_MAG2] == ELFMAG2 &&
1444 e->e_ident[EI_MAG3] == ELFMAG3 &&
1445 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1446 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1447 e->e_type == ET_EXEC &&
1448 e->e_machine == EM_PPC);
1452 is_elf64(loadinfo_t *loadinfo)
1454 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1456 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1457 e->e_ident[EI_MAG1] == ELFMAG1 &&
1458 e->e_ident[EI_MAG2] == ELFMAG2 &&
1459 e->e_ident[EI_MAG3] == ELFMAG3 &&
1460 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1461 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1462 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1463 e->e_machine == EM_PPC64);
1469 #ifdef CONFIG_SET_COLORMAP
1470 static unsigned char default_colors[] = {
1489 prom_handle scrn = PROM_INVALID_HANDLE;
1491 /* Try Apple's mac-boot screen ihandle */
1492 result = (int)call_prom_return("interpret", 1, 2,
1493 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1494 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1496 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1498 /* Hrm... check to see if stdout is a display */
1499 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1500 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1501 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1502 DEBUG_F("got it ! stdout is a screen\n");
1505 /* Else, we try to open the package */
1506 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1507 DEBUG_F("Open screen result: %p\n", scrn);
1511 if (scrn == PROM_INVALID_HANDLE) {
1512 prom_printf("No screen device found !\n");
1516 prom_set_color(scrn, i, default_colors[i*3],
1517 default_colors[i*3+1], default_colors[i*3+2]);
1519 prom_printf("\x1b[1;37m\x1b[2;40m");
1521 for (i=0;i<16; i++) {
1522 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1523 ansi_color_table[i].index,
1524 ansi_color_table[i].value,
1525 ansi_color_table[i].name,
1526 ansi_color_table[i].name);
1527 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1528 ansi_color_table[i].index,
1529 ansi_color_table[i].value+10,
1530 ansi_color_table[i].name,
1531 ansi_color_table[i].name);
1533 prom_printf("\x1b[1;37m\x1b[2;40m");
1534 #endif /* COLOR_TEST */
1540 #endif /* CONFIG_SET_COLORMAP */
1549 char conf_path[1024];
1551 if (_machine == _MACH_Pmac)
1554 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1555 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1556 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1557 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1558 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1559 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1560 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1561 if (fw_reboot_cnt > 0L)
1562 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1564 /* If conf= specified on command line, it overrides
1565 Usage: conf=device:partition,/path/to/conffile
1566 Example: On Open Firmware Prompt, type
1567 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1569 if (!strncmp(bootargs, "conf=", 5)) {
1570 DEBUG_F("Using conf argument in Open Firmware\n");
1571 char *end = strchr(bootargs,' ');
1575 strcpy(bootdevice, bootargs + 5);
1577 DEBUG_F("Using conf=%s\n", bootdevice);
1579 /* Remove conf=xxx from bootargs */
1581 memmove(bootargs, end+1, strlen(end+1)+1);
1585 if (bootdevice[0] == 0) {
1586 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1587 DEBUG_F("boot-device = %s\n", bootdevice);
1589 if (bootdevice[0] == 0) {
1590 prom_printf("Couldn't determine boot device\n");
1594 if (bootoncelabel[0] == 0) {
1595 prom_get_options("boot-once", bootoncelabel,
1596 sizeof(bootoncelabel));
1597 if (bootoncelabel[0] != 0)
1598 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1600 prom_set_options("boot-once", NULL, 0);
1602 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1603 prom_printf("%s: Unable to parse\n", bootdevice);
1606 if (_machine == _MACH_bplan && !conf_given)
1608 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1609 boot.dev, boot.part, boot.file);
1612 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1613 boot.file = "/etc/";
1614 else if (strlen(boot.file)) {
1615 if (!strncmp(boot.file, "\\\\", 2))
1619 p = last = boot.file;
1629 if (strlen(boot.file))
1630 strcat(boot.file, "\\");
1633 strcpy(conf_path, boot.file);
1634 strcat(conf_path, CONFIG_FILE_NAME);
1635 boot.file = conf_path;
1636 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1637 boot.dev, boot.part, boot.file);
1641 * If we're doing a netboot, first look for one which matches our
1644 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1645 prom_printf("Try to netboot\n");
1646 useconf = load_my_config_file(&boot);
1650 useconf = load_config_file(&boot);
1652 prom_printf("Welcome to yaboot version " VERSION "\n");
1653 prom_printf("Enter \"help\" to get some basic usage information\n");
1655 /* I am fed up with lusers using the wrong partition type and
1656 mailing me *when* it breaks */
1658 if (_machine == _MACH_Pmac) {
1659 char *entry = cfg_get_strg(0, "ptypewarning");
1662 warn = strcmp(entry,
1663 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1665 ptype = get_part_type(boot.dev, boot.part);
1666 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1667 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1668 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1676 prom_printf("Bye.\n");
1682 * c-file-style: "k&r"