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 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
460 packet = prom_get_netinfo();
463 * First, try to match on mac address with the hardware type
467 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
468 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
472 if (_machine == _MACH_chrp)
473 sprintf(fspec.file, "/etc/%02x-", packet->htype);
475 sprintf(fspec.file, "%02x-", packet->htype);
476 strcat(fspec.file, prom_get_mac(packet));
478 rc = load_config_file(&fspec);
484 * Now try to match on IP.
487 /* 8 chars in yiaddr + \0 */
488 fspec.file = malloc(9);
492 strcat(fspec.file, prom_get_ip(packet));
494 while (strlen(fspec.file)) {
495 rc = load_config_file(&fspec);
498 /* Chop one digit off the end, try again */
499 fspec.file[strlen(fspec.file) - 1] = '\0';
503 if (rc) /* modify original only on success */
504 orig_fspec->file = fspec.file;
510 void maintabfunc (void)
514 prom_printf("boot: %s", cbuff);
519 word_split(char **linep, char **paramsp)
534 while (*p != 0 && *p != ' ')
543 make_params(char *label, char *params)
546 static char buffer[2048];
551 p = cfg_get_strg(label, "literal");
563 p = cfg_get_strg(label, "root");
570 if (cfg_get_flag(label, "read-only")) {
574 if (cfg_get_flag(label, "read-write")) {
578 p = cfg_get_strg(label, "ramdisk");
580 strcpy (q, "ramdisk=");
585 p = cfg_get_strg(label, "initrd-size");
587 strcpy (q, "ramdisk_size=");
592 if (cfg_get_flag(label, "novideo")) {
593 strcpy (q, "video=ofonly");
597 p = cfg_get_strg (label, "append");
604 pause_after = cfg_get_flag (label, "pause-after");
605 p = cfg_get_strg(label, "pause-message");
614 void check_password(char *str)
618 prom_printf("\n%s", str);
619 for (i = 0; i < 3; i++) {
620 prom_printf ("\nPassword: ");
622 cmdedit ((void (*)(void)) 0, 1);
624 #ifdef USE_MD5_PASSWORDS
625 if (!strncmp (password, "$1$", 3)) {
626 if (!check_md5_password(passwdbuff, password))
629 else if (!strcmp (password, passwdbuff))
632 if (!strcmp (password, passwdbuff))
634 #endif /* USE_MD5_PASSWORDS */
637 prom_printf ("Incorrect password. Try again.");
640 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
641 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
642 " ||----w |\n || ||\n");
644 prom_interpret("reset-all");
647 int get_params(struct boot_param_t* params)
651 char defdevice_bak[1024];
654 char *imagename = 0, *label;
659 static int first = 1;
660 static char imagepath[1024];
661 static char initrdpath[1024];
662 static char sysmappath[1024];
665 memset(params, 0, sizeof(*params));
667 params->kernel.part = -1;
668 params->rd.part = -1;
669 params->sysmap.part = -1;
676 imagename = bootargs;
677 word_split(&imagename, ¶ms->args);
678 timeout = DEFAULT_TIMEOUT;
680 prom_printf("Default supplied on the command line: %s ", imagename);
682 prom_printf("%s", params->args);
685 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
686 timeout = simple_strtol(q, NULL, 0);
689 prom_printf("boot: ");
694 end = beg + 100 * timeout;
696 c = prom_nbgetchar();
697 } while (c == -1 && prom_getms() <= end);
701 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
707 if (c != -1 && c != '\n' && c != '\r') {
710 } else if (c >= ' ') {
713 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
716 prom_printf("%s\n", cbuff);
721 if (c == '\n' || c == '\r') {
723 if (bootoncelabel[0] != 0)
724 imagename = bootoncelabel;
726 imagename = cfg_get_default();
729 prom_printf("%s", imagename);
731 prom_printf(" %s", params->args);
733 } else if (!singlekey) {
734 cmdedit(maintabfunc, 0);
736 strcpy(given_bootargs, cbuff);
737 given_bootargs_by_user = 1;
739 word_split(&imagename, ¶ms->args);
742 /* chrp gets this wrong, force it -- Cort */
743 if ( useconf && (!imagename || imagename[0] == 0 ))
744 imagename = cfg_get_default();
747 defdevice = boot.dev;
749 strcpy(defdevice_bak,defdevice);
752 defdevice = cfg_get_strg(0, "device");
753 p = cfg_get_strg(0, "partition");
755 n = simple_strtol(p, &endp, 10);
756 if (endp != p && *endp == 0)
759 p = cfg_get_strg(0, "pause-message");
762 if (cfg_get_flag(0, "restricted"))
764 p = cfg_get_strg(imagename, "image");
768 defdevice = cfg_get_strg(label, "device");
769 if(!defdevice) defdevice=boot.dev;
770 p = cfg_get_strg(label, "partition");
772 n = simple_strtol(p, &endp, 10);
773 if (endp != p && *endp == 0)
776 if (cfg_get_flag(label, "restricted"))
779 if (params->args && password && restricted)
780 check_password ("To specify arguments for this image "
781 "you must enter the password.");
782 else if (password && !restricted)
783 check_password ("This image is restricted.");
785 params->args = make_params(label, params->args);
789 if (!strcmp (imagename, "help")) {
790 /* FIXME: defdevice shouldn't need to be reset all over the place */
791 if(!defdevice) defdevice = boot.dev;
793 "\nPress the tab key for a list of defined images.\n"
794 "The label marked with a \"*\" is is the default image, "
795 "press <return> to boot it.\n\n"
796 "To boot any other label simply type its name and press <return>.\n\n"
797 "To boot a kernel image which is not defined in the yaboot configuration \n"
798 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
799 "\"device:\" is the OpenFirmware device path to the disk the image \n"
800 "resides on, and \"partno\" is the partition number the image resides on.\n"
801 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
802 "device, if you only specify a filename you should not start it with a \",\"\n\n"
803 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
804 "its device, partno and path, on Open Firmware Prompt:\n"
805 "boot conf=device:partno,/path/to/configfile\n."
806 "To reload the config file or load a new one, use the \"conf\" command\n"
807 "on Yaboot's prompt:\n"
808 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
809 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
810 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
815 if (!strcmp (imagename, "halt")) {
817 check_password ("Restricted command.");
821 if (!strcmp (imagename, "bye")) {
823 check_password ("Restricted command.");
829 if (!strncmp (imagename, "conf", 4)) {
831 // imagename = "conf file=blah dev=bleh part=blih"
832 DEBUG_F("Loading user-specified config file: %s\n",imagename);
834 check_password ("Restricted command.");
838 // args= "file=blah dev=bleh part=blih"
839 char *args = params->args;
843 // set a pointer to the first space in args
844 char *space = strchr(args,' ');
848 char temp[1024] = "0";
850 // copy next argument to temp
851 strncpy(temp, args, space-args);
853 // parse temp and set boot arguments
854 if (!strncmp (temp, "file=", 5)){
855 DEBUG_F("conf file: %s\n", temp+5);
856 strcpy(boot.file, temp+5);
857 } else if (!strncmp (temp, "device=", 7)){
858 DEBUG_F("conf device: %s\n", temp+7);
859 strcpy(boot.dev, temp+7);
860 } else if (!strncmp (temp, "partition=", 10)){
861 DEBUG_F("conf partition: %s\n", temp+10);
862 boot.part=simple_strtol(temp+10,NULL,10);
866 // set the pointer to the next space in args;
867 // set the loop control variable
868 if (strlen(space)>1){
869 // Go to the next argument
873 if (strchr(args,' ') == NULL)
874 space = &args[strlen(args)];
876 space = strchr(args,' ');
883 prom_printf("Loading config file...\n");
884 useconf = load_config_file(&boot);
886 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
887 timeout = simple_strtol(q, NULL, 0);
889 prom_printf("Restoring default values.\n");
890 strcpy(boot.file,"");
891 strcpy(boot.dev, defdevice_bak);
896 prom_printf("Current configuration:\n");
897 prom_printf("device: %s\n", boot.dev);
899 prom_printf("partition: auto\n");
901 prom_printf("partition: %d\n", boot.part);
902 if (strlen(boot.file))
903 prom_printf("file: %s\n", boot.file);
905 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
914 if (imagename[0] == '$') {
915 /* forth command string */
917 check_password ("OpenFirmware commands are restricted.");
918 prom_interpret(imagename+1);
922 strncpy(imagepath, imagename, 1024);
924 if (!label && password)
925 check_password ("To boot a custom image you must enter the password.");
927 if (!parse_device_path(imagepath, defdevice, defpart,
928 "/vmlinux", ¶ms->kernel)) {
929 prom_printf("%s: Unable to parse\n", imagepath);
932 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
933 params->kernel.part, params->kernel.file);
936 p = cfg_get_strg(label, "initrd");
938 DEBUG_F("Parsing initrd path <%s>\n", p);
939 strncpy(initrdpath, p, 1024);
940 if (!parse_device_path(initrdpath, defdevice, defpart,
941 "/root.bin", ¶ms->rd)) {
942 prom_printf("%s: Unable to parse\n", imagepath);
946 p = cfg_get_strg(label, "sysmap");
948 DEBUG_F("Parsing sysmap path <%s>\n", p);
949 strncpy(sysmappath, p, 1024);
950 if (!parse_device_path(sysmappath, defdevice, defpart,
951 "/boot/System.map", ¶ms->sysmap)) {
952 prom_printf("%s: Unable to parse\n", imagepath);
960 /* This is derived from quik core. To be changed to first parse the headers
961 * doing lazy-loading, and then claim the memory before loading the kernel
963 * We also need to add initrd support to this whole mecanism
968 #define MAX_HEADERS 32
970 struct boot_file_t file;
972 static struct boot_param_t params;
974 unsigned long initrd_size;
976 unsigned long sysmap_size;
977 kernel_entry_t kernel_entry;
978 struct bi_record* birec;
981 void *initrd_more,*initrd_want;
982 unsigned long initrd_read;
984 loadinfo.load_loc = 0;
992 if (get_params(¶ms))
994 if (!params.kernel.file)
997 prom_printf("Please wait, loading kernel...\n");
999 memset(&file, 0, sizeof(file));
1001 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1002 && params.kernel.file[0] != '\\') {
1003 loc=(char*)malloc(strlen(params.kernel.file)+3);
1005 prom_printf ("malloc error\n");
1008 strcpy(loc,boot.file);
1009 strcat(loc,params.kernel.file);
1010 free(params.kernel.file);
1011 params.kernel.file=loc;
1013 result = open_file(¶ms.kernel, &file);
1014 if (result != FILE_ERR_OK) {
1015 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1016 prom_perror(result, params.kernel.file);
1020 /* Read the Elf e_ident, e_type and e_machine fields to
1021 * determine Elf file type
1023 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1024 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1025 file.fs->close(&file);
1026 memset(&file, 0, sizeof(file));
1030 if (is_elf32(&loadinfo)) {
1031 if (!load_elf32(&file, &loadinfo)) {
1032 file.fs->close(&file);
1033 memset(&file, 0, sizeof(file));
1036 prom_printf(" Elf32 kernel loaded...\n");
1037 } else if (is_elf64(&loadinfo)) {
1038 if (!load_elf64(&file, &loadinfo)) {
1039 file.fs->close(&file);
1040 memset(&file, 0, sizeof(file));
1043 prom_printf(" Elf64 kernel loaded...\n");
1045 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1046 file.fs->close(&file);
1047 memset(&file, 0, sizeof(file));
1050 file.fs->close(&file);
1051 memset(&file, 0, sizeof(file));
1053 /* If sysmap, load it (only if booting a vmlinux).
1055 if (flat_vmlinux && params.sysmap.file) {
1056 prom_printf("Loading System.map ...\n");
1057 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1058 && params.sysmap.file[0] != '\\') {
1060 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1062 prom_printf ("malloc error\n");
1065 strcpy(loc,boot.file);
1066 strcat(loc,params.sysmap.file);
1067 free(params.sysmap.file);
1068 params.sysmap.file=loc;
1071 result = open_file(¶ms.sysmap, &file);
1072 if (result != FILE_ERR_OK) {
1073 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1074 prom_perror(result, params.sysmap.file);
1077 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1078 if (sysmap_base == (void *)-1) {
1079 prom_printf("Claim failed for sysmap memory\n");
1083 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1084 if (sysmap_size == 0)
1087 ((char *)sysmap_base)[sysmap_size++] = 0;
1089 file.fs->close(&file);
1090 memset(&file, 0, sizeof(file));
1093 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1094 sysmap_base, sysmap_size >> 10);
1095 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1097 prom_printf("System.map load failed !\n");
1102 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1103 * can't tell the size it will be so we claim an arbitrary amount
1106 if (flat_vmlinux && params.rd.file) {
1107 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1108 && params.kernel.file[0] != '\\')
1111 loc=(char*)malloc(strlen(params.rd.file)+3);
1113 prom_printf ("Malloc error\n");
1116 strcpy(loc,boot.file);
1117 strcat(loc,params.rd.file);
1118 free(params.rd.file);
1121 prom_printf("Loading ramdisk...\n");
1122 result = open_file(¶ms.rd, &file);
1123 if (result != FILE_ERR_OK) {
1124 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1125 prom_perror(result, params.rd.file);
1128 #define INITRD_CHUNKSIZE 0x100000
1129 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1130 if (initrd_base == (void *)-1) {
1131 prom_printf("Claim failed for initrd memory\n");
1134 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1135 if (initrd_size == 0)
1137 initrd_read = initrd_size;
1138 initrd_more = initrd_base;
1139 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1140 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1141 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1142 if (initrd_more != initrd_want) {
1143 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1147 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1148 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1149 initrd_size += initrd_read;
1152 file.fs->close(&file);
1153 memset(&file, 0, sizeof(file));
1156 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1157 initrd_base, initrd_size >> 10);
1159 prom_printf("ramdisk load failed !\n");
1164 DEBUG_F("setting kernel args to: %s\n", params.args);
1165 prom_setargs(params.args);
1166 DEBUG_F("flushing icache...");
1167 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1172 * Fill new boot infos (only if booting a vmlinux).
1174 * The birec is low on memory, probably inside the malloc pool,
1175 * so we don't write it earlier. At this point, we should not
1176 * use anything coming from the malloc pool.
1178 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1180 /* We make sure it's mapped. We map only 64k for now, it's
1181 * plenty enough we don't claim since this precise memory
1182 * range may already be claimed by the malloc pool.
1184 prom_map (birec, birec, 0x10000);
1185 DEBUG_F("birec at %p\n", birec);
1188 birec->tag = BI_FIRST;
1189 birec->size = sizeof(struct bi_record);
1190 birec = (struct bi_record *)((ulong)birec + birec->size);
1192 birec->tag = BI_BOOTLOADER_ID;
1193 sprintf( (char *)birec->data, "yaboot");
1194 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1195 birec = (struct bi_record *)((ulong)birec + birec->size);
1197 birec->tag = BI_MACHTYPE;
1198 birec->data[0] = _machine;
1199 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1200 birec = (struct bi_record *)((ulong)birec + birec->size);
1203 birec->tag = BI_SYSMAP;
1204 birec->data[0] = (ulong)sysmap_base;
1205 birec->data[1] = sysmap_size;
1206 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1207 birec = (struct bi_record *)((ulong)birec + birec->size);
1209 birec->tag = BI_LAST;
1210 birec->size = sizeof(struct bi_record);
1211 birec = (struct bi_record *)((ulong)birec + birec->size);
1214 /* compute the kernel's entry point. */
1215 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1217 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1218 DEBUG_F("kernel: arg1 = %p,\n"
1219 " arg2 = 0x%08lx,\n"
1223 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1225 DEBUG_F("Entering kernel...\n");
1227 /* call the kernel with our stack. */
1228 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1236 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1239 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1241 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1242 unsigned long addr, loadaddr;
1244 /* Read the rest of the Elf header... */
1245 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1246 prom_printf("\nCan't read Elf32 image header\n");
1250 DEBUG_F("Elf32 header:\n");
1251 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1252 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1253 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1254 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1255 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1256 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1257 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1258 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1259 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1260 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1262 loadinfo->entry = e->e_entry;
1264 if (e->e_phnum > MAX_HEADERS) {
1265 prom_printf ("Can only load kernels with one program header\n");
1269 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1271 prom_printf ("Malloc error\n");
1275 /* Now, we read the section header */
1276 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1277 prom_printf ("seek error\n");
1280 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1281 sizeof(Elf32_Phdr) * e->e_phnum) {
1282 prom_printf ("read error\n");
1286 /* Scan through the program header
1287 * HACK: We must return the _memory size of the kernel image, not the
1288 * file size (because we have to leave room before other boot
1289 * infos. This code works as a side effect of the fact that
1290 * we have one section and vaddr == p_paddr
1292 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1294 for (i = 0; i < e->e_phnum; ++i, ++p) {
1295 if (p->p_type != PT_LOAD || p->p_offset == 0)
1297 if (loadinfo->memsize == 0) {
1298 loadinfo->offset = p->p_offset;
1299 loadinfo->memsize = p->p_memsz;
1300 loadinfo->filesize = p->p_filesz;
1301 loadinfo->load_loc = p->p_vaddr;
1303 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1304 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1308 if (loadinfo->memsize == 0) {
1309 prom_printf("Can't find a loadable segment !\n");
1313 /* leave some room (1Mb) for boot infos */
1314 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1315 /* Claim OF memory */
1316 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1318 /* Determine whether we are trying to boot a vmlinux or some
1319 * other binary image (eg, zImage). We load vmlinux's at
1320 * KERNELADDR and all other binaries at their e_entry value.
1322 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1324 loadaddr = KERNELADDR;
1327 loadaddr = loadinfo->load_loc;
1330 /* On some systems, loadaddr may already be claimed, so try some
1331 * other nearby addresses before giving up.
1333 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1334 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1335 if (loadinfo->base != (void *)-1) break;
1337 if (loadinfo->base == (void *)-1) {
1338 prom_printf("Claim error, can't allocate kernel memory\n");
1342 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1343 loadinfo->base, loadinfo->memsize);
1344 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1345 loadaddr, loadinfo->memsize);
1347 /* Load the program segments... */
1349 for (i = 0; i < e->e_phnum; ++i, ++p) {
1350 unsigned long offset;
1351 if (p->p_type != PT_LOAD || p->p_offset == 0)
1354 /* Now, we skip to the image itself */
1355 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1356 prom_printf ("Seek error\n");
1357 prom_release(loadinfo->base, loadinfo->memsize);
1360 offset = p->p_vaddr - loadinfo->load_loc;
1361 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1362 prom_printf ("Read failed\n");
1363 prom_release(loadinfo->base, loadinfo->memsize);
1370 /* Return success at loading the Elf32 kernel */
1380 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1383 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1385 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1386 unsigned long addr, loadaddr;
1388 /* Read the rest of the Elf header... */
1389 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1390 prom_printf("\nCan't read Elf64 image header\n");
1394 DEBUG_F("Elf64 header:\n");
1395 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1396 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1397 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1398 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1399 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1400 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1401 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1402 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1403 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1404 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1406 loadinfo->entry = e->e_entry;
1408 if (e->e_phnum > MAX_HEADERS) {
1409 prom_printf ("Can only load kernels with one program header\n");
1413 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1415 prom_printf ("Malloc error\n");
1419 /* Now, we read the section header */
1420 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1421 prom_printf ("Seek error\n");
1424 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1425 sizeof(Elf64_Phdr) * e->e_phnum) {
1426 prom_printf ("Read error\n");
1430 /* Scan through the program header
1431 * HACK: We must return the _memory size of the kernel image, not the
1432 * file size (because we have to leave room before other boot
1433 * infos. This code works as a side effect of the fact that
1434 * we have one section and vaddr == p_paddr
1436 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1438 for (i = 0; i < e->e_phnum; ++i, ++p) {
1439 if (p->p_type != PT_LOAD || p->p_offset == 0)
1441 if (loadinfo->memsize == 0) {
1442 loadinfo->offset = p->p_offset;
1443 loadinfo->memsize = p->p_memsz;
1444 loadinfo->filesize = p->p_filesz;
1445 loadinfo->load_loc = p->p_vaddr;
1447 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1448 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1452 if (loadinfo->memsize == 0) {
1453 prom_printf("Can't find a loadable segment !\n");
1457 /* leave some room (1Mb) for boot infos */
1458 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1459 /* Claim OF memory */
1460 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1462 /* Determine whether we are trying to boot a vmlinux or some
1463 * other binary image (eg, zImage). We load vmlinux's at
1464 * KERNELADDR and all other binaries at their e_entry value.
1466 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1468 loadaddr = KERNELADDR;
1471 loadaddr = e->e_entry;
1474 /* On some systems, loadaddr may already be claimed, so try some
1475 * other nearby addresses before giving up.
1477 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1478 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1479 if (loadinfo->base != (void *)-1) break;
1481 if (loadinfo->base == (void *)-1) {
1482 prom_printf("Claim error, can't allocate kernel memory\n");
1486 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1487 loadinfo->base, loadinfo->memsize);
1488 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1489 loadaddr, loadinfo->memsize);
1491 /* Load the program segments... */
1493 for (i = 0; i < e->e_phnum; ++i, ++p) {
1494 unsigned long offset;
1495 if (p->p_type != PT_LOAD || p->p_offset == 0)
1498 /* Now, we skip to the image itself */
1499 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1500 prom_printf ("Seek error\n");
1501 prom_release(loadinfo->base, loadinfo->memsize);
1504 offset = p->p_vaddr - loadinfo->load_loc;
1505 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1506 prom_printf ("Read failed\n");
1507 prom_release(loadinfo->base, loadinfo->memsize);
1514 /* Return success at loading the Elf64 kernel */
1524 is_elf32(loadinfo_t *loadinfo)
1526 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1528 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1529 e->e_ident[EI_MAG1] == ELFMAG1 &&
1530 e->e_ident[EI_MAG2] == ELFMAG2 &&
1531 e->e_ident[EI_MAG3] == ELFMAG3 &&
1532 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1533 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1534 e->e_type == ET_EXEC &&
1535 e->e_machine == EM_PPC);
1539 is_elf64(loadinfo_t *loadinfo)
1541 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1543 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1544 e->e_ident[EI_MAG1] == ELFMAG1 &&
1545 e->e_ident[EI_MAG2] == ELFMAG2 &&
1546 e->e_ident[EI_MAG3] == ELFMAG3 &&
1547 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1548 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1549 e->e_type == ET_EXEC &&
1550 e->e_machine == EM_PPC64);
1556 #ifdef CONFIG_SET_COLORMAP
1557 static unsigned char default_colors[] = {
1576 prom_handle scrn = PROM_INVALID_HANDLE;
1578 /* Try Apple's mac-boot screen ihandle */
1579 result = (int)call_prom_return("interpret", 1, 2,
1580 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1581 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1583 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1585 /* Hrm... check to see if stdout is a display */
1586 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1587 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1588 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1589 DEBUG_F("got it ! stdout is a screen\n");
1592 /* Else, we try to open the package */
1593 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1594 DEBUG_F("Open screen result: %p\n", scrn);
1598 if (scrn == PROM_INVALID_HANDLE) {
1599 prom_printf("No screen device found !/n");
1603 prom_set_color(scrn, i, default_colors[i*3],
1604 default_colors[i*3+1], default_colors[i*3+2]);
1606 prom_printf("\x1b[1;37m\x1b[2;40m");
1608 for (i=0;i<16; i++) {
1609 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1610 ansi_color_table[i].index,
1611 ansi_color_table[i].value,
1612 ansi_color_table[i].name,
1613 ansi_color_table[i].name);
1614 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1615 ansi_color_table[i].index,
1616 ansi_color_table[i].value+10,
1617 ansi_color_table[i].name,
1618 ansi_color_table[i].name);
1620 prom_printf("\x1b[1;37m\x1b[2;40m");
1621 #endif /* COLOR_TEST */
1627 #endif /* CONFIG_SET_COLORMAP */
1635 char conf_path[1024];
1637 if (_machine == _MACH_Pmac)
1640 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1641 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1642 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1643 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1645 /* If conf= specified on command line, it overrides
1646 Usage: conf=device:partition,/path/to/conffile
1647 Example: On Open Firmware Prompt, type
1648 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1650 if (!strncmp(bootargs, "conf=", 5)) {
1651 DEBUG_F("Using conf argument in Open Firmware\n");
1652 char *end = strchr(bootargs,' ');
1656 strcpy(bootdevice, bootargs + 5);
1658 DEBUG_F("Using conf=%s\n", bootdevice);
1660 /* Remove conf=xxx from bootargs */
1662 memmove(bootargs, end+1, strlen(end+1)+1);
1666 if (bootdevice[0] == 0) {
1667 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1668 DEBUG_F("boot-device = %s\n", bootdevice);
1670 if (bootdevice[0] == 0) {
1671 prom_printf("Couldn't determine boot device\n");
1675 if (bootoncelabel[0] == 0) {
1676 prom_get_options("boot-once", bootoncelabel,
1677 sizeof(bootoncelabel));
1678 if (bootoncelabel[0] != 0)
1679 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1681 prom_set_options("boot-once", NULL, 0);
1683 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1684 prom_printf("%s: Unable to parse\n", bootdevice);
1687 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1688 boot.dev, boot.part, boot.file);
1691 if (_machine == _MACH_chrp)
1692 boot.file = "/etc/";
1693 else if (strlen(boot.file)) {
1694 if (!strncmp(boot.file, "\\\\", 2))
1698 p = last = boot.file;
1708 if (strlen(boot.file))
1709 strcat(boot.file, "\\");
1712 strcpy(conf_path, boot.file);
1713 strcat(conf_path, CONFIG_FILE_NAME);
1714 boot.file = conf_path;
1715 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1716 boot.dev, boot.part, boot.file);
1720 * If we're doing a netboot, first look for one which matches our
1723 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1724 prom_printf("Try to netboot\n");
1725 useconf = load_my_config_file(&boot);
1729 useconf = load_config_file(&boot);
1731 prom_printf("Welcome to yaboot version " VERSION "\n");
1732 prom_printf("Enter \"help\" to get some basic usage information\n");
1734 /* I am fed up with lusers using the wrong partition type and
1735 mailing me *when* it breaks */
1737 if (_machine == _MACH_Pmac) {
1738 char *entry = cfg_get_strg(0, "ptypewarning");
1741 warn = strcmp(entry,
1742 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1744 ptype = get_part_type(boot.dev, boot.part);
1745 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1746 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1747 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1755 prom_printf("Bye.\n");
1761 * c-file-style: "k&r"