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 #ifdef USE_MD5_PASSWORDS
63 #endif /* USE_MD5_PASSWORDS */
65 /* align addr on a size boundry - adjust address up if needed -- Cort */
66 #define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1)))
68 /* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at.
69 * These are used to determine whether we are booting a vmlinux, in
70 * which case, it will be loaded at KERNELADDR. Otherwise (eg zImage),
71 * we load the binary where it was linked at (ie, e_entry field in
74 #define KERNEL_LINK_ADDR_PPC32 0xC0000000UL
75 #define KERNEL_LINK_ADDR_PPC64 0xC000000000000000ULL
83 unsigned long memsize;
84 unsigned long filesize;
86 unsigned long load_loc;
90 typedef void (*kernel_entry_t)( void *,
96 /* Imported functions */
97 extern unsigned long reloc_offset(void);
98 extern long flush_icache_range(unsigned long start, unsigned long stop);
100 /* Exported functions */
101 int yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5);
103 /* Local functions */
104 static int yaboot_main(void);
105 static int is_elf32(loadinfo_t *loadinfo);
106 static int is_elf64(loadinfo_t *loadinfo);
107 static int load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo);
108 static int load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo);
109 static void setup_display(void);
111 /* Locals & globals */
114 char bootdevice[BOOTDEVSZ];
115 char bootoncelabel[1024];
117 char *password = NULL;
118 struct boot_fspec_t boot;
119 int _machine = _MACH_Pmac;
122 #ifdef CONFIG_COLOR_TEXT
124 /* Color values for text ui */
125 static struct ansi_color_t {
129 } ansi_color_table[] = {
137 { "light-gray", 0, 37 },
138 { "dark-gray", 1, 30 },
139 { "light-blue", 1, 31 },
140 { "light-green", 1, 32 },
141 { "light-cyan", 1, 33 },
142 { "light-red", 1, 34 },
143 { "light-purple", 1, 35 },
149 /* Default colors for text ui */
152 #endif /* CONFIG_COLOR_TEXT */
156 static int test_data = 0;
158 static int pause_after;
159 static char *pause_message = "Type go<return> to continue.\n";
160 static char given_bootargs[1024];
161 static int given_bootargs_by_user = 0;
163 extern unsigned char linux_logo_red[];
164 extern unsigned char linux_logo_green[];
165 extern unsigned char linux_logo_blue[];
167 #define DEFAULT_TIMEOUT -1
169 /* Entry, currently called directly by crt0 (bss not inited) */
171 extern char* __bss_start;
174 static struct first_info *quik_fip = NULL;
177 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
180 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 /* Check for quik first stage bootloader (but I don't think we are
187 * compatible with it anyway, I'll look into backporting to older OF
190 if (r5 == 0xdeadbeef) {
192 quik_fip = (struct first_info *)r4;
195 /* Initialize OF interface */
196 prom_init ((prom_entry) r5);
198 /* Allocate some memory for malloc'ator */
199 malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
200 if (malloc_base == (void *)-1) {
201 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
202 MALLOCSIZE, MALLOCADDR);
205 malloc_init(malloc_base, MALLOCSIZE);
206 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
207 malloc_base, MALLOCSIZE);
209 /* A few useless DEBUG_F's */
210 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
211 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
212 DEBUG_F("test_data : %d (should be 0)\n", test_data);
213 DEBUG_F("&test_data : %p\n", &test_data);
214 DEBUG_F("&test_bss : %p\n", &test_bss);
215 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
217 /* ask the OF info if we're a chrp or pmac */
218 /* we need to set _machine before calling finish_device_tree */
219 root = prom_finddevice("/");
221 static char model[256];
222 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
223 !strncmp("chrp", model, 4))
224 _machine = _MACH_chrp;
226 if (prom_getprop(root, "model", model, 256 ) > 0 &&
227 !strncmp(model, "IBM", 3))
228 _machine = _MACH_chrp;
232 DEBUG_F("Running on _machine = %d\n", _machine);
236 result = yaboot_main();
238 /* Get rid of malloc pool */
240 prom_release(malloc_base, MALLOCSIZE);
241 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
251 #ifdef CONFIG_COLOR_TEXT
253 * Validify color for text ui
256 check_color_text_ui(char *color)
259 while(ansi_color_table[i].name) {
260 if (!strcmp(color, ansi_color_table[i].name))
266 #endif /* CONFIG_COLOR_TEXT */
269 void print_message_file(char *filename)
273 char *defdev = boot.dev;
274 int defpart = boot.part;
279 struct boot_file_t file;
280 struct boot_fspec_t msgfile;
282 defdev = cfg_get_strg(0, "device");
285 p = cfg_get_strg(0, "partition");
287 n = simple_strtol(p, &endp, 10);
288 if (endp != p && *endp == 0)
292 strncpy(msgpath, filename, sizeof(msgpath));
293 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
294 prom_printf("%s: Unable to parse\n", msgpath);
298 result = open_file(&msgfile, &file);
299 if (result != FILE_ERR_OK) {
300 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
301 prom_perror(result, msgfile.file);
310 memset(msg, 0, 2001);
312 if (file.fs->read(&file, 2000, msg) <= 0)
315 prom_printf("%s", msg);
319 file.fs->close(&file);
324 /* Currently, the config file must be at the root of the filesystem.
325 * todo: recognize the full path to myself and use it to load the
326 * config file. Handle the "\\" (blessed system folder)
329 load_config_file(struct boot_fspec_t *fspec)
331 char *conf_file = NULL, *p;
332 struct boot_file_t file;
333 int sz, opened = 0, result = 0;
335 /* Allocate a buffer for the config file */
336 conf_file = malloc(CONFIG_FILE_MAX);
338 prom_printf("Can't alloc config file buffer\n");
343 result = open_file(fspec, &file);
344 if (result != FILE_ERR_OK) {
345 prom_printf("%s:%d,", fspec->dev, fspec->part);
346 prom_perror(result, fspec->file);
347 prom_printf("Can't open config file\n");
353 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
355 prom_printf("Error, can't read config file\n");
358 prom_printf("Config file read, %d bytes\n", sz);
362 file.fs->close(&file);
365 /* Call the parsing code in cfg.c */
366 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
367 prom_printf ("Syntax error or read error config\n");
372 * set the default cf_option to label that has the same MAC addr
373 * it only works if there is a label with the MAC addr on yaboot.conf
375 if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) {
376 /* change the variable bellow to get the MAC dinamicaly */
377 char * macaddr = NULL;
380 macaddr = prom_get_mac(prom_get_netinfo());
381 default_mac = cfg_set_default_by_mac(macaddr);
382 if (default_mac >= 1) {
383 prom_printf("Default label was changed to macaddr label.\n");
387 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
389 /* Now, we do the initialisations stored in the config file */
390 p = cfg_get_strg(0, "init-code");
394 password = cfg_get_strg(0, "password");
396 #ifdef CONFIG_COLOR_TEXT
397 p = cfg_get_strg(0, "fgcolor");
399 DEBUG_F("fgcolor=%s\n", p);
400 fgcolor = check_color_text_ui(p);
402 prom_printf("Invalid fgcolor: \"%s\".\n", p);
405 p = cfg_get_strg(0, "bgcolor");
407 DEBUG_F("bgcolor=%s\n", p);
408 bgcolor = check_color_text_ui(p);
410 prom_printf("Invalid bgcolor: \"%s\".\n", p);
414 sprintf(temp, "%x to background-color", bgcolor);
415 prom_interpret(temp);
422 sprintf(temp, "%x to foreground-color", fgcolor);
423 prom_interpret(temp);
425 #endif /* CONFIG_COLOR_TEXT */
427 p = cfg_get_strg(0, "init-message");
429 prom_printf("%s\n", p);
431 p = cfg_get_strg(0, "message");
433 print_message_file(p);
440 file.fs->close(&file);
449 * Search for config file by MAC address, then by IP address.
450 * Basically copying pxelinux's algorithm.
451 * http://syslinux.zytor.com/pxe.php#config
453 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
455 struct bootp_packet *packet;
457 struct boot_fspec_t fspec = *orig_fspec;
458 char *cfgpath = (_machine == _MACH_chrp) ? "/etc/" : "";
462 packet = prom_get_netinfo();
465 * First, try to match on mac address with the hardware type
469 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
470 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
474 sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype);
475 strcat(fspec.file, prom_get_mac(packet));
477 rc = load_config_file(&fspec);
482 * Now try to match on IP.
484 /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */
485 sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet));
487 for (flen = strlen(fspec.file),
488 minlen = strlen(cfgpath); flen > minlen; flen--) {
489 rc = load_config_file(&fspec);
492 /* Chop one digit off the end, try again */
493 fspec.file[flen - 1] = '\0';
497 if (rc) /* modify original only on success */
498 orig_fspec->file = fspec.file;
504 void maintabfunc (void)
508 prom_printf("boot: %s", cbuff);
513 word_split(char **linep, char **paramsp)
528 while (*p != 0 && *p != ' ')
537 make_params(char *label, char *params)
540 static char buffer[2048];
545 p = cfg_get_strg(label, "literal");
557 p = cfg_get_strg(label, "root");
564 if (cfg_get_flag(label, "read-only")) {
568 if (cfg_get_flag(label, "read-write")) {
572 p = cfg_get_strg(label, "ramdisk");
574 strcpy (q, "ramdisk=");
579 p = cfg_get_strg(label, "initrd-size");
581 strcpy (q, "ramdisk_size=");
586 if (cfg_get_flag(label, "novideo")) {
587 strcpy (q, "video=ofonly");
591 p = cfg_get_strg (label, "append");
598 pause_after = cfg_get_flag (label, "pause-after");
599 p = cfg_get_strg(label, "pause-message");
608 void check_password(char *str)
612 prom_printf("\n%s", str);
613 for (i = 0; i < 3; i++) {
614 prom_printf ("\nPassword: ");
616 cmdedit ((void (*)(void)) 0, 1);
618 #ifdef USE_MD5_PASSWORDS
619 if (!strncmp (password, "$1$", 3)) {
620 if (!check_md5_password(passwdbuff, password))
623 else if (!strcmp (password, passwdbuff))
626 if (!strcmp (password, passwdbuff))
628 #endif /* USE_MD5_PASSWORDS */
631 prom_printf ("Incorrect password. Try again.");
634 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
635 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
636 " ||----w |\n || ||\n");
638 prom_interpret("reset-all");
641 int get_params(struct boot_param_t* params)
645 char defdevice_bak[1024];
648 char *imagename = 0, *label;
653 static int first = 1;
654 static char imagepath[1024];
655 static char initrdpath[1024];
656 static char sysmappath[1024];
659 memset(params, 0, sizeof(*params));
661 params->kernel.part = -1;
662 params->rd.part = -1;
663 params->sysmap.part = -1;
670 imagename = bootargs;
671 word_split(&imagename, ¶ms->args);
672 timeout = DEFAULT_TIMEOUT;
674 prom_printf("Default supplied on the command line: %s ", imagename);
676 prom_printf("%s", params->args);
679 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
680 timeout = simple_strtol(q, NULL, 0);
683 prom_printf("boot: ");
688 end = beg + 100 * timeout;
690 c = prom_nbgetchar();
691 } while (c == -1 && prom_getms() <= end);
695 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
701 if (c != -1 && c != '\n' && c != '\r') {
704 } else if (c >= ' ') {
707 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
710 prom_printf("%s\n", cbuff);
715 if (c == '\n' || c == '\r') {
717 if (bootoncelabel[0] != 0)
718 imagename = bootoncelabel;
720 imagename = cfg_get_default();
723 prom_printf("%s", imagename);
725 prom_printf(" %s", params->args);
727 } else if (!singlekey) {
728 cmdedit(maintabfunc, 0);
730 strcpy(given_bootargs, cbuff);
731 given_bootargs_by_user = 1;
733 word_split(&imagename, ¶ms->args);
736 /* chrp gets this wrong, force it -- Cort */
737 if ( useconf && (!imagename || imagename[0] == 0 ))
738 imagename = cfg_get_default();
741 defdevice = boot.dev;
743 strcpy(defdevice_bak,defdevice);
746 defdevice = cfg_get_strg(0, "device");
747 p = cfg_get_strg(0, "partition");
749 n = simple_strtol(p, &endp, 10);
750 if (endp != p && *endp == 0)
753 p = cfg_get_strg(0, "pause-message");
756 if (cfg_get_flag(0, "restricted"))
758 p = cfg_get_strg(imagename, "image");
762 defdevice = cfg_get_strg(label, "device");
763 if(!defdevice) defdevice=boot.dev;
764 p = cfg_get_strg(label, "partition");
766 n = simple_strtol(p, &endp, 10);
767 if (endp != p && *endp == 0)
770 if (cfg_get_flag(label, "restricted"))
773 if (params->args && password && restricted)
774 check_password ("To specify arguments for this image "
775 "you must enter the password.");
776 else if (password && !restricted)
777 check_password ("This image is restricted.");
779 params->args = make_params(label, params->args);
783 if (!strcmp (imagename, "help")) {
784 /* FIXME: defdevice shouldn't need to be reset all over the place */
785 if(!defdevice) defdevice = boot.dev;
787 "\nPress the tab key for a list of defined images.\n"
788 "The label marked with a \"*\" is is the default image, "
789 "press <return> to boot it.\n\n"
790 "To boot any other label simply type its name and press <return>.\n\n"
791 "To boot a kernel image which is not defined in the yaboot configuration \n"
792 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
793 "\"device:\" is the OpenFirmware device path to the disk the image \n"
794 "resides on, and \"partno\" is the partition number the image resides on.\n"
795 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
796 "device, if you only specify a filename you should not start it with a \",\"\n\n"
797 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
798 "its device, partno and path, on Open Firmware Prompt:\n"
799 "boot conf=device:partno,/path/to/configfile\n."
800 "To reload the config file or load a new one, use the \"conf\" command\n"
801 "on Yaboot's prompt:\n"
802 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
803 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
804 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
809 if (!strcmp (imagename, "halt")) {
811 check_password ("Restricted command.");
815 if (!strcmp (imagename, "bye")) {
817 check_password ("Restricted command.");
823 if (!strncmp (imagename, "conf", 4)) {
825 // imagename = "conf file=blah dev=bleh part=blih"
826 DEBUG_F("Loading user-specified config file: %s\n",imagename);
828 check_password ("Restricted command.");
832 // args= "file=blah dev=bleh part=blih"
833 char *args = params->args;
837 // set a pointer to the first space in args
838 char *space = strchr(args,' ');
842 char temp[1024] = "0";
844 // copy next argument to temp
845 strncpy(temp, args, space-args);
847 // parse temp and set boot arguments
848 if (!strncmp (temp, "file=", 5)){
849 DEBUG_F("conf file: %s\n", temp+5);
850 strcpy(boot.file, temp+5);
851 } else if (!strncmp (temp, "device=", 7)){
852 DEBUG_F("conf device: %s\n", temp+7);
853 strcpy(boot.dev, temp+7);
854 } else if (!strncmp (temp, "partition=", 10)){
855 DEBUG_F("conf partition: %s\n", temp+10);
856 boot.part=simple_strtol(temp+10,NULL,10);
860 // set the pointer to the next space in args;
861 // set the loop control variable
862 if (strlen(space)>1){
863 // Go to the next argument
867 if (strchr(args,' ') == NULL)
868 space = &args[strlen(args)];
870 space = strchr(args,' ');
877 prom_printf("Loading config file...\n");
878 useconf = load_config_file(&boot);
880 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
881 timeout = simple_strtol(q, NULL, 0);
883 prom_printf("Restoring default values.\n");
884 strcpy(boot.file,"");
885 strcpy(boot.dev, defdevice_bak);
890 prom_printf("Current configuration:\n");
891 prom_printf("device: %s\n", boot.dev);
893 prom_printf("partition: auto\n");
895 prom_printf("partition: %d\n", boot.part);
896 if (strlen(boot.file))
897 prom_printf("file: %s\n", boot.file);
899 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
908 if (imagename[0] == '$') {
909 /* forth command string */
911 check_password ("OpenFirmware commands are restricted.");
912 prom_interpret(imagename+1);
916 strncpy(imagepath, imagename, 1024);
918 if (!label && password)
919 check_password ("To boot a custom image you must enter the password.");
921 if (!parse_device_path(imagepath, defdevice, defpart,
922 "/vmlinux", ¶ms->kernel)) {
923 prom_printf("%s: Unable to parse\n", imagepath);
926 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
927 params->kernel.part, params->kernel.file);
930 p = cfg_get_strg(label, "initrd");
932 DEBUG_F("Parsing initrd path <%s>\n", p);
933 strncpy(initrdpath, p, 1024);
934 if (!parse_device_path(initrdpath, defdevice, defpart,
935 "/root.bin", ¶ms->rd)) {
936 prom_printf("%s: Unable to parse\n", imagepath);
940 p = cfg_get_strg(label, "sysmap");
942 DEBUG_F("Parsing sysmap path <%s>\n", p);
943 strncpy(sysmappath, p, 1024);
944 if (!parse_device_path(sysmappath, defdevice, defpart,
945 "/boot/System.map", ¶ms->sysmap)) {
946 prom_printf("%s: Unable to parse\n", imagepath);
954 /* This is derived from quik core. To be changed to first parse the headers
955 * doing lazy-loading, and then claim the memory before loading the kernel
957 * We also need to add initrd support to this whole mecanism
962 #define MAX_HEADERS 32
964 struct boot_file_t file;
966 static struct boot_param_t params;
968 unsigned long initrd_size;
970 unsigned long sysmap_size;
971 kernel_entry_t kernel_entry;
972 struct bi_record* birec;
975 void *initrd_more,*initrd_want;
976 unsigned long initrd_read;
978 loadinfo.load_loc = 0;
986 if (get_params(¶ms))
988 if (!params.kernel.file)
991 prom_printf("Please wait, loading kernel...\n");
993 memset(&file, 0, sizeof(file));
995 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
996 && params.kernel.file[0] != '\\') {
997 loc=(char*)malloc(strlen(params.kernel.file)+3);
999 prom_printf ("malloc error\n");
1002 strcpy(loc,boot.file);
1003 strcat(loc,params.kernel.file);
1004 free(params.kernel.file);
1005 params.kernel.file=loc;
1007 result = open_file(¶ms.kernel, &file);
1008 if (result != FILE_ERR_OK) {
1009 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1010 prom_perror(result, params.kernel.file);
1014 /* Read the Elf e_ident, e_type and e_machine fields to
1015 * determine Elf file type
1017 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1018 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1019 file.fs->close(&file);
1020 memset(&file, 0, sizeof(file));
1024 if (is_elf32(&loadinfo)) {
1025 if (!load_elf32(&file, &loadinfo)) {
1026 file.fs->close(&file);
1027 memset(&file, 0, sizeof(file));
1030 prom_printf(" Elf32 kernel loaded...\n");
1031 } else if (is_elf64(&loadinfo)) {
1032 if (!load_elf64(&file, &loadinfo)) {
1033 file.fs->close(&file);
1034 memset(&file, 0, sizeof(file));
1037 prom_printf(" Elf64 kernel loaded...\n");
1039 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1040 file.fs->close(&file);
1041 memset(&file, 0, sizeof(file));
1044 file.fs->close(&file);
1045 memset(&file, 0, sizeof(file));
1047 /* If sysmap, load it (only if booting a vmlinux).
1049 if (flat_vmlinux && params.sysmap.file) {
1050 prom_printf("Loading System.map ...\n");
1051 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1052 && params.sysmap.file[0] != '\\') {
1054 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1056 prom_printf ("malloc error\n");
1059 strcpy(loc,boot.file);
1060 strcat(loc,params.sysmap.file);
1061 free(params.sysmap.file);
1062 params.sysmap.file=loc;
1065 result = open_file(¶ms.sysmap, &file);
1066 if (result != FILE_ERR_OK) {
1067 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1068 prom_perror(result, params.sysmap.file);
1071 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1072 if (sysmap_base == (void *)-1) {
1073 prom_printf("Claim failed for sysmap memory\n");
1077 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1078 if (sysmap_size == 0)
1081 ((char *)sysmap_base)[sysmap_size++] = 0;
1083 file.fs->close(&file);
1084 memset(&file, 0, sizeof(file));
1087 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1088 sysmap_base, sysmap_size >> 10);
1089 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1091 prom_printf("System.map load failed !\n");
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);
1166 * Fill new boot infos (only if booting a vmlinux).
1168 * The birec is low on memory, probably inside the malloc pool,
1169 * so we don't write it earlier. At this point, we should not
1170 * use anything coming from the malloc pool.
1172 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1174 /* We make sure it's mapped. We map only 64k for now, it's
1175 * plenty enough we don't claim since this precise memory
1176 * range may already be claimed by the malloc pool.
1178 prom_map (birec, birec, 0x10000);
1179 DEBUG_F("birec at %p\n", birec);
1182 birec->tag = BI_FIRST;
1183 birec->size = sizeof(struct bi_record);
1184 birec = (struct bi_record *)((ulong)birec + birec->size);
1186 birec->tag = BI_BOOTLOADER_ID;
1187 sprintf( (char *)birec->data, "yaboot");
1188 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1189 birec = (struct bi_record *)((ulong)birec + birec->size);
1191 birec->tag = BI_MACHTYPE;
1192 birec->data[0] = _machine;
1193 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1194 birec = (struct bi_record *)((ulong)birec + birec->size);
1197 birec->tag = BI_SYSMAP;
1198 birec->data[0] = (ulong)sysmap_base;
1199 birec->data[1] = sysmap_size;
1200 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1201 birec = (struct bi_record *)((ulong)birec + birec->size);
1203 birec->tag = BI_LAST;
1204 birec->size = sizeof(struct bi_record);
1205 birec = (struct bi_record *)((ulong)birec + birec->size);
1208 /* compute the kernel's entry point. */
1209 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1211 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1212 DEBUG_F("kernel: arg1 = %p,\n"
1213 " arg2 = 0x%08lx,\n"
1217 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1219 DEBUG_F("Entering kernel...\n");
1221 /* call the kernel with our stack. */
1222 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1230 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1233 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1235 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1236 unsigned long addr, loadaddr;
1238 /* Read the rest of the Elf header... */
1239 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1240 prom_printf("\nCan't read Elf32 image header\n");
1244 DEBUG_F("Elf32 header:\n");
1245 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1246 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1247 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1248 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1249 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1250 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1251 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1252 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1253 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1254 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1256 loadinfo->entry = e->e_entry;
1258 if (e->e_phnum > MAX_HEADERS) {
1259 prom_printf ("Can only load kernels with one program header\n");
1263 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1265 prom_printf ("Malloc error\n");
1269 /* Now, we read the section header */
1270 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1271 prom_printf ("seek error\n");
1274 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1275 sizeof(Elf32_Phdr) * e->e_phnum) {
1276 prom_printf ("read error\n");
1280 /* Scan through the program header
1281 * HACK: We must return the _memory size of the kernel image, not the
1282 * file size (because we have to leave room before other boot
1283 * infos. This code works as a side effect of the fact that
1284 * we have one section and vaddr == p_paddr
1286 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1288 for (i = 0; i < e->e_phnum; ++i, ++p) {
1289 if (p->p_type != PT_LOAD || p->p_offset == 0)
1291 if (loadinfo->memsize == 0) {
1292 loadinfo->offset = p->p_offset;
1293 loadinfo->memsize = p->p_memsz;
1294 loadinfo->filesize = p->p_filesz;
1295 loadinfo->load_loc = p->p_vaddr;
1297 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1298 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1302 if (loadinfo->memsize == 0) {
1303 prom_printf("Can't find a loadable segment !\n");
1307 /* leave some room (1Mb) for boot infos */
1308 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1309 /* Claim OF memory */
1310 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1312 /* Determine whether we are trying to boot a vmlinux or some
1313 * other binary image (eg, zImage). We load vmlinux's at
1314 * KERNELADDR and all other binaries at their e_entry value.
1316 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1318 loadaddr = KERNELADDR;
1321 loadaddr = loadinfo->load_loc;
1324 /* On some systems, loadaddr may already be claimed, so try some
1325 * other nearby addresses before giving up.
1327 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1328 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1329 if (loadinfo->base != (void *)-1) break;
1331 if (loadinfo->base == (void *)-1) {
1332 prom_printf("Claim error, can't allocate kernel memory\n");
1336 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1337 loadinfo->base, loadinfo->memsize);
1338 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1339 loadaddr, loadinfo->memsize);
1341 /* Load the program segments... */
1343 for (i = 0; i < e->e_phnum; ++i, ++p) {
1344 unsigned long offset;
1345 if (p->p_type != PT_LOAD || p->p_offset == 0)
1348 /* Now, we skip to the image itself */
1349 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1350 prom_printf ("Seek error\n");
1351 prom_release(loadinfo->base, loadinfo->memsize);
1354 offset = p->p_vaddr - loadinfo->load_loc;
1355 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1356 prom_printf ("Read failed\n");
1357 prom_release(loadinfo->base, loadinfo->memsize);
1364 /* Return success at loading the Elf32 kernel */
1374 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1377 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1379 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1380 unsigned long addr, loadaddr;
1382 /* Read the rest of the Elf header... */
1383 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1384 prom_printf("\nCan't read Elf64 image header\n");
1388 DEBUG_F("Elf64 header:\n");
1389 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1390 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1391 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1392 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1393 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1394 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1395 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1396 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1397 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1398 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1400 loadinfo->entry = e->e_entry;
1402 if (e->e_phnum > MAX_HEADERS) {
1403 prom_printf ("Can only load kernels with one program header\n");
1407 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1409 prom_printf ("Malloc error\n");
1413 /* Now, we read the section header */
1414 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1415 prom_printf ("Seek error\n");
1418 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1419 sizeof(Elf64_Phdr) * e->e_phnum) {
1420 prom_printf ("Read error\n");
1424 /* Scan through the program header
1425 * HACK: We must return the _memory size of the kernel image, not the
1426 * file size (because we have to leave room before other boot
1427 * infos. This code works as a side effect of the fact that
1428 * we have one section and vaddr == p_paddr
1430 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1432 for (i = 0; i < e->e_phnum; ++i, ++p) {
1433 if (p->p_type != PT_LOAD || p->p_offset == 0)
1435 if (loadinfo->memsize == 0) {
1436 loadinfo->offset = p->p_offset;
1437 loadinfo->memsize = p->p_memsz;
1438 loadinfo->filesize = p->p_filesz;
1439 loadinfo->load_loc = p->p_vaddr;
1441 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1442 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1446 if (loadinfo->memsize == 0) {
1447 prom_printf("Can't find a loadable segment !\n");
1451 /* leave some room (1Mb) for boot infos */
1452 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1453 /* Claim OF memory */
1454 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1456 /* Determine whether we are trying to boot a vmlinux or some
1457 * other binary image (eg, zImage). We load vmlinux's at
1458 * KERNELADDR and all other binaries at their e_entry value.
1460 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1462 loadaddr = KERNELADDR;
1465 loadaddr = e->e_entry;
1468 /* On some systems, loadaddr may already be claimed, so try some
1469 * other nearby addresses before giving up.
1471 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1472 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1473 if (loadinfo->base != (void *)-1) break;
1475 if (loadinfo->base == (void *)-1) {
1476 prom_printf("Claim error, can't allocate kernel memory\n");
1480 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1481 loadinfo->base, loadinfo->memsize);
1482 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1483 loadaddr, loadinfo->memsize);
1485 /* Load the program segments... */
1487 for (i = 0; i < e->e_phnum; ++i, ++p) {
1488 unsigned long offset;
1489 if (p->p_type != PT_LOAD || p->p_offset == 0)
1492 /* Now, we skip to the image itself */
1493 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1494 prom_printf ("Seek error\n");
1495 prom_release(loadinfo->base, loadinfo->memsize);
1498 offset = p->p_vaddr - loadinfo->load_loc;
1499 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1500 prom_printf ("Read failed\n");
1501 prom_release(loadinfo->base, loadinfo->memsize);
1508 /* Return success at loading the Elf64 kernel */
1518 is_elf32(loadinfo_t *loadinfo)
1520 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1522 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1523 e->e_ident[EI_MAG1] == ELFMAG1 &&
1524 e->e_ident[EI_MAG2] == ELFMAG2 &&
1525 e->e_ident[EI_MAG3] == ELFMAG3 &&
1526 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1527 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1528 e->e_type == ET_EXEC &&
1529 e->e_machine == EM_PPC);
1533 is_elf64(loadinfo_t *loadinfo)
1535 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1537 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1538 e->e_ident[EI_MAG1] == ELFMAG1 &&
1539 e->e_ident[EI_MAG2] == ELFMAG2 &&
1540 e->e_ident[EI_MAG3] == ELFMAG3 &&
1541 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1542 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1543 e->e_type == ET_EXEC &&
1544 e->e_machine == EM_PPC64);
1550 #ifdef CONFIG_SET_COLORMAP
1551 static unsigned char default_colors[] = {
1570 prom_handle scrn = PROM_INVALID_HANDLE;
1572 /* Try Apple's mac-boot screen ihandle */
1573 result = (int)call_prom_return("interpret", 1, 2,
1574 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1575 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1577 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1579 /* Hrm... check to see if stdout is a display */
1580 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1581 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1582 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1583 DEBUG_F("got it ! stdout is a screen\n");
1586 /* Else, we try to open the package */
1587 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1588 DEBUG_F("Open screen result: %p\n", scrn);
1592 if (scrn == PROM_INVALID_HANDLE) {
1593 prom_printf("No screen device found !/n");
1597 prom_set_color(scrn, i, default_colors[i*3],
1598 default_colors[i*3+1], default_colors[i*3+2]);
1600 prom_printf("\x1b[1;37m\x1b[2;40m");
1602 for (i=0;i<16; i++) {
1603 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1604 ansi_color_table[i].index,
1605 ansi_color_table[i].value,
1606 ansi_color_table[i].name,
1607 ansi_color_table[i].name);
1608 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1609 ansi_color_table[i].index,
1610 ansi_color_table[i].value+10,
1611 ansi_color_table[i].name,
1612 ansi_color_table[i].name);
1614 prom_printf("\x1b[1;37m\x1b[2;40m");
1615 #endif /* COLOR_TEST */
1621 #endif /* CONFIG_SET_COLORMAP */
1629 char conf_path[1024];
1631 if (_machine == _MACH_Pmac)
1634 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1635 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1636 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1637 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1639 /* If conf= specified on command line, it overrides
1640 Usage: conf=device:partition,/path/to/conffile
1641 Example: On Open Firmware Prompt, type
1642 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1644 if (!strncmp(bootargs, "conf=", 5)) {
1645 DEBUG_F("Using conf argument in Open Firmware\n");
1646 char *end = strchr(bootargs,' ');
1650 strcpy(bootdevice, bootargs + 5);
1652 DEBUG_F("Using conf=%s\n", bootdevice);
1654 /* Remove conf=xxx from bootargs */
1656 memmove(bootargs, end+1, strlen(end+1)+1);
1660 if (bootdevice[0] == 0) {
1661 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1662 DEBUG_F("boot-device = %s\n", bootdevice);
1664 if (bootdevice[0] == 0) {
1665 prom_printf("Couldn't determine boot device\n");
1669 if (bootoncelabel[0] == 0) {
1670 prom_get_options("boot-once", bootoncelabel,
1671 sizeof(bootoncelabel));
1672 if (bootoncelabel[0] != 0)
1673 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1675 prom_set_options("boot-once", NULL, 0);
1677 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1678 prom_printf("%s: Unable to parse\n", bootdevice);
1681 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1682 boot.dev, boot.part, boot.file);
1685 if (_machine == _MACH_chrp)
1686 boot.file = "/etc/";
1687 else if (strlen(boot.file)) {
1688 if (!strncmp(boot.file, "\\\\", 2))
1692 p = last = boot.file;
1702 if (strlen(boot.file))
1703 strcat(boot.file, "\\");
1706 strcpy(conf_path, boot.file);
1707 strcat(conf_path, CONFIG_FILE_NAME);
1708 boot.file = conf_path;
1709 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1710 boot.dev, boot.part, boot.file);
1714 * If we're doing a netboot, first look for one which matches our
1717 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1718 prom_printf("Try to netboot\n");
1719 useconf = load_my_config_file(&boot);
1723 useconf = load_config_file(&boot);
1725 prom_printf("Welcome to yaboot version " VERSION "\n");
1726 prom_printf("Enter \"help\" to get some basic usage information\n");
1728 /* I am fed up with lusers using the wrong partition type and
1729 mailing me *when* it breaks */
1731 if (_machine == _MACH_Pmac) {
1732 char *entry = cfg_get_strg(0, "ptypewarning");
1735 warn = strcmp(entry,
1736 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1738 ptype = get_part_type(boot.dev, boot.part);
1739 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1740 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1741 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1749 prom_printf("Bye.\n");
1755 * c-file-style: "k&r"