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;
182 /* OF seems to do it, but I'm not very confident */
183 memset(&__bss_start, 0, &_end - &__bss_start);
185 /* Initialize OF interface */
186 prom_init ((prom_entry) r5);
188 /* Allocate some memory for malloc'ator */
189 malloc_base = prom_claim_chunk((void *)MALLOCADDR, MALLOCSIZE, 0);
190 if (malloc_base == (void *)-1) {
191 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
192 MALLOCSIZE, MALLOCADDR);
195 malloc_init(malloc_base, MALLOCSIZE);
196 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
197 malloc_base, MALLOCSIZE);
199 /* A few useless DEBUG_F's */
200 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
201 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
203 /* ask the OF info if we're a chrp or pmac */
204 /* we need to set _machine before calling finish_device_tree */
205 root = prom_finddevice("/");
207 static char model[256];
208 if (prom_getprop(root, "CODEGEN,vendor", model, 256) > 0 &&
209 !strncmp("bplan", model, 5))
210 _machine = _MACH_bplan;
211 else if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
212 !strncmp("chrp", model, 4))
213 _machine = _MACH_chrp;
215 if (prom_getprop(root, "model", model, 256 ) > 0 &&
216 !strncmp(model, "IBM", 3))
217 _machine = _MACH_chrp;
221 DEBUG_F("Running on _machine = %d\n", _machine);
225 result = yaboot_main();
227 /* Get rid of malloc pool */
229 prom_release(malloc_base, MALLOCSIZE);
230 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
240 #ifdef CONFIG_COLOR_TEXT
242 * Validify color for text ui
245 check_color_text_ui(char *color)
248 while(ansi_color_table[i].name) {
249 if (!strcmp(color, ansi_color_table[i].name))
255 #endif /* CONFIG_COLOR_TEXT */
258 void print_message_file(char *filename)
262 char *defdev = boot.dev;
263 int defpart = boot.part;
268 struct boot_file_t file;
269 struct boot_fspec_t msgfile;
271 defdev = cfg_get_strg(0, "device");
274 p = cfg_get_strg(0, "partition");
276 n = simple_strtol(p, &endp, 10);
277 if (endp != p && *endp == 0)
281 strncpy(msgpath, filename, sizeof(msgpath));
282 msgfile = boot; /* Copy all the original paramters */
283 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
284 prom_printf("%s: Unable to parse\n", msgpath);
288 result = open_file(&msgfile, &file);
289 if (result != FILE_ERR_OK) {
290 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
291 prom_perror(result, msgfile.file);
296 msg = malloc(MESSAGE_FILE_MAX + 1);
300 memset(msg, 0, MESSAGE_FILE_MAX + 1);
302 if (file.fs->read(&file, MESSAGE_FILE_MAX, msg) <= 0)
305 prom_printf("%s", msg);
309 file.fs->close(&file);
314 /* Currently, the config file must be at the root of the filesystem.
315 * todo: recognize the full path to myself and use it to load the
316 * config file. Handle the "\\" (blessed system folder)
319 load_config_file(struct boot_fspec_t *fspec)
321 char *conf_file = NULL, *p;
322 struct boot_file_t file;
323 int sz, opened = 0, result = 0;
325 /* Allocate a buffer for the config file */
326 conf_file = malloc(CONFIG_FILE_MAX);
328 prom_printf("Can't alloc config file buffer\n");
333 result = open_file(fspec, &file);
334 if (result != FILE_ERR_OK) {
335 prom_printf("%s:%d,", fspec->dev, fspec->part);
336 prom_perror(result, fspec->file);
337 prom_printf("Can't open config file\n");
343 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
345 prom_printf("Error, can't read config file\n");
348 prom_printf("Config file read, %d bytes\n", sz);
352 file.fs->close(&file);
355 /* Call the parsing code in cfg.c */
356 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
357 prom_printf ("Syntax error or read error config\n");
362 * set the default cf_option to label that has the same MAC addr
363 * it only works if there is a label with the MAC addr on yaboot.conf
365 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
366 /* change the variable bellow to get the MAC dinamicaly */
367 char * macaddr = NULL;
370 macaddr = prom_get_mac(prom_get_netinfo());
371 default_mac = cfg_set_default_by_mac(macaddr);
372 if (default_mac >= 1) {
373 prom_printf("Default label was changed to macaddr label.\n");
377 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
379 /* Now, we do the initialisations stored in the config file */
380 p = cfg_get_strg(0, "init-code");
384 password = cfg_get_strg(0, "password");
386 #ifdef CONFIG_COLOR_TEXT
387 p = cfg_get_strg(0, "fgcolor");
389 DEBUG_F("fgcolor=%s\n", p);
390 fgcolor = check_color_text_ui(p);
392 prom_printf("Invalid fgcolor: \"%s\".\n", p);
395 p = cfg_get_strg(0, "bgcolor");
397 DEBUG_F("bgcolor=%s\n", p);
398 bgcolor = check_color_text_ui(p);
400 prom_printf("Invalid bgcolor: \"%s\".\n", p);
404 sprintf(temp, "%x to background-color", bgcolor);
405 prom_interpret(temp);
412 sprintf(temp, "%x to foreground-color", fgcolor);
413 prom_interpret(temp);
415 #endif /* CONFIG_COLOR_TEXT */
417 p = cfg_get_strg(0, "init-message");
419 prom_printf("%s\n", p);
421 p = cfg_get_strg(0, "message");
423 print_message_file(p);
430 file.fs->close(&file);
439 * Search for config file by MAC address, then by IP address.
440 * Basically copying pxelinux's algorithm.
441 * http://syslinux.zytor.com/pxe.php#config
443 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
445 struct bootp_packet *packet;
447 struct boot_fspec_t fspec = *orig_fspec;
448 char *cfgpath = (_machine == _MACH_chrp || _machine == _MACH_bplan) ? "/etc/" : "";
452 packet = prom_get_netinfo();
457 * First, try to match on mac address with the hardware type
461 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
462 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
466 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
467 strcat(fspec.file, prom_get_mac(packet));
469 rc = load_config_file(&fspec);
474 * Now try to match on IP.
476 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
477 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
479 for (flen = strlen(fspec.file),
480 minlen = strlen(cfgpath); flen > minlen; flen--) {
481 rc = load_config_file(&fspec);
484 /* Chop one digit off the end, try again */
485 fspec.file[flen - 1] = '\0';
489 if (rc) /* modify original only on success */
490 orig_fspec->file = fspec.file;
496 void maintabfunc (void)
500 prom_printf("boot: %s", cbuff);
505 word_split(char **linep, char **paramsp)
520 while (*p != 0 && *p != ' ')
529 make_params(char *label, char *params)
532 static char buffer[2048];
537 p = cfg_get_strg(label, "literal");
549 p = cfg_get_strg(label, "root");
556 if (cfg_get_flag(label, "read-only")) {
560 if (cfg_get_flag(label, "read-write")) {
564 p = cfg_get_strg(label, "ramdisk");
566 strcpy (q, "ramdisk=");
571 p = cfg_get_strg(label, "initrd-size");
573 strcpy (q, "ramdisk_size=");
578 if (cfg_get_flag(label, "novideo")) {
579 strcpy (q, "video=ofonly");
583 p = cfg_get_strg (label, "append");
590 pause_after = cfg_get_flag (label, "pause-after");
591 p = cfg_get_strg(label, "pause-message");
600 void check_password(char *str)
604 prom_printf("\n%s", str);
605 for (i = 0; i < 3; i++) {
606 prom_printf ("\nPassword: ");
608 cmdedit ((void (*)(void)) 0, 1);
610 #ifdef USE_MD5_PASSWORDS
611 if (!strncmp (password, "$1$", 3)) {
612 if (!check_md5_password(passwdbuff, password))
615 else if (!strcmp (password, passwdbuff))
618 if (!strcmp (password, passwdbuff))
620 #endif /* USE_MD5_PASSWORDS */
623 prom_printf ("Incorrect password. Try again.");
626 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
627 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
628 " ||----w |\n || ||\n");
630 prom_interpret("reset-all");
633 int get_params(struct boot_param_t* params)
637 char defdevice_bak[1024];
640 char *imagename = 0, *label;
645 static int first = 1;
646 static char imagepath[1024];
647 static char initrdpath[1024];
648 static char manualinitrd[1024];
649 static int definitrd = 1, hasarg = 0;
652 memset(params, 0, sizeof(*params));
654 params->kernel.part = -1;
655 params->rd.part = -1;
660 if (first && !fw_reboot_cnt) {
662 imagename = bootargs;
663 word_split(&imagename, ¶ms->args);
664 timeout = DEFAULT_TIMEOUT;
666 prom_printf("Default supplied on the command line: %s ", imagename);
668 prom_printf("%s", params->args);
671 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
672 timeout = simple_strtol(q, NULL, 0);
675 /* If this is a reboot due to FW detecting CAS changes then
676 * set timeout to 1. The last kernel booted will be booted
677 * again automatically. It should seem seamless to the user
682 prom_printf("boot: ");
687 end = beg + 100 * timeout;
689 c = prom_nbgetchar();
690 } while (c == -1 && prom_getms() <= end);
694 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
700 if (c != -1 && c != '\n' && c != '\r') {
703 } else if (c >= ' ') {
706 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
709 prom_printf("%s\n", cbuff);
714 if (c == '\n' || c == '\r') {
716 if (bootoncelabel[0] != 0)
717 imagename = bootoncelabel;
718 else if (bootlastlabel[0] != 0)
719 imagename = bootlastlabel;
721 imagename = cfg_get_default();
724 prom_printf("%s", imagename);
726 prom_printf(" %s", params->args);
728 } else if (!singlekey) {
729 cmdedit(maintabfunc, 0);
731 strcpy(given_bootargs, cbuff);
732 given_bootargs_by_user = 1;
734 word_split(&imagename, ¶ms->args);
737 /* initrd setup via cmd console */
738 /* first, check if the user uses it with some label */
739 if (!strncmp(params->args, "initrd=", 7)) {
740 DEBUG_F("params->args: %s\n", params->args);
743 /* after, check if there is the 'initrd=' in the imagename string */
744 if (!strncmp(imagename, "initrd=", 7) || !definitrd) {
746 /* return the value of definitrd to 1 */
750 /* args = "initrd=blah" */
761 /* copy the string after the '=' to manualinitrd */
762 strcpy(manualinitrd, args+7);
764 prom_printf("New initrd file specified: %s\n", manualinitrd);
766 prom_printf("ERROR: no initrd specified!\n");
770 /* set imagename with the default values of the config file */
771 if ((prom_get_devtype(boot.dev) == FILE_DEVICE_NET) && !hasarg)
772 imagename = cfg_get_default();
774 imagename = cfg_get_default();
777 /* chrp gets this wrong, force it -- Cort */
778 if ( useconf && (!imagename || imagename[0] == 0 ))
779 imagename = cfg_get_default();
781 /* write the imagename out so it can be reused on reboot if necessary */
782 prom_set_options("boot-last-label", imagename, strlen(imagename));
785 defdevice = boot.dev;
787 strcpy(defdevice_bak,defdevice);
790 defdevice = cfg_get_strg(0, "device");
791 p = cfg_get_strg(0, "partition");
793 n = simple_strtol(p, &endp, 10);
794 if (endp != p && *endp == 0)
797 p = cfg_get_strg(0, "pause-message");
800 if (cfg_get_flag(0, "restricted"))
802 p = cfg_get_strg(imagename, "image");
806 defdevice = cfg_get_strg(label, "device");
807 if(!defdevice) defdevice=boot.dev;
808 p = cfg_get_strg(label, "partition");
810 n = simple_strtol(p, &endp, 10);
811 if (endp != p && *endp == 0)
814 if (cfg_get_flag(label, "restricted"))
817 if (params->args && password && restricted)
818 check_password ("To specify arguments for this image "
819 "you must enter the password.");
820 else if (password && !restricted)
821 check_password ("This image is restricted.");
823 params->args = make_params(label, params->args);
827 if (!strcmp (imagename, "help")) {
828 /* FIXME: defdevice shouldn't need to be reset all over the place */
829 if(!defdevice) defdevice = boot.dev;
831 "\nPress the tab key for a list of defined images.\n"
832 "The label marked with a \"*\" is is the default image, "
833 "press <return> to boot it.\n\n"
834 "To boot any other label simply type its name and press <return>.\n\n"
835 "To boot a kernel image which is not defined in the yaboot configuration \n"
836 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
837 "\"device:\" is the OpenFirmware device path to the disk the image \n"
838 "resides on, and \"partno\" is the partition number the image resides on.\n"
839 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
840 "device, if you only specify a filename you should not start it with a \",\"\n\n"
841 "To boot a alternative initrd file rather than specified in the yaboot\n"
842 "configuration file, use the \"initrd\" command on Yaboot's prompt: \n"
843 "\"initrd=[name.img]\". This will load the \"name.img\" file after the default\n"
844 "kernel image. You can, also, specify a different initrd file to any other\n"
845 "label of the yaboot configuration file. Just type \"label initrd=[name.img]\"\n"
846 "and the specified initrd file will be loaded.\n\n"
847 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
848 "its device, partno and path, on Open Firmware Prompt:\n"
849 "boot conf=device:partno,/path/to/configfile\n."
850 "To reload the config file or load a new one, use the \"conf\" command\n"
851 "on Yaboot's prompt:\n"
852 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
853 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
854 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
859 if (!strcmp (imagename, "halt")) {
861 check_password ("Restricted command.");
865 if (!strcmp (imagename, "bye")) {
867 check_password ("Restricted command.");
873 if (!strncmp (imagename, "conf", 4)) {
875 // imagename = "conf file=blah dev=bleh part=blih"
876 DEBUG_F("Loading user-specified config file: %s\n",imagename);
878 check_password ("Restricted command.");
882 // args= "file=blah dev=bleh part=blih"
883 char *args = params->args;
887 // set a pointer to the first space in args
888 char *space = strchr(args,' ');
892 char temp[1024] = "0";
894 // copy next argument to temp
895 strncpy(temp, args, space-args);
897 // parse temp and set boot arguments
898 if (!strncmp (temp, "file=", 5)){
899 DEBUG_F("conf file: %s\n", temp+5);
900 strcpy(boot.file, temp+5);
901 } else if (!strncmp (temp, "device=", 7)){
902 DEBUG_F("conf device: %s\n", temp+7);
903 strcpy(boot.dev, temp+7);
904 } else if (!strncmp (temp, "partition=", 10)){
905 DEBUG_F("conf partition: %s\n", temp+10);
906 boot.part=simple_strtol(temp+10,NULL,10);
910 // set the pointer to the next space in args;
911 // set the loop control variable
912 if (strlen(space)>1){
913 // Go to the next argument
917 if (strchr(args,' ') == NULL)
918 space = &args[strlen(args)];
920 space = strchr(args,' ');
927 prom_printf("Loading config file...\n");
928 useconf = load_config_file(&boot);
930 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
931 timeout = simple_strtol(q, NULL, 0);
933 prom_printf("Restoring default values.\n");
934 strcpy(boot.file,"");
935 strcpy(boot.dev, defdevice_bak);
940 prom_printf("Current configuration:\n");
941 prom_printf("device: %s\n", boot.dev);
943 prom_printf("partition: auto\n");
945 prom_printf("partition: %d\n", boot.part);
946 if (strlen(boot.file))
947 prom_printf("file: %s\n", boot.file);
949 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
958 if (imagename[0] == '$') {
959 /* forth command string */
961 check_password ("OpenFirmware commands are restricted.");
962 prom_interpret(imagename+1);
966 strncpy(imagepath, imagename, 1024);
968 if (!label && password)
969 check_password ("To boot a custom image you must enter the password.");
971 params->kernel = boot; /* Copy all the original paramters */
972 if (!parse_device_path(imagepath, defdevice, defpart,
973 "/vmlinux", ¶ms->kernel)) {
974 prom_printf("%s: Unable to parse\n", imagepath);
977 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, params->kernel.part, params->kernel.file);
979 p = cfg_get_strg(label, "initrd");
982 /* check if user seted to use a initrd file from boot console */
983 if (!definitrd && p != manualinitrd) {
984 if (manualinitrd[0] != '/' && (prom_get_devtype(defdevice_bak) != FILE_DEVICE_NET)) {
985 strcpy(initrdpath, "/");
986 strcat(initrdpath, manualinitrd);
988 strncpy(initrdpath, manualinitrd, 1024);
990 strncpy(initrdpath, p, 1024);
992 DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
993 params->rd = boot; /* Copy all the original paramters */
994 if (!parse_device_path(initrdpath, defdevice, defpart,
995 "/root.bin", ¶ms->rd)) {
996 prom_printf("%s: Unable to parse\n", imagepath);
1004 /* This is derived from quik core. To be changed to first parse the headers
1005 * doing lazy-loading, and then claim the memory before loading the kernel
1007 * We also need to add initrd support to this whole mecanism
1010 yaboot_text_ui(void)
1012 struct boot_file_t file;
1014 static struct boot_param_t params;
1016 unsigned long initrd_size;
1017 kernel_entry_t kernel_entry;
1019 loadinfo_t loadinfo;
1020 void *initrd_more,*initrd_want;
1021 unsigned long initrd_read;
1023 loadinfo.load_loc = 0;
1029 if (get_params(¶ms))
1031 if (!params.kernel.file)
1034 prom_printf("Please wait, loading kernel...\n");
1036 memset(&file, 0, sizeof(file));
1038 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1039 && params.kernel.file[0] != '\\') {
1040 loc=(char*)malloc(strlen(params.kernel.file)+3);
1042 prom_printf ("malloc error\n");
1045 strcpy(loc,boot.file);
1046 strcat(loc,params.kernel.file);
1047 free(params.kernel.file);
1048 params.kernel.file=loc;
1050 result = open_file(¶ms.kernel, &file);
1051 if (result != FILE_ERR_OK) {
1052 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1053 prom_perror(result, params.kernel.file);
1057 /* Read the Elf e_ident, e_type and e_machine fields to
1058 * determine Elf file type
1060 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1061 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1062 file.fs->close(&file);
1063 memset(&file, 0, sizeof(file));
1067 if (is_elf32(&loadinfo)) {
1068 if (!load_elf32(&file, &loadinfo)) {
1069 file.fs->close(&file);
1070 memset(&file, 0, sizeof(file));
1073 prom_printf(" Elf32 kernel loaded...\n");
1074 } else if (is_elf64(&loadinfo)) {
1075 if (!load_elf64(&file, &loadinfo)) {
1076 file.fs->close(&file);
1077 memset(&file, 0, sizeof(file));
1080 prom_printf(" Elf64 kernel loaded...\n");
1082 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1083 file.fs->close(&file);
1084 memset(&file, 0, sizeof(file));
1087 file.fs->close(&file);
1088 memset(&file, 0, sizeof(file));
1090 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1091 * can't tell the size it will be so we claim an arbitrary amount
1094 if (flat_vmlinux && params.rd.file) {
1095 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1096 && params.kernel.file[0] != '\\')
1099 loc=(char*)malloc(strlen(params.rd.file)+3);
1101 prom_printf ("Malloc error\n");
1104 strcpy(loc,boot.file);
1105 strcat(loc,params.rd.file);
1106 free(params.rd.file);
1109 prom_printf("Loading ramdisk...\n");
1110 result = open_file(¶ms.rd, &file);
1111 if (result != FILE_ERR_OK) {
1112 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1113 prom_perror(result, params.rd.file);
1116 #define INITRD_CHUNKSIZE 0x100000
1117 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1118 if (initrd_base == (void *)-1) {
1119 prom_printf("Claim failed for initrd memory\n");
1122 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1123 if (initrd_size == 0)
1125 initrd_read = initrd_size;
1126 initrd_more = initrd_base;
1127 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1128 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1129 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1130 if (initrd_more != initrd_want) {
1131 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1135 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1136 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1137 initrd_size += initrd_read;
1140 file.fs->close(&file);
1141 memset(&file, 0, sizeof(file));
1144 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1145 initrd_base, initrd_size >> 10);
1147 prom_printf("ramdisk load failed !\n");
1152 DEBUG_F("setting kernel args to: %s\n", params.args);
1153 prom_setargs(params.args);
1154 DEBUG_F("flushing icache...");
1155 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1158 /* compute the kernel's entry point. */
1159 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1161 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1162 DEBUG_F("kernel: arg1 = %p,\n"
1163 " arg2 = 0x%08lx,\n"
1167 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1169 DEBUG_F("Entering kernel...\n");
1171 /* call the kernel with our stack. */
1172 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1180 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1183 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1185 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1186 unsigned long loadaddr;
1188 /* Read the rest of the Elf header... */
1189 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1190 prom_printf("\nCan't read Elf32 image header\n");
1194 DEBUG_F("Elf32 header:\n");
1195 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1196 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1197 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1198 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1199 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1200 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1201 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1202 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1203 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1204 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1206 loadinfo->entry = e->e_entry;
1208 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1210 prom_printf ("Malloc error\n");
1214 /* Now, we read the section header */
1215 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1216 prom_printf ("seek error\n");
1219 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1220 sizeof(Elf32_Phdr) * e->e_phnum) {
1221 prom_printf ("read error\n");
1225 /* Scan through the program header
1226 * HACK: We must return the _memory size of the kernel image, not the
1227 * file size (because we have to leave room before other boot
1228 * infos. This code works as a side effect of the fact that
1229 * we have one section and vaddr == p_paddr
1231 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1233 for (i = 0; i < e->e_phnum; ++i, ++p) {
1234 if (p->p_type != PT_LOAD || p->p_offset == 0)
1236 if (loadinfo->memsize == 0) {
1237 loadinfo->offset = p->p_offset;
1238 loadinfo->memsize = p->p_memsz;
1239 loadinfo->filesize = p->p_filesz;
1240 loadinfo->load_loc = p->p_vaddr;
1242 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1243 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1247 if (loadinfo->memsize == 0) {
1248 prom_printf("Can't find a loadable segment !\n");
1252 /* leave some room (1Mb) for boot infos */
1253 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1254 /* Claim OF memory */
1255 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1257 /* Determine whether we are trying to boot a vmlinux or some
1258 * other binary image (eg, zImage). We load vmlinux's at
1259 * KERNELADDR and all other binaries at their e_entry value.
1261 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1263 loadaddr = KERNELADDR;
1266 loadaddr = loadinfo->load_loc;
1269 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1270 if (loadinfo->base == (void *)-1) {
1271 prom_printf("Claim error, can't allocate kernel memory\n");
1275 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1276 loadinfo->base, loadinfo->memsize);
1277 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1278 loadaddr, loadinfo->memsize);
1280 /* Load the program segments... */
1282 for (i = 0; i < e->e_phnum; ++i, ++p) {
1283 unsigned long offset;
1284 if (p->p_type != PT_LOAD || p->p_offset == 0)
1287 /* Now, we skip to the image itself */
1288 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1289 prom_printf ("Seek error\n");
1290 prom_release(loadinfo->base, loadinfo->memsize);
1293 offset = p->p_vaddr - loadinfo->load_loc;
1294 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1295 prom_printf ("Read failed\n");
1296 prom_release(loadinfo->base, loadinfo->memsize);
1303 /* Return success at loading the Elf32 kernel */
1313 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1316 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1318 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1319 unsigned long loadaddr;
1321 /* Read the rest of the Elf header... */
1322 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1323 prom_printf("\nCan't read Elf64 image header\n");
1327 DEBUG_F("Elf64 header:\n");
1328 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1329 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1330 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1331 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1332 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1333 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1334 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1335 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1336 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1337 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1339 loadinfo->entry = e->e_entry;
1341 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1343 prom_printf ("Malloc error\n");
1347 /* Now, we read the section header */
1348 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1349 prom_printf ("Seek error\n");
1352 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1353 sizeof(Elf64_Phdr) * e->e_phnum) {
1354 prom_printf ("Read error\n");
1358 /* Scan through the program header
1359 * HACK: We must return the _memory size of the kernel image, not the
1360 * file size (because we have to leave room before other boot
1361 * infos. This code works as a side effect of the fact that
1362 * we have one section and vaddr == p_paddr
1364 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1366 for (i = 0; i < e->e_phnum; ++i, ++p) {
1367 if (p->p_type != PT_LOAD || p->p_offset == 0)
1369 if (loadinfo->memsize == 0) {
1370 loadinfo->offset = p->p_offset;
1371 loadinfo->memsize = p->p_memsz;
1372 loadinfo->filesize = p->p_filesz;
1373 loadinfo->load_loc = p->p_vaddr;
1375 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1376 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1380 if (loadinfo->memsize == 0) {
1381 prom_printf("Can't find a loadable segment !\n");
1385 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20));
1386 /* Claim OF memory */
1387 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1389 /* Determine whether we are trying to boot a vmlinux or some
1390 * other binary image (eg, zImage). We load vmlinux's at
1391 * KERNELADDR and all other binaries at their e_entry value.
1393 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1395 loadaddr = KERNELADDR;
1398 loadaddr = e->e_entry;
1401 loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0);
1402 if (loadinfo->base == (void *)-1) {
1403 prom_printf("Claim error, can't allocate kernel memory\n");
1407 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1408 loadinfo->base, loadinfo->memsize);
1409 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1410 loadaddr, loadinfo->memsize);
1412 /* Load the program segments... */
1414 for (i = 0; i < e->e_phnum; ++i, ++p) {
1415 unsigned long offset;
1416 if (p->p_type != PT_LOAD || p->p_offset == 0)
1419 /* Now, we skip to the image itself */
1420 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1421 prom_printf ("Seek error\n");
1422 prom_release(loadinfo->base, loadinfo->memsize);
1425 offset = p->p_vaddr - loadinfo->load_loc;
1426 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1427 prom_printf ("Read failed\n");
1428 prom_release(loadinfo->base, loadinfo->memsize);
1435 /* Return success at loading the Elf64 kernel */
1445 is_elf32(loadinfo_t *loadinfo)
1447 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1449 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1450 e->e_ident[EI_MAG1] == ELFMAG1 &&
1451 e->e_ident[EI_MAG2] == ELFMAG2 &&
1452 e->e_ident[EI_MAG3] == ELFMAG3 &&
1453 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1454 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1455 e->e_type == ET_EXEC &&
1456 e->e_machine == EM_PPC);
1460 is_elf64(loadinfo_t *loadinfo)
1462 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1464 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1465 e->e_ident[EI_MAG1] == ELFMAG1 &&
1466 e->e_ident[EI_MAG2] == ELFMAG2 &&
1467 e->e_ident[EI_MAG3] == ELFMAG3 &&
1468 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1469 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1470 (e->e_type == ET_EXEC || e->e_type == ET_DYN) &&
1471 e->e_machine == EM_PPC64);
1477 #ifdef CONFIG_SET_COLORMAP
1478 static unsigned char default_colors[] = {
1497 prom_handle scrn = PROM_INVALID_HANDLE;
1499 /* Try Apple's mac-boot screen ihandle */
1500 result = (int)call_prom_return("interpret", 1, 2,
1501 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1502 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1504 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1506 /* Hrm... check to see if stdout is a display */
1507 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1508 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1509 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1510 DEBUG_F("got it ! stdout is a screen\n");
1513 /* Else, we try to open the package */
1514 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1515 DEBUG_F("Open screen result: %p\n", scrn);
1519 if (scrn == PROM_INVALID_HANDLE) {
1520 prom_printf("No screen device found !\n");
1524 prom_set_color(scrn, i, default_colors[i*3],
1525 default_colors[i*3+1], default_colors[i*3+2]);
1527 prom_printf("\x1b[1;37m\x1b[2;40m");
1529 for (i=0;i<16; i++) {
1530 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1531 ansi_color_table[i].index,
1532 ansi_color_table[i].value,
1533 ansi_color_table[i].name,
1534 ansi_color_table[i].name);
1535 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1536 ansi_color_table[i].index,
1537 ansi_color_table[i].value+10,
1538 ansi_color_table[i].name,
1539 ansi_color_table[i].name);
1541 prom_printf("\x1b[1;37m\x1b[2;40m");
1542 #endif /* COLOR_TEST */
1548 #endif /* CONFIG_SET_COLORMAP */
1557 char conf_path[1024];
1559 if (_machine == _MACH_Pmac)
1562 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1563 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1564 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1565 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1566 if (prom_get_options("ibm,client-architecture-support-reboot",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 )
1567 prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ);
1568 fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10);
1569 if (fw_reboot_cnt > 0L)
1570 prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ);
1572 /* If conf= specified on command line, it overrides
1573 Usage: conf=device:partition,/path/to/conffile
1574 Example: On Open Firmware Prompt, type
1575 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1577 if (!strncmp(bootargs, "conf=", 5)) {
1578 DEBUG_F("Using conf argument in Open Firmware\n");
1579 char *end = strchr(bootargs,' ');
1583 strcpy(bootdevice, bootargs + 5);
1585 DEBUG_F("Using conf=%s\n", bootdevice);
1587 /* Remove conf=xxx from bootargs */
1589 memmove(bootargs, end+1, strlen(end+1)+1);
1593 if (bootdevice[0] == 0) {
1594 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1595 DEBUG_F("boot-device = %s\n", bootdevice);
1597 if (bootdevice[0] == 0) {
1598 prom_printf("Couldn't determine boot device\n");
1602 if (bootoncelabel[0] == 0) {
1603 prom_get_options("boot-once", bootoncelabel,
1604 sizeof(bootoncelabel));
1605 if (bootoncelabel[0] != 0)
1606 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1608 prom_set_options("boot-once", NULL, 0);
1610 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1611 prom_printf("%s: Unable to parse\n", bootdevice);
1614 if (_machine == _MACH_bplan && !conf_given)
1616 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1617 boot.dev, boot.part, boot.file);
1620 if (_machine == _MACH_chrp || _machine == _MACH_bplan)
1621 boot.file = "/etc/";
1622 else if (strlen(boot.file)) {
1623 if (!strncmp(boot.file, "\\\\", 2))
1627 p = last = boot.file;
1637 if (strlen(boot.file))
1638 strcat(boot.file, "\\");
1641 strcpy(conf_path, boot.file);
1642 strcat(conf_path, CONFIG_FILE_NAME);
1643 boot.file = conf_path;
1644 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1645 boot.dev, boot.part, boot.file);
1649 * If we're doing a netboot, first look for one which matches our
1652 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1653 prom_printf("Try to netboot\n");
1654 useconf = load_my_config_file(&boot);
1658 useconf = load_config_file(&boot);
1660 prom_printf("Welcome to yaboot version " VERSION "\n");
1661 prom_printf("Enter \"help\" to get some basic usage information\n");
1663 /* I am fed up with lusers using the wrong partition type and
1664 mailing me *when* it breaks */
1666 if (_machine == _MACH_Pmac) {
1667 char *entry = cfg_get_strg(0, "ptypewarning");
1670 warn = strcmp(entry,
1671 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1673 ptype = get_part_type(boot.dev, boot.part);
1674 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1675 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1676 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1684 prom_printf("Bye.\n");
1690 * c-file-style: "k&r"