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
170 /* Entry, currently called directly by crt0 (bss not inited) */
172 extern char* __bss_start;
176 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
179 void* malloc_base = NULL;
183 /* OF seems to do it, but I'm not very confident */
184 memset(&__bss_start, 0, &_end - &__bss_start);
186 /* Initialize OF interface */
187 prom_init ((prom_entry) r5);
189 /* Allocate some memory for malloc'ator */
190 for (addr = MALLOCADDR; addr <= MALLOCADDR * 16 ;addr+=0x100000) {
191 malloc_base = prom_claim((void *)addr, MALLOCSIZE, 0);
192 if (malloc_base != (void *)-1) break;
194 if (malloc_base == (void *)-1) {
195 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
196 MALLOCSIZE, MALLOCADDR);
199 malloc_init(malloc_base, MALLOCSIZE);
200 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
201 malloc_base, MALLOCSIZE);
203 /* A few useless DEBUG_F's */
204 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
205 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
207 /* ask the OF info if we're a chrp or pmac */
208 /* we need to set _machine before calling finish_device_tree */
209 root = prom_finddevice("/");
211 static char model[256];
212 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
213 !strncmp("bplan", model, 5))
214 _machine = _MACH_bplan;
215 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
216 !strncmp("chrp", model, 4))
217 _machine = _MACH_chrp;
219 if (prom_getprop(root, "model", model, 256 ) > 0 &&
220 !strncmp(model, "IBM", 3))
221 _machine = _MACH_chrp;
225 DEBUG_F("Running on _machine = %d\n", _machine);
229 result = yaboot_main();
231 /* Get rid of malloc pool */
233 prom_release(malloc_base, MALLOCSIZE);
234 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
244 #ifdef CONFIG_COLOR_TEXT
246 * Validify color for text ui
249 check_color_text_ui(char *color)
252 while(ansi_color_table[i].name) {
253 if (!strcmp(color, ansi_color_table[i].name))
259 #endif /* CONFIG_COLOR_TEXT */
262 void print_message_file(char *filename)
266 char *defdev = boot.dev;
267 int defpart = boot.part;
272 struct boot_file_t file;
273 struct boot_fspec_t msgfile;
275 defdev = cfg_get_strg(0, "device");
278 p = cfg_get_strg(0, "partition");
280 n = simple_strtol(p, &endp, 10);
281 if (endp != p && *endp == 0)
285 strncpy(msgpath, filename, sizeof(msgpath));
286 msgfile = boot; /* Copy all the original paramters */
287 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
288 prom_printf("%s: Unable to parse\n", msgpath);
292 result = open_file(&msgfile, &file);
293 if (result != FILE_ERR_OK) {
294 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
295 prom_perror(result, msgfile.file);
300 msg = malloc(MESSAGE_FILE_MAX + 1);
304 memset(msg, 0, MESSAGE_FILE_MAX + 1);
306 if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
309 prom_printf("%s", msg);
313 file.fs->close(&file);
318 /* Currently, the config file must be at the root of the filesystem.
319 * todo: recognize the full path to myself and use it to load the
320 * config file. Handle the "\\" (blessed system folder)
323 load_config_file(struct boot_fspec_t *fspec)
325 char *conf_file = NULL, *p;
326 struct boot_file_t file;
327 int sz, opened = 0, result = 0;
329 /* Allocate a buffer for the config file */
330 conf_file = malloc(CONFIG_FILE_MAX);
332 prom_printf("Can't alloc config file buffer\n");
337 result = open_file(fspec, &file);
338 if (result != FILE_ERR_OK) {
339 prom_printf("%s:%d,", fspec->dev, fspec->part);
340 prom_perror(result, fspec->file);
341 prom_printf("Can't open config file\n");
347 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
349 prom_printf("Error, can't read config file\n");
352 prom_printf("Config file read, %d bytes\n", sz);
356 file.fs->close(&file);
359 /* Call the parsing code in cfg.c */
360 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
361 prom_printf ("Syntax error or read error config\n");
366 * set the default cf_option to label that has the same MAC addr
367 * it only works if there is a label with the MAC addr on yaboot.conf
369 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
370 /* change the variable bellow to get the MAC dinamicaly */
371 char * macaddr = NULL;
374 macaddr = prom_get_mac(prom_get_netinfo());
375 default_mac = cfg_set_default_by_mac(macaddr);
376 if (default_mac >= 1) {
377 prom_printf("Default label was changed to macaddr label.\n");
381 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
383 /* Now, we do the initialisations stored in the config file */
384 p = cfg_get_strg(0, "init-code");
388 password = cfg_get_strg(0, "password");
390 #ifdef CONFIG_COLOR_TEXT
391 p = cfg_get_strg(0, "fgcolor");
393 DEBUG_F("fgcolor=%s\n", p);
394 fgcolor = check_color_text_ui(p);
396 prom_printf("Invalid fgcolor: \"%s\".\n", p);
399 p = cfg_get_strg(0, "bgcolor");
401 DEBUG_F("bgcolor=%s\n", p);
402 bgcolor = check_color_text_ui(p);
404 prom_printf("Invalid bgcolor: \"%s\".\n", p);
408 sprintf(temp, "%x to background-color", bgcolor);
409 prom_interpret(temp);
416 sprintf(temp, "%x to foreground-color", fgcolor);
417 prom_interpret(temp);
419 #endif /* CONFIG_COLOR_TEXT */
421 p = cfg_get_strg(0, "init-message");
423 prom_printf("%s\n", p);
425 p = cfg_get_strg(0, "message");
427 print_message_file(p);
434 file.fs->close(&file);
443 * Search for config file by MAC address, then by IP address.
444 * Basically copying pxelinux's algorithm.
445 * http://syslinux.zytor.com/pxe.php#config
447 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
449 struct bootp_packet *packet;
451 struct boot_fspec_t fspec = *orig_fspec;
452 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
456 packet = prom_get_netinfo();
461 * First, try to match on mac address with the hardware type
465 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
466 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
470 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
471 strcat(fspec.file, prom_get_mac(packet));
473 rc = load_config_file(&fspec);
478 * Now try to match on IP.
480 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
481 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
483 for (flen = strlen(fspec.file),
484 minlen = strlen(cfgpath); flen > minlen; flen--) {
485 rc = load_config_file(&fspec);
488 /* Chop one digit off the end, try again */
489 fspec.file[flen - 1] = '\0';
493 if (rc) /* modify original only on success */
494 orig_fspec->file = fspec.file;
500 void maintabfunc (void)
504 prom_printf("boot: %s", cbuff);
509 word_split(char **linep, char **paramsp)
524 while (*p != 0 && *p != ' ')
533 make_params(char *label, char *params)
536 static char buffer[2048];
541 p = cfg_get_strg(label, "literal");
553 p = cfg_get_strg(label, "root");
560 if (cfg_get_flag(label, "read-only")) {
564 if (cfg_get_flag(label, "read-write")) {
568 p = cfg_get_strg(label, "ramdisk");
570 strcpy (q, "ramdisk=");
575 p = cfg_get_strg(label, "initrd-size");
577 strcpy (q, "ramdisk_size=");
582 if (cfg_get_flag(label, "novideo")) {
583 strcpy (q, "video=ofonly");
587 p = cfg_get_strg (label, "append");
594 pause_after = cfg_get_flag (label, "pause-after");
595 p = cfg_get_strg(label, "pause-message");
604 void check_password(char *str)
608 prom_printf("\n%s", str);
609 for (i = 0; i < 3; i++) {
610 prom_printf ("\nPassword: ");
612 cmdedit ((void (*)(void)) 0, 1);
614 #ifdef USE_MD5_PASSWORDS
615 if (!strncmp (password, "$1$", 3)) {
616 if (!check_md5_password(passwdbuff, password))
619 else if (!strcmp (password, passwdbuff))
622 if (!strcmp (password, passwdbuff))
624 #endif /* USE_MD5_PASSWORDS */
627 prom_printf ("Incorrect password. Try again.");
630 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
631 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
632 " ||----w |\n || ||\n");
634 prom_interpret("reset-all");
637 int get_params(struct boot_param_t* params)
641 char defdevice_bak[1024];
644 char *imagename = 0, *label;
649 static int first = 1;
650 static char imagepath[1024];
651 static char initrdpath[1024];
652 static char manualinitrd[1024];
653 static int definitrd = 1, hasarg = 0;
656 memset(params, 0, sizeof(*params));
658 params->kernel.part = -1;
659 params->rd.part = -1;
664 if (first && !fw_reboot_cnt) {
666 imagename = bootargs;
667 word_split(&imagename, ¶ms->args);
668 timeout = DEFAULT_TIMEOUT;
670 prom_printf("Default supplied on the command line: %s ", imagename);
672 prom_printf("%s", params->args);
675 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
676 timeout = simple_strtol(q, NULL, 0);
679 /* If this is a reboot due to FW detecting CAS changes then
680 * set timeout to 1. The last kernel booted will be booted
681 * again automatically. It should seem seamless to the user
686 prom_printf("boot: ");
691 end = beg + 100 * timeout;
693 c = prom_nbgetchar();
694 } while (c == -1 && prom_getms() <= end);
698 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
704 if (c != -1 && c != '\n' && c != '\r') {
707 } else if (c >= ' ') {
710 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
713 prom_printf("%s\n", cbuff);
718 if (c == '\n' || c == '\r') {
720 if (bootoncelabel[0] != 0)
721 imagename = bootoncelabel;
722 else if (bootlastlabel[0] != 0)
723 imagename = bootlastlabel;
725 imagename = cfg_get_default();
728 prom_printf("%s", imagename);
730 prom_printf(" %s", params->args);
732 } else if (!singlekey) {
733 cmdedit(maintabfunc, 0);
735 strcpy(given_bootargs, cbuff);
736 given_bootargs_by_user = 1;
738 word_split(&imagename, ¶ms->args);
741 /* initrd setup via cmd console */
742 /* first, check if the user uses it with some label */
743 if (!strncmp(params->args, "initrd=", 7)) {
744 DEBUG_F("params->args: %s\n", params->args);
747 /* after, check if there is the 'initrd=' in the imagename string */
748 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
750 /* return the value of definitrd to 1 */
754 /* args = "initrd=blah" */
765 /* copy the string after the '=' to manualinitrd */
766 strcpy(manualinitrd, args+7);
768 prom_printf("New initrd file specified: %s\n", manualinitrd);
770 prom_printf("ERROR: no initrd specified!\n");
774 /* set imagename with the default values of the config file */
775 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
776 imagename = cfg_get_default();
778 imagename = cfg_get_default();
781 /* chrp gets this wrong, force it -- Cort */
782 if ( useconf && (!imagename || imagename[0] == 0 ))
783 imagename = cfg_get_default();
785 /* write the imagename out so it can be reused on reboot if necessary */
786 prom_set_options("boot-last-label", imagename, strlen(imagename));
789 defdevice = boot.dev;
791 strcpy(defdevice_bak,defdevice);
794 defdevice = cfg_get_strg(0, "device");
795 p = cfg_get_strg(0, "partition");
797 n = simple_strtol(p, &endp, 10);
798 if (endp != p && *endp == 0)
801 p = cfg_get_strg(0, "pause-message");
804 if (cfg_get_flag(0, "restricted"))
806 p = cfg_get_strg(imagename, "image");
810 defdevice = cfg_get_strg(label, "device");
811 if(!defdevice) defdevice=boot.dev;
812 p = cfg_get_strg(label, "partition");
814 n = simple_strtol(p, &endp, 10);
815 if (endp != p && *endp == 0)
818 if (cfg_get_flag(label, "restricted"))
821 if (params->args && password && restricted)
822 check_password ("To specify arguments for this image "
823 "you must enter the password.");
824 else if (password && !restricted)
825 check_password ("This image is restricted.");
827 params->args = make_params(label, params->args);
831 if (!strcmp (imagename, "help")) {
832 /* FIXME: defdevice shouldn't need to be reset all over the place */
833 if(!defdevice) defdevice = boot.dev;
835 "\nPress the tab key for a list of defined images.\n"
836 "The label marked with a \"*\" is is the default image, "
837 "press <return> to boot it.\n\n"
838 "To boot any other label simply type its name and press <return>.\n\n"
839 "To boot a kernel image which is not defined in the yaboot configuration \n"
840 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
841 "\"device:\" is the OpenFirmware device path to the disk the image \n"
842 "resides on, and \"partno\" is the partition number the image resides on.\n"
843 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
844 "device, if you only specify a filename you should not start it with a \",\"\n\n"
845 "To boot a alternative initrd file rather than specified in the yaboot\n"
846 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
847 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
848 "kernel image. You can, also, specify a different initrd file to any other\n"
849 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
850 "and the specified initrd file will be loaded.\n\n"
851 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
852 "its device, partno and path, on Open Firmware Prompt:\n"
853 "boot conf=device:partno,/path/to/configfile\n."
854 "To reload the config file or load a new one, use the \"conf\" command\n"
855 "on Yaboot's prompt:\n"
856 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
857 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
858 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
863 if (!strcmp (imagename, "halt")) {
865 check_password ("Restricted command.");
869 if (!strcmp (imagename, "bye")) {
871 check_password ("Restricted command.");
877 if (!strncmp (imagename, "conf", 4)) {
879 // imagename = "conf file=blah dev=bleh part=blih"
880 DEBUG_F("Loading user-specified config file: %s\n",imagename);
882 check_password ("Restricted command.");
886 // args= "file=blah dev=bleh part=blih"
887 char *args = params->args;
891 // set a pointer to the first space in args
892 char *space = strchr(args,' ');
896 char temp[1024] = "0";
898 // copy next argument to temp
899 strncpy(temp, args, space-args);
901 // parse temp and set boot arguments
902 if (!strncmp (temp, "file=", 5)){
903 DEBUG_F("conf file: %s\n", temp+5);
904 strcpy(boot.file, temp+5);
905 } else if (!strncmp (temp, "device=", 7)){
906 DEBUG_F("conf device: %s\n", temp+7);
907 strcpy(boot.dev, temp+7);
908 } else if (!strncmp (temp, "partition=", 10)){
909 DEBUG_F("conf partition: %s\n", temp+10);
910 boot.part=simple_strtol(temp+10,NULL,10);
914 // set the pointer to the next space in args;
915 // set the loop control variable
916 if (strlen(space)>1){
917 // Go to the next argument
921 if (strchr(args,' ') == NULL)
922 space = &args[strlen(args)];
924 space = strchr(args,' ');
931 prom_printf("Loading config file...\n");
932 useconf = load_config_file(&boot);
934 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
935 timeout = simple_strtol(q, NULL, 0);
937 prom_printf("Restoring default values.\n");
938 strcpy(boot.file,"");
939 strcpy(boot.dev, defdevice_bak);
944 prom_printf("Current configuration:\n");
945 prom_printf("device: %s\n", boot.dev);
947 prom_printf("partition: auto\n");
949 prom_printf("partition: %d\n", boot.part);
950 if (strlen(boot.file))
951 prom_printf("file: %s\n", boot.file);
953 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
962 if (imagename[0] == '$') {
963 /* forth command string */
965 check_password ("OpenFirmware commands are restricted.");
966 prom_interpret(imagename+1);
970 strncpy(imagepath, imagename, 1024);
972 if (!label && password)
973 check_password ("To boot a custom image you must enter the password.");
975 params->kernel = boot; /* Copy all the original paramters */
976 if (!parse_device_path(imagepath, defdevice, defpart,
977 "/vmlinux", ¶ms->kernel)) {
978 prom_printf("%s: Unable to parse\n", imagepath);
981 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
983 p = cfg_get_strg(label, "initrd");
986 /* check if user seted to use a initrd file from boot console */
987 if (!definitrd && p != manualinitrd) {
988 if (manualinitrd[0] != "/" && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
989 strcpy(initrdpath, "/");
990 strcat(initrdpath, manualinitrd);
992 strncpy(initrdpath, manualinitrd, 1024);
994 strncpy(initrdpath, p, 1024);
996 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
997 params->rd = boot; /* Copy all the original paramters */
998 if (!parse_device_path(initrdpath, defdevice, defpart,
999 "/root.bin", ¶ms->rd)) {
1000 prom_printf("%s: Unable to parse\n", imagepath);
1008 /* This is derived from quik core. To be changed to first parse the headers
1009 * doing lazy-loading, and then claim the memory before loading the kernel
1011 * We also need to add initrd support to this whole mecanism
1014 yaboot_text_ui(void)
1016 #define MAX_HEADERS 32
1018 struct boot_file_t file;
1020 static struct boot_param_t params;
1022 unsigned long initrd_size;
1023 kernel_entry_t kernel_entry;
1025 loadinfo_t loadinfo;
1026 void *initrd_more,*initrd_want;
1027 unsigned long initrd_read;
1029 loadinfo.load_loc = 0;
1035 if (get_params(¶ms))
1037 if (!params.kernel.file)
1040 prom_printf("Please wait, loading kernel...\n");
1042 memset(&file, 0, sizeof(file));
1044 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1045 && params.kernel.file[0] != '\\') {
1046 loc=(char*)malloc(strlen(params.kernel.file)+3);
1048 prom_printf ("malloc error\n");
1051 strcpy(loc,boot.file);
1052 strcat(loc,params.kernel.file);
1053 free(params.kernel.file);
1054 params.kernel.file=loc;
1056 result = open_file(¶ms.kernel, &file);
1057 if (result != FILE_ERR_OK) {
1058 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1059 prom_perror(result, params.kernel.file);
1063 /* Read the Elf e_ident, e_type and e_machine fields to
1064 * determine Elf file type
1066 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1067 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1068 file.fs->close(&file);
1069 memset(&file, 0, sizeof(file));
1073 if (is_elf32(&loadinfo)) {
1074 if (!load_elf32(&file, &loadinfo)) {
1075 file.fs->close(&file);
1076 memset(&file, 0, sizeof(file));
1079 prom_printf(" Elf32 kernel loaded...\n");
1080 } else if (is_elf64(&loadinfo)) {
1081 if (!load_elf64(&file, &loadinfo)) {
1082 file.fs->close(&file);
1083 memset(&file, 0, sizeof(file));
1086 prom_printf(" Elf64 kernel loaded...\n");
1088 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1089 file.fs->close(&file);
1090 memset(&file, 0, sizeof(file));
1093 file.fs->close(&file);
1094 memset(&file, 0, sizeof(file));
1096 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1097 * can't tell the size it will be so we claim an arbitrary amount
1100 if (flat_vmlinux && params.rd.file) {
1101 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1102 && params.kernel.file[0] != '\\')
1105 loc=(char*)malloc(strlen(params.rd.file)+3);
1107 prom_printf ("Malloc error\n");
1110 strcpy(loc,boot.file);
1111 strcat(loc,params.rd.file);
1112 free(params.rd.file);
1115 prom_printf("Loading ramdisk...\n");
1116 result = open_file(¶ms.rd, &file);
1117 if (result != FILE_ERR_OK) {
1118 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1119 prom_perror(result, params.rd.file);
1122 #define INITRD_CHUNKSIZE 0x100000
1123 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1124 if (initrd_base == (void *)-1) {
1125 prom_printf("Claim failed for initrd memory\n");
1128 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1129 if (initrd_size == 0)
1131 initrd_read = initrd_size;
1132 initrd_more = initrd_base;
1133 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1134 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1135 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1136 if (initrd_more != initrd_want) {
1137 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1141 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1142 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1143 initrd_size += initrd_read;
1146 file.fs->close(&file);
1147 memset(&file, 0, sizeof(file));
1150 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1151 initrd_base, initrd_size >> 10);
1153 prom_printf("ramdisk load failed !\n");
1158 DEBUG_F("setting kernel args to: %s\n", params.args);
1159 prom_setargs(params.args);
1160 DEBUG_F("flushing icache...");
1161 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1164 /* compute the kernel's entry point. */
1165 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1167 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1168 DEBUG_F("kernel: arg1 = %p,\n"
1169 " arg2 = 0x%08lx,\n"
1173 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1175 DEBUG_F("Entering kernel...\n");
1177 /* call the kernel with our stack. */
1178 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1186 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1189 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1191 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1192 unsigned long loadaddr;
1194 /* Read the rest of the Elf header... */
1195 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1196 prom_printf("\nCan't read Elf32 image header\n");
1200 DEBUG_F("Elf32 header:\n");
1201 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1202 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1203 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1204 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1205 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1206 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1207 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1208 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1209 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1210 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1212 loadinfo->entry = e->e_entry;
1214 if (e->e_phnum > MAX_HEADERS) {
1215 prom_printf ("Can only load kernels with one program header\n");
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 if (e->e_phnum > MAX_HEADERS) {
1353 prom_printf ("Can only load kernels with one program header\n");
1357 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1359 prom_printf ("Malloc error\n");
1363 /* Now, we read the section header */
1364 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1365 prom_printf ("Seek error\n");
1368 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1369 sizeof(Elf64_Phdr) * e->e_phnum) {
1370 prom_printf ("Read error\n");
1374 /* Scan through the program header
1375 * HACK: We must return the _memory size of the kernel image, not the
1376 * file size (because we have to leave room before other boot
1377 * infos. This code works as a side effect of the fact that
1378 * we have one section and vaddr == p_paddr
1380 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1382 for (i = 0; i < e->e_phnum; ++i, ++p) {
1383 if (p->p_type != PT_LOAD || p->p_offset == 0)
1385 if (loadinfo->memsize == 0) {
1386 loadinfo->offset = p->p_offset;
1387 loadinfo->memsize = p->p_memsz;
1388 loadinfo->filesize = p->p_filesz;
1389 loadinfo->load_loc = p->p_vaddr;
1391 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1392 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1396 if (loadinfo->memsize == 0) {
1397 prom_printf("Can't find a loadable segment !\n");
1401 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1402 /* Claim OF memory */
1403 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1405 /* Determine whether we are trying to boot a vmlinux or some
1406 * other binary image (eg, zImage). We load vmlinux's at
1407 * KERNELADDR and all other binaries at their e_entry value.
1409 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1411 loadaddr = KERNELADDR;
1414 loadaddr = e->e_entry;
1417 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1418 if (loadinfo->base == (void *)-1) {
1419 prom_printf("Claim error, can't allocate kernel memory\n");
1423 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1424 loadinfo->base, loadinfo->memsize);
1425 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1426 loadaddr, loadinfo->memsize);
1428 /* Load the program segments... */
1430 for (i = 0; i < e->e_phnum; ++i, ++p) {
1431 unsigned long offset;
1432 if (p->p_type != PT_LOAD || p->p_offset == 0)
1435 /* Now, we skip to the image itself */
1436 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1437 prom_printf ("Seek error\n");
1438 prom_release(loadinfo->base, loadinfo->memsize);
1441 offset = p->p_vaddr - loadinfo->load_loc;
1442 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1443 prom_printf ("Read failed\n");
1444 prom_release(loadinfo->base, loadinfo->memsize);
1451 /* Return success at loading the Elf64 kernel */
1461 is_elf32(loadinfo_t *loadinfo)
1463 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1465 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1466 e->e_ident[EI_MAG1] == ELFMAG1 &&
1467 e->e_ident[EI_MAG2] == ELFMAG2 &&
1468 e->e_ident[EI_MAG3] == ELFMAG3 &&
1469 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1470 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1471 e->e_type == ET_EXEC &&
1472 e->e_machine == EM_PPC);
1476 is_elf64(loadinfo_t *loadinfo)
1478 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1480 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1481 e->e_ident[EI_MAG1] == ELFMAG1 &&
1482 e->e_ident[EI_MAG2] == ELFMAG2 &&
1483 e->e_ident[EI_MAG3] == ELFMAG3 &&
1484 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1485 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1486 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1487 e->e_machine == EM_PPC64);
1493 #ifdef CONFIG_SET_COLORMAP
1494 static unsigned char default_colors[] = {
1513 prom_handle scrn = PROM_INVALID_HANDLE;
1515 /* Try Apple's mac-boot screen ihandle */
1516 result = (int)call_prom_return("interpret", 1, 2,
1517 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1518 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1520 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1522 /* Hrm... check to see if stdout is a display */
1523 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1524 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1525 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1526 DEBUG_F("got it ! stdout is a screen\n");
1529 /* Else, we try to open the package */
1530 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1531 DEBUG_F("Open screen result: %p\n", scrn);
1535 if (scrn == PROM_INVALID_HANDLE) {
1536 prom_printf("No screen device found !\n");
1540 prom_set_color(scrn, i, default_colors[i*3],
1541 default_colors[i*3+1], default_colors[i*3+2]);
1543 prom_printf("\x1b[1;37m\x1b[2;40m");
1545 for (i=0;i<16; i++) {
1546 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1547 ansi_color_table[i].index,
1548 ansi_color_table[i].value,
1549 ansi_color_table[i].name,
1550 ansi_color_table[i].name);
1551 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1552 ansi_color_table[i].index,
1553 ansi_color_table[i].value+10,
1554 ansi_color_table[i].name,
1555 ansi_color_table[i].name);
1557 prom_printf("\x1b[1;37m\x1b[2;40m");
1558 #endif /* COLOR_TEST */
1564 #endif /* CONFIG_SET_COLORMAP */
1573 char conf_path[1024];
1575 if (_machine == _MACH_Pmac)
1578 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1579 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1580 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1581 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1582 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1583 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1584 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1585 if (fw_reboot_cnt > 0L)
1586 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1588 /* If conf= specified on command line, it overrides
1589 Usage: conf=device:partition,/path/to/conffile
1590 Example: On Open Firmware Prompt, type
1591 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1593 if (!strncmp(bootargs, "conf=", 5)) {
1594 DEBUG_F("Using conf argument in Open Firmware\n");
1595 char *end = strchr(bootargs,' ');
1599 strcpy(bootdevice, bootargs + 5);
1601 DEBUG_F("Using conf=%s\n", bootdevice);
1603 /* Remove conf=xxx from bootargs */
1605 memmove(bootargs, end+1, strlen(end+1)+1);
1609 if (bootdevice[0] == 0) {
1610 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1611 DEBUG_F("boot-device = %s\n", bootdevice);
1613 if (bootdevice[0] == 0) {
1614 prom_printf("Couldn't determine boot device\n");
1618 if (bootoncelabel[0] == 0) {
1619 prom_get_options("boot-once", bootoncelabel,
1620 sizeof(bootoncelabel));
1621 if (bootoncelabel[0] != 0)
1622 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1624 prom_set_options("boot-once", NULL, 0);
1626 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1627 prom_printf("%s: Unable to parse\n", bootdevice);
1630 if (_machine == _MACH_bplan && !conf_given)
1632 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1633 boot.dev, boot.part, boot.file);
1636 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1637 boot.file = "/etc/";
1638 else if (strlen(boot.file)) {
1639 if (!strncmp(boot.file, "\\\\", 2))
1643 p = last = boot.file;
1653 if (strlen(boot.file))
1654 strcat(boot.file, "\\");
1657 strcpy(conf_path, boot.file);
1658 strcat(conf_path, CONFIG_FILE_NAME);
1659 boot.file = conf_path;
1660 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1661 boot.dev, boot.part, boot.file);
1665 * If we're doing a netboot, first look for one which matches our
1668 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1669 prom_printf("Try to netboot\n");
1670 useconf = load_my_config_file(&boot);
1674 useconf = load_config_file(&boot);
1676 prom_printf("Welcome to yaboot version " VERSION "\n");
1677 prom_printf("Enter \"help\" to get some basic usage information\n");
1679 /* I am fed up with lusers using the wrong partition type and
1680 mailing me *when* it breaks */
1682 if (_machine == _MACH_Pmac) {
1683 char *entry = cfg_get_strg(0, "ptypewarning");
1686 warn = strcmp(entry,
1687 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1689 ptype = get_part_type(boot.dev, boot.part);
1690 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1691 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1692 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1700 prom_printf("Bye.\n");
1706 * c-file-style: "k&r"