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((void *)MALLOCADDR, MALLOCSIZE, 0);
184 if (malloc_base == (void *)-1) {
185 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
186 MALLOCSIZE, MALLOCADDR);
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(passwdbuff, 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;
715 imagename = cfg_get_default();
718 prom_printf("%s", imagename);
720 prom_printf(" %s", params->args);
722 } else if (!singlekey) {
723 cmdedit(maintabfunc, 0);
725 strcpy(given_bootargs, cbuff);
726 given_bootargs_by_user = 1;
728 word_split(&imagename, ¶ms->args);
731 /* initrd setup via cmd console */
732 /* first, check if the user uses it with some label */
733 if (!strncmp(params->args, "initrd=", 7)) {
734 DEBUG_F("params->args: %s\n", params->args);
737 /* after, check if there is the 'initrd=' in the imagename string */
738 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
740 /* return the value of definitrd to 1 */
744 /* args = "initrd=blah" */
755 /* copy the string after the '=' to manualinitrd */
756 strcpy(manualinitrd, args+7);
758 prom_printf("New initrd file specified: %s\n", manualinitrd);
760 prom_printf("ERROR: no initrd specified!\n");
764 /* set imagename with the default values of the config file */
765 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
766 imagename = cfg_get_default();
768 imagename = cfg_get_default();
771 /* chrp gets this wrong, force it -- Cort */
772 if ( useconf && (!imagename || imagename[0] == 0 ))
773 imagename = cfg_get_default();
775 /* write the imagename out so it can be reused on reboot if necessary */
776 prom_set_options("boot-last-label", imagename, strlen(imagename));
779 defdevice = boot.dev;
781 strcpy(defdevice_bak,defdevice);
784 defdevice = cfg_get_strg(0, "device");
785 p = cfg_get_strg(0, "partition");
787 n = simple_strtol(p, &endp, 10);
788 if (endp != p && *endp == 0)
791 p = cfg_get_strg(0, "pause-message");
794 if (cfg_get_flag(0, "restricted"))
796 p = cfg_get_strg(imagename, "image");
800 defdevice = cfg_get_strg(label, "device");
801 if(!defdevice) defdevice=boot.dev;
802 p = cfg_get_strg(label, "partition");
804 n = simple_strtol(p, &endp, 10);
805 if (endp != p && *endp == 0)
808 if (cfg_get_flag(label, "restricted"))
811 if (params->args && password && restricted)
812 check_password ("To specify arguments for this image "
813 "you must enter the password.");
814 else if (password && !restricted)
815 check_password ("This image is restricted.");
817 params->args = make_params(label, params->args);
821 if (!strcmp (imagename, "help")) {
822 /* FIXME: defdevice shouldn't need to be reset all over the place */
823 if(!defdevice) defdevice = boot.dev;
825 "\nPress the tab key for a list of defined images.\n"
826 "The label marked with a \"*\" is is the default image, "
827 "press <return> to boot it.\n\n"
828 "To boot any other label simply type its name and press <return>.\n\n"
829 "To boot a kernel image which is not defined in the yaboot configuration \n"
830 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
831 "\"device:\" is the OpenFirmware device path to the disk the image \n"
832 "resides on, and \"partno\" is the partition number the image resides on.\n"
833 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
834 "device, if you only specify a filename you should not start it with a \",\"\n\n"
835 "To boot a alternative initrd file rather than specified in the yaboot\n"
836 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
837 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
838 "kernel image. You can, also, specify a different initrd file to any other\n"
839 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
840 "and the specified initrd file will be loaded.\n\n"
841 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
842 "its device, partno and path, on Open Firmware Prompt:\n"
843 "boot conf=device:partno,/path/to/configfile\n."
844 "To reload the config file or load a new one, use the \"conf\" command\n"
845 "on Yaboot's prompt:\n"
846 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
847 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
848 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
853 if (!strcmp (imagename, "halt")) {
855 check_password ("Restricted command.");
859 if (!strcmp (imagename, "bye")) {
861 check_password ("Restricted command.");
867 if (!strncmp (imagename, "conf", 4)) {
869 // imagename = "conf file=blah dev=bleh part=blih"
870 DEBUG_F("Loading user-specified config file: %s\n",imagename);
872 check_password ("Restricted command.");
876 // args= "file=blah dev=bleh part=blih"
877 char *args = params->args;
881 // set a pointer to the first space in args
882 char *space = strchr(args,' ');
886 char temp[1024] = "0";
888 // copy next argument to temp
889 strncpy(temp, args, space-args);
891 // parse temp and set boot arguments
892 if (!strncmp (temp, "file=", 5)){
893 DEBUG_F("conf file: %s\n", temp+5);
894 strcpy(boot.file, temp+5);
895 } else if (!strncmp (temp, "device=", 7)){
896 DEBUG_F("conf device: %s\n", temp+7);
897 strcpy(boot.dev, temp+7);
898 } else if (!strncmp (temp, "partition=", 10)){
899 DEBUG_F("conf partition: %s\n", temp+10);
900 boot.part=simple_strtol(temp+10,NULL,10);
904 // set the pointer to the next space in args;
905 // set the loop control variable
906 if (strlen(space)>1){
907 // Go to the next argument
911 if (strchr(args,' ') == NULL)
912 space = &args[strlen(args)];
914 space = strchr(args,' ');
921 prom_printf("Loading config file...\n");
922 useconf = load_config_file(&boot);
924 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
925 timeout = simple_strtol(q, NULL, 0);
927 prom_printf("Restoring default values.\n");
928 strcpy(boot.file,"");
929 strcpy(boot.dev, defdevice_bak);
934 prom_printf("Current configuration:\n");
935 prom_printf("device: %s\n", boot.dev);
937 prom_printf("partition: auto\n");
939 prom_printf("partition: %d\n", boot.part);
940 if (strlen(boot.file))
941 prom_printf("file: %s\n", boot.file);
943 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
952 if (imagename[0] == '$') {
953 /* forth command string */
955 check_password ("OpenFirmware commands are restricted.");
956 prom_interpret(imagename+1);
960 strncpy(imagepath, imagename, 1024);
962 if (!label && password)
963 check_password ("To boot a custom image you must enter the password.");
965 params->kernel = boot; /* Copy all the original paramters */
966 if (!parse_device_path(imagepath, defdevice, defpart,
967 "/vmlinux", ¶ms->kernel)) {
968 prom_printf("%s: Unable to parse\n", imagepath);
971 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
973 p = cfg_get_strg(label, "initrd");
976 /* check if user seted to use a initrd file from boot console */
977 if (!definitrd && p != manualinitrd) {
978 if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
979 strcpy(initrdpath, "/");
980 strcat(initrdpath, manualinitrd);
982 strncpy(initrdpath, manualinitrd, 1024);
984 strncpy(initrdpath, p, 1024);
986 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
987 params->rd = boot; /* Copy all the original paramters */
988 if (!parse_device_path(initrdpath, defdevice, defpart,
989 "/root.bin", ¶ms->rd)) {
990 prom_printf("%s: Unable to parse\n", imagepath);
998 /* This is derived from quik core. To be changed to first parse the headers
999 * doing lazy-loading, and then claim the memory before loading the kernel
1001 * We also need to add initrd support to this whole mecanism
1004 yaboot_text_ui(void)
1006 struct boot_file_t file;
1008 static struct boot_param_t params;
1010 unsigned long initrd_size;
1011 kernel_entry_t kernel_entry;
1013 loadinfo_t loadinfo;
1014 void *initrd_more,*initrd_want;
1015 unsigned long initrd_read;
1017 loadinfo.load_loc = 0;
1023 if (get_params(¶ms))
1025 if (!params.kernel.file)
1028 prom_printf("Please wait, loading kernel...\n");
1030 memset(&file, 0, sizeof(file));
1032 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1033 && params.kernel.file[0] != '\\') {
1034 loc=(char*)malloc(strlen(params.kernel.file)+3);
1036 prom_printf ("malloc error\n");
1039 strcpy(loc,boot.file);
1040 strcat(loc,params.kernel.file);
1041 free(params.kernel.file);
1042 params.kernel.file=loc;
1044 result = open_file(¶ms.kernel, &file);
1045 if (result != FILE_ERR_OK) {
1046 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1047 prom_perror(result, params.kernel.file);
1051 /* Read the Elf e_ident, e_type and e_machine fields to
1052 * determine Elf file type
1054 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1055 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1056 file.fs->close(&file);
1057 memset(&file, 0, sizeof(file));
1061 if (is_elf32(&loadinfo)) {
1062 if (!load_elf32(&file, &loadinfo)) {
1063 file.fs->close(&file);
1064 memset(&file, 0, sizeof(file));
1067 prom_printf(" Elf32 kernel loaded...\n");
1068 } else if (is_elf64(&loadinfo)) {
1069 if (!load_elf64(&file, &loadinfo)) {
1070 file.fs->close(&file);
1071 memset(&file, 0, sizeof(file));
1074 prom_printf(" Elf64 kernel loaded...\n");
1076 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1077 file.fs->close(&file);
1078 memset(&file, 0, sizeof(file));
1081 file.fs->close(&file);
1082 memset(&file, 0, sizeof(file));
1084 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1085 * can't tell the size it will be so we claim an arbitrary amount
1088 if (flat_vmlinux && params.rd.file) {
1089 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1090 && params.kernel.file[0] != '\\')
1093 loc=(char*)malloc(strlen(params.rd.file)+3);
1095 prom_printf ("Malloc error\n");
1098 strcpy(loc,boot.file);
1099 strcat(loc,params.rd.file);
1100 free(params.rd.file);
1103 prom_printf("Loading ramdisk...\n");
1104 result = open_file(¶ms.rd, &file);
1105 if (result != FILE_ERR_OK) {
1106 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1107 prom_perror(result, params.rd.file);
1110 #define INITRD_CHUNKSIZE 0x100000
1111 unsigned int len = INITRD_CHUNKSIZE;
1113 /* We add a bit to the actual size so the loop below doesn't think
1114 * there is more to load.
1116 if (file.fs->ino_size && file.fs->ino_size(&file) > 0)
1117 len = file.fs->ino_size(&file) + 0x1000;
1119 initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0);
1120 if (initrd_base == (void *)-1) {
1121 prom_printf("Claim failed for initrd memory\n");
1124 initrd_size = file.fs->read(&file, len, initrd_base);
1125 if (initrd_size == 0)
1127 initrd_read = initrd_size;
1128 initrd_more = initrd_base;
1129 while (initrd_read == len ) { /* need to read more? */
1130 initrd_want = (void *)((unsigned long)initrd_more+len);
1131 initrd_more = prom_claim(initrd_want, len, 0);
1132 if (initrd_more != initrd_want) {
1133 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1137 initrd_read = file.fs->read(&file, len, initrd_more);
1138 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1139 initrd_size += initrd_read;
1142 file.fs->close(&file);
1143 memset(&file, 0, sizeof(file));
1146 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1147 initrd_base, initrd_size >> 10);
1149 prom_printf("ramdisk load failed !\n");
1154 DEBUG_F("setting kernel args to: %s\n", params.args);
1155 prom_setargs(params.args);
1156 DEBUG_F("flushing icache...");
1157 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1160 /* compute the kernel's entry point. */
1161 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1163 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1164 DEBUG_F("kernel: arg1 = %p,\n"
1165 " arg2 = 0x%08lx,\n"
1169 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1171 DEBUG_F("Entering kernel...\n");
1173 prom_print_available();
1175 /* call the kernel with our stack. */
1176 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1184 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1187 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1189 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1190 unsigned long loadaddr;
1192 /* Read the rest of the Elf header... */
1193 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1194 prom_printf("\nCan't read Elf32 image header\n");
1198 DEBUG_F("Elf32 header:\n");
1199 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1200 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1201 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1202 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1203 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1204 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1205 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1206 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1207 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1208 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1210 loadinfo->entry = e->e_entry;
1212 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1214 prom_printf ("Malloc error\n");
1218 /* Now, we read the section header */
1219 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1220 prom_printf ("seek error\n");
1223 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1224 sizeof(Elf32_Phdr) * e->e_phnum) {
1225 prom_printf ("read error\n");
1229 /* Scan through the program header
1230 * HACK: We must return the _memory size of the kernel image, not the
1231 * file size (because we have to leave room before other boot
1232 * infos. This code works as a side effect of the fact that
1233 * we have one section and vaddr == p_paddr
1235 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1237 for (i = 0; i < e->e_phnum; ++i, ++p) {
1238 if (p->p_type != PT_LOAD || p->p_offset == 0)
1240 if (loadinfo->memsize == 0) {
1241 loadinfo->offset = p->p_offset;
1242 loadinfo->memsize = p->p_memsz;
1243 loadinfo->filesize = p->p_filesz;
1244 loadinfo->load_loc = p->p_vaddr;
1246 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1247 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1251 if (loadinfo->memsize == 0) {
1252 prom_printf("Can't find a loadable segment !\n");
1256 /* leave some room (1Mb) for boot infos */
1257 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1258 /* Claim OF memory */
1259 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1261 /* Determine whether we are trying to boot a vmlinux or some
1262 * other binary image (eg, zImage). We load vmlinux's at
1263 * KERNELADDR and all other binaries at their e_entry value.
1265 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1267 loadaddr = KERNELADDR;
1270 loadaddr = loadinfo->load_loc;
1273 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1274 if (loadinfo->base == (void *)-1) {
1275 prom_printf("Claim error, can't allocate kernel memory\n");
1279 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1280 loadinfo->base, loadinfo->memsize);
1281 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1282 loadaddr, loadinfo->memsize);
1284 /* Load the program segments... */
1286 for (i = 0; i < e->e_phnum; ++i, ++p) {
1287 unsigned long offset;
1288 if (p->p_type != PT_LOAD || p->p_offset == 0)
1291 /* Now, we skip to the image itself */
1292 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1293 prom_printf ("Seek error\n");
1294 prom_release(loadinfo->base, loadinfo->memsize);
1297 offset = p->p_vaddr - loadinfo->load_loc;
1298 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1299 prom_printf ("Read failed\n");
1300 prom_release(loadinfo->base, loadinfo->memsize);
1307 /* Return success at loading the Elf32 kernel */
1317 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1320 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1322 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1323 unsigned long loadaddr;
1325 /* Read the rest of the Elf header... */
1326 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1327 prom_printf("\nCan't read Elf64 image header\n");
1331 DEBUG_F("Elf64 header:\n");
1332 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1333 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1334 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1335 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1336 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1337 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1338 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1339 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1340 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1341 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1343 loadinfo->entry = e->e_entry;
1345 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1347 prom_printf ("Malloc error\n");
1351 /* Now, we read the section header */
1352 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1353 prom_printf ("Seek error\n");
1356 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1357 sizeof(Elf64_Phdr) * e->e_phnum) {
1358 prom_printf ("Read error\n");
1362 /* Scan through the program header
1363 * HACK: We must return the _memory size of the kernel image, not the
1364 * file size (because we have to leave room before other boot
1365 * infos. This code works as a side effect of the fact that
1366 * we have one section and vaddr == p_paddr
1368 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1370 for (i = 0; i < e->e_phnum; ++i, ++p) {
1371 if (p->p_type != PT_LOAD || p->p_offset == 0)
1373 if (loadinfo->memsize == 0) {
1374 loadinfo->offset = p->p_offset;
1375 loadinfo->memsize = p->p_memsz;
1376 loadinfo->filesize = p->p_filesz;
1377 loadinfo->load_loc = p->p_vaddr;
1379 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1380 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1384 if (loadinfo->memsize == 0) {
1385 prom_printf("Can't find a loadable segment !\n");
1389 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1390 /* Claim OF memory */
1391 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1393 /* Determine whether we are trying to boot a vmlinux or some
1394 * other binary image (eg, zImage). We load vmlinux's at
1395 * KERNELADDR and all other binaries at their e_entry value.
1397 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1399 loadaddr = KERNELADDR;
1402 loadaddr = e->e_entry;
1405 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1406 if (loadinfo->base == (void *)-1) {
1407 prom_printf("Claim error, can't allocate kernel memory\n");
1411 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1412 loadinfo->base, loadinfo->memsize);
1413 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1414 loadaddr, loadinfo->memsize);
1416 /* Load the program segments... */
1418 for (i = 0; i < e->e_phnum; ++i, ++p) {
1419 unsigned long offset;
1420 if (p->p_type != PT_LOAD || p->p_offset == 0)
1423 /* Now, we skip to the image itself */
1424 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1425 prom_printf ("Seek error\n");
1426 prom_release(loadinfo->base, loadinfo->memsize);
1429 offset = p->p_vaddr - loadinfo->load_loc;
1430 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1431 prom_printf ("Read failed\n");
1432 prom_release(loadinfo->base, loadinfo->memsize);
1439 /* Return success at loading the Elf64 kernel */
1449 is_elf32(loadinfo_t *loadinfo)
1451 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1453 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1454 e->e_ident[EI_MAG1] == ELFMAG1 &&
1455 e->e_ident[EI_MAG2] == ELFMAG2 &&
1456 e->e_ident[EI_MAG3] == ELFMAG3 &&
1457 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1458 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1459 e->e_type == ET_EXEC &&
1460 e->e_machine == EM_PPC);
1464 is_elf64(loadinfo_t *loadinfo)
1466 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1468 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1469 e->e_ident[EI_MAG1] == ELFMAG1 &&
1470 e->e_ident[EI_MAG2] == ELFMAG2 &&
1471 e->e_ident[EI_MAG3] == ELFMAG3 &&
1472 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1473 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1474 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1475 e->e_machine == EM_PPC64);
1481 #ifdef CONFIG_SET_COLORMAP
1482 static unsigned char default_colors[] = {
1501 prom_handle scrn = PROM_INVALID_HANDLE;
1503 /* Try Apple's mac-boot screen ihandle */
1504 result = (int)call_prom_return("interpret", 1, 2,
1505 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1506 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1508 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1510 /* Hrm... check to see if stdout is a display */
1511 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1512 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1513 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1514 DEBUG_F("got it ! stdout is a screen\n");
1517 /* Else, we try to open the package */
1518 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1519 DEBUG_F("Open screen result: %p\n", scrn);
1523 if (scrn == PROM_INVALID_HANDLE) {
1524 prom_printf("No screen device found !\n");
1528 prom_set_color(scrn, i, default_colors[i*3],
1529 default_colors[i*3+1], default_colors[i*3+2]);
1531 prom_printf("\x1b[1;37m\x1b[2;40m");
1533 for (i=0;i<16; i++) {
1534 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1535 ansi_color_table[i].index,
1536 ansi_color_table[i].value,
1537 ansi_color_table[i].name,
1538 ansi_color_table[i].name);
1539 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1540 ansi_color_table[i].index,
1541 ansi_color_table[i].value+10,
1542 ansi_color_table[i].name,
1543 ansi_color_table[i].name);
1545 prom_printf("\x1b[1;37m\x1b[2;40m");
1546 #endif /* COLOR_TEST */
1552 #endif /* CONFIG_SET_COLORMAP */
1561 char conf_path[1024];
1563 if (_machine == _MACH_Pmac)
1566 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1567 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1568 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1569 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1570 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1571 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1572 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1573 if (fw_reboot_cnt > 0L)
1574 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1576 /* If conf= specified on command line, it overrides
1577 Usage: conf=device:partition,/path/to/conffile
1578 Example: On Open Firmware Prompt, type
1579 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1581 if (!strncmp(bootargs, "conf=", 5)) {
1582 DEBUG_F("Using conf argument in Open Firmware\n");
1583 char *end = strchr(bootargs,' ');
1587 strcpy(bootdevice, bootargs + 5);
1589 DEBUG_F("Using conf=%s\n", bootdevice);
1591 /* Remove conf=xxx from bootargs */
1593 memmove(bootargs, end+1, strlen(end+1)+1);
1597 if (bootdevice[0] == 0) {
1598 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1599 DEBUG_F("boot-device = %s\n", bootdevice);
1601 if (bootdevice[0] == 0) {
1602 prom_printf("Couldn't determine boot device\n");
1606 if (bootoncelabel[0] == 0) {
1607 prom_get_options("boot-once", bootoncelabel,
1608 sizeof(bootoncelabel));
1609 if (bootoncelabel[0] != 0)
1610 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1612 prom_set_options("boot-once", NULL, 0);
1614 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1615 prom_printf("%s: Unable to parse\n", bootdevice);
1618 if (_machine == _MACH_bplan && !conf_given)
1620 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1621 boot.dev, boot.part, boot.file);
1624 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1625 boot.file = "/etc/";
1626 else if (strlen(boot.file)) {
1627 if (!strncmp(boot.file, "\\\\", 2))
1631 p = last = boot.file;
1641 if (strlen(boot.file))
1642 strcat(boot.file, "\\");
1645 strcpy(conf_path, boot.file);
1646 strcat(conf_path, CONFIG_FILE_NAME);
1647 boot.file = conf_path;
1648 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1649 boot.dev, boot.part, boot.file);
1653 * If we're doing a netboot, first look for one which matches our
1656 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1657 prom_printf("Try to netboot\n");
1658 useconf = load_my_config_file(&boot);
1662 useconf = load_config_file(&boot);
1664 prom_printf("Welcome to yaboot version " VERSION "\n");
1665 prom_printf("Enter \"help\" to get some basic usage information\n");
1667 /* I am fed up with lusers using the wrong partition type and
1668 mailing me *when* it breaks */
1670 if (_machine == _MACH_Pmac) {
1671 char *entry = cfg_get_strg(0, "ptypewarning");
1674 warn = strcmp(entry,
1675 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1677 ptype = get_part_type(boot.dev, boot.part);
1678 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1679 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1680 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1688 prom_printf("Bye.\n");
1694 * c-file-style: "k&r"