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");
371 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
373 /* Now, we do the initialisations stored in the config file */
374 p = cfg_get_strg(0, "init-code");
378 password = cfg_get_strg(0, "password");
380 #ifdef CONFIG_COLOR_TEXT
381 p = cfg_get_strg(0, "fgcolor");
383 DEBUG_F("fgcolor=%s\n", p);
384 fgcolor = check_color_text_ui(p);
386 prom_printf("Invalid fgcolor: \"%s\".\n", p);
389 p = cfg_get_strg(0, "bgcolor");
391 DEBUG_F("bgcolor=%s\n", p);
392 bgcolor = check_color_text_ui(p);
394 prom_printf("Invalid bgcolor: \"%s\".\n", p);
398 sprintf(temp, "%x to background-color", bgcolor);
399 prom_interpret(temp);
406 sprintf(temp, "%x to foreground-color", fgcolor);
407 prom_interpret(temp);
409 #endif /* CONFIG_COLOR_TEXT */
411 p = cfg_get_strg(0, "init-message");
413 prom_printf("%s\n", p);
415 p = cfg_get_strg(0, "message");
417 print_message_file(p);
424 file.fs->close(&file);
433 * Search for config file by MAC address, then by IP address.
434 * Basically copying pxelinux's algorithm.
435 * http://syslinux.zytor.com/pxe.php#config
437 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
439 struct bootp_packet *packet;
441 struct boot_fspec_t fspec = *orig_fspec;
442 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
444 packet = prom_get_netinfo();
447 * First, try to match on mac address with the hardware type
451 /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */
452 fspec.file = malloc(packet->hlen * 3 + 2 + 6);
456 if (_machine == _MACH_chrp)
457 sprintf(fspec.file, "/etc/%02x-", packet->htype);
459 sprintf(fspec.file, "%02x-", packet->htype);
460 strcat(fspec.file, prom_get_mac(packet));
462 rc = load_config_file(&fspec);
468 * Now try to match on IP.
471 /* 8 chars in yiaddr + \0 */
472 fspec.file = malloc(9);
476 strcat(fspec.file, prom_get_ip(packet));
478 while (strlen(fspec.file)) {
479 rc = load_config_file(&fspec);
482 /* Chop one digit off the end, try again */
483 fspec.file[strlen(fspec.file) - 1] = '\0';
487 if (rc) /* modify original only on success */
488 orig_fspec->file = fspec.file;
494 void maintabfunc (void)
498 prom_printf("boot: %s", cbuff);
503 word_split(char **linep, char **paramsp)
518 while (*p != 0 && *p != ' ')
527 make_params(char *label, char *params)
530 static char buffer[2048];
535 p = cfg_get_strg(label, "literal");
547 p = cfg_get_strg(label, "root");
554 if (cfg_get_flag(label, "read-only")) {
558 if (cfg_get_flag(label, "read-write")) {
562 p = cfg_get_strg(label, "ramdisk");
564 strcpy (q, "ramdisk=");
569 p = cfg_get_strg(label, "initrd-size");
571 strcpy (q, "ramdisk_size=");
576 if (cfg_get_flag(label, "novideo")) {
577 strcpy (q, "video=ofonly");
581 p = cfg_get_strg (label, "append");
588 pause_after = cfg_get_flag (label, "pause-after");
589 p = cfg_get_strg(label, "pause-message");
598 void check_password(char *str)
602 prom_printf("\n%s", str);
603 for (i = 0; i < 3; i++) {
604 prom_printf ("\nPassword: ");
606 cmdedit ((void (*)(void)) 0, 1);
608 #ifdef USE_MD5_PASSWORDS
609 if (!strncmp (password, "$1$", 3)) {
610 if (!check_md5_password(passwdbuff, password))
613 else if (!strcmp (password, passwdbuff))
616 if (!strcmp (password, passwdbuff))
618 #endif /* USE_MD5_PASSWORDS */
621 prom_printf ("Incorrect password. Try again.");
624 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
625 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
626 " ||----w |\n || ||\n");
628 prom_interpret("reset-all");
631 int get_params(struct boot_param_t* params)
635 char defdevice_bak[1024];
638 char *imagename = 0, *label;
643 static int first = 1;
644 static char imagepath[1024];
645 static char initrdpath[1024];
646 static char sysmappath[1024];
649 memset(params, 0, sizeof(*params));
651 params->kernel.part = -1;
652 params->rd.part = -1;
653 params->sysmap.part = -1;
660 imagename = bootargs;
661 word_split(&imagename, ¶ms->args);
662 timeout = DEFAULT_TIMEOUT;
664 prom_printf("Default supplied on the command line: %s ", imagename);
666 prom_printf("%s", params->args);
669 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
670 timeout = simple_strtol(q, NULL, 0);
673 prom_printf("boot: ");
678 end = beg + 100 * timeout;
680 c = prom_nbgetchar();
681 } while (c == -1 && prom_getms() <= end);
685 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
691 if (c != -1 && c != '\n' && c != '\r') {
694 } else if (c >= ' ') {
697 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
700 prom_printf("%s\n", cbuff);
705 if (c == '\n' || c == '\r') {
707 if (bootoncelabel[0] != 0)
708 imagename = bootoncelabel;
710 imagename = cfg_get_default();
713 prom_printf("%s", imagename);
715 prom_printf(" %s", params->args);
717 } else if (!singlekey) {
718 cmdedit(maintabfunc, 0);
720 strcpy(given_bootargs, cbuff);
721 given_bootargs_by_user = 1;
723 word_split(&imagename, ¶ms->args);
726 /* chrp gets this wrong, force it -- Cort */
727 if ( useconf && (!imagename || imagename[0] == 0 ))
728 imagename = cfg_get_default();
731 defdevice = boot.dev;
733 strcpy(defdevice_bak,defdevice);
736 defdevice = cfg_get_strg(0, "device");
737 p = cfg_get_strg(0, "partition");
739 n = simple_strtol(p, &endp, 10);
740 if (endp != p && *endp == 0)
743 p = cfg_get_strg(0, "pause-message");
746 if (cfg_get_flag(0, "restricted"))
748 p = cfg_get_strg(imagename, "image");
752 defdevice = cfg_get_strg(label, "device");
753 if(!defdevice) defdevice=boot.dev;
754 p = cfg_get_strg(label, "partition");
756 n = simple_strtol(p, &endp, 10);
757 if (endp != p && *endp == 0)
760 if (cfg_get_flag(label, "restricted"))
763 if (params->args && password && restricted)
764 check_password ("To specify arguments for this image "
765 "you must enter the password.");
766 else if (password && !restricted)
767 check_password ("This image is restricted.");
769 params->args = make_params(label, params->args);
773 if (!strcmp (imagename, "help")) {
774 /* FIXME: defdevice shouldn't need to be reset all over the place */
775 if(!defdevice) defdevice = boot.dev;
777 "\nPress the tab key for a list of defined images.\n"
778 "The label marked with a \"*\" is is the default image, "
779 "press <return> to boot it.\n\n"
780 "To boot any other label simply type its name and press <return>.\n\n"
781 "To boot a kernel image which is not defined in the yaboot configuration \n"
782 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
783 "\"device:\" is the OpenFirmware device path to the disk the image \n"
784 "resides on, and \"partno\" is the partition number the image resides on.\n"
785 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
786 "device, if you only specify a filename you should not start it with a \",\"\n\n"
787 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
788 "its device, partno and path, on Open Firmware Prompt:\n"
789 "boot conf=device:partno,/path/to/configfile\n."
790 "To reload the config file or load a new one, use the \"conf\" command\n"
791 "on Yaboot's prompt:\n"
792 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
793 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
794 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
799 if (!strcmp (imagename, "halt")) {
801 check_password ("Restricted command.");
805 if (!strcmp (imagename, "bye")) {
807 check_password ("Restricted command.");
813 if (!strncmp (imagename, "conf", 4)) {
815 // imagename = "conf file=blah dev=bleh part=blih"
816 DEBUG_F("Loading user-specified config file: %s\n",imagename);
818 check_password ("Restricted command.");
822 // args= "file=blah dev=bleh part=blih"
823 char *args = params->args;
827 // set a pointer to the first space in args
828 char *space = strchr(args,' ');
832 char temp[1024] = "0";
834 // copy next argument to temp
835 strncpy(temp, args, space-args);
837 // parse temp and set boot arguments
838 if (!strncmp (temp, "file=", 5)){
839 DEBUG_F("conf file: %s\n", temp+5);
840 strcpy(boot.file, temp+5);
841 } else if (!strncmp (temp, "device=", 7)){
842 DEBUG_F("conf device: %s\n", temp+7);
843 strcpy(boot.dev, temp+7);
844 } else if (!strncmp (temp, "partition=", 10)){
845 DEBUG_F("conf partition: %s\n", temp+10);
846 boot.part=simple_strtol(temp+10,NULL,10);
850 // set the pointer to the next space in args;
851 // set the loop control variable
852 if (strlen(space)>1){
853 // Go to the next argument
857 if (strchr(args,' ') == NULL)
858 space = &args[strlen(args)];
860 space = strchr(args,' ');
867 prom_printf("Loading config file...\n");
868 useconf = load_config_file(&boot);
870 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
871 timeout = simple_strtol(q, NULL, 0);
873 prom_printf("Restoring default values.\n");
874 strcpy(boot.file,"");
875 strcpy(boot.dev, defdevice_bak);
880 prom_printf("Current configuration:\n");
881 prom_printf("device: %s\n", boot.dev);
883 prom_printf("partition: auto\n");
885 prom_printf("partition: %d\n", boot.part);
886 if (strlen(boot.file))
887 prom_printf("file: %s\n", boot.file);
889 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
898 if (imagename[0] == '$') {
899 /* forth command string */
901 check_password ("OpenFirmware commands are restricted.");
902 prom_interpret(imagename+1);
906 strncpy(imagepath, imagename, 1024);
908 if (!label && password)
909 check_password ("To boot a custom image you must enter the password.");
911 if (!parse_device_path(imagepath, defdevice, defpart,
912 "/vmlinux", ¶ms->kernel)) {
913 prom_printf("%s: Unable to parse\n", imagepath);
916 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
917 params->kernel.part, params->kernel.file);
920 p = cfg_get_strg(label, "initrd");
922 DEBUG_F("Parsing initrd path <%s>\n", p);
923 strncpy(initrdpath, p, 1024);
924 if (!parse_device_path(initrdpath, defdevice, defpart,
925 "/root.bin", ¶ms->rd)) {
926 prom_printf("%s: Unable to parse\n", imagepath);
930 p = cfg_get_strg(label, "sysmap");
932 DEBUG_F("Parsing sysmap path <%s>\n", p);
933 strncpy(sysmappath, p, 1024);
934 if (!parse_device_path(sysmappath, defdevice, defpart,
935 "/boot/System.map", ¶ms->sysmap)) {
936 prom_printf("%s: Unable to parse\n", imagepath);
944 /* This is derived from quik core. To be changed to first parse the headers
945 * doing lazy-loading, and then claim the memory before loading the kernel
947 * We also need to add initrd support to this whole mecanism
952 #define MAX_HEADERS 32
954 struct boot_file_t file;
956 static struct boot_param_t params;
958 unsigned long initrd_size;
960 unsigned long sysmap_size;
961 kernel_entry_t kernel_entry;
962 struct bi_record* birec;
965 void *initrd_more,*initrd_want;
966 unsigned long initrd_read;
968 loadinfo.load_loc = 0;
976 if (get_params(¶ms))
978 if (!params.kernel.file)
981 prom_printf("Please wait, loading kernel...\n");
983 memset(&file, 0, sizeof(file));
985 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
986 && params.kernel.file[0] != '\\') {
987 loc=(char*)malloc(strlen(params.kernel.file)+3);
989 prom_printf ("malloc error\n");
992 strcpy(loc,boot.file);
993 strcat(loc,params.kernel.file);
994 free(params.kernel.file);
995 params.kernel.file=loc;
997 result = open_file(¶ms.kernel, &file);
998 if (result != FILE_ERR_OK) {
999 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1000 prom_perror(result, params.kernel.file);
1004 /* Read the Elf e_ident, e_type and e_machine fields to
1005 * determine Elf file type
1007 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1008 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1009 file.fs->close(&file);
1010 memset(&file, 0, sizeof(file));
1014 if (is_elf32(&loadinfo)) {
1015 if (!load_elf32(&file, &loadinfo)) {
1016 file.fs->close(&file);
1017 memset(&file, 0, sizeof(file));
1020 prom_printf(" Elf32 kernel loaded...\n");
1021 } else if (is_elf64(&loadinfo)) {
1022 if (!load_elf64(&file, &loadinfo)) {
1023 file.fs->close(&file);
1024 memset(&file, 0, sizeof(file));
1027 prom_printf(" Elf64 kernel loaded...\n");
1029 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1030 file.fs->close(&file);
1031 memset(&file, 0, sizeof(file));
1034 file.fs->close(&file);
1035 memset(&file, 0, sizeof(file));
1037 /* If sysmap, load it (only if booting a vmlinux).
1039 if (flat_vmlinux && params.sysmap.file) {
1040 prom_printf("Loading System.map ...\n");
1041 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1042 && params.sysmap.file[0] != '\\') {
1044 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1046 prom_printf ("malloc error\n");
1049 strcpy(loc,boot.file);
1050 strcat(loc,params.sysmap.file);
1051 free(params.sysmap.file);
1052 params.sysmap.file=loc;
1055 result = open_file(¶ms.sysmap, &file);
1056 if (result != FILE_ERR_OK) {
1057 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1058 prom_perror(result, params.sysmap.file);
1061 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1062 if (sysmap_base == (void *)-1) {
1063 prom_printf("Claim failed for sysmap memory\n");
1067 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1068 if (sysmap_size == 0)
1071 ((char *)sysmap_base)[sysmap_size++] = 0;
1073 file.fs->close(&file);
1074 memset(&file, 0, sizeof(file));
1077 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1078 sysmap_base, sysmap_size >> 10);
1079 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1081 prom_printf("System.map load failed !\n");
1086 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1087 * can't tell the size it will be so we claim an arbitrary amount
1090 if (flat_vmlinux && params.rd.file) {
1091 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1092 && params.kernel.file[0] != '\\')
1095 loc=(char*)malloc(strlen(params.rd.file)+3);
1097 prom_printf ("Malloc error\n");
1100 strcpy(loc,boot.file);
1101 strcat(loc,params.rd.file);
1102 free(params.rd.file);
1105 prom_printf("Loading ramdisk...\n");
1106 result = open_file(¶ms.rd, &file);
1107 if (result != FILE_ERR_OK) {
1108 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1109 prom_perror(result, params.rd.file);
1112 #define INITRD_CHUNKSIZE 0x100000
1113 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1114 if (initrd_base == (void *)-1) {
1115 prom_printf("Claim failed for initrd memory\n");
1118 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1119 if (initrd_size == 0)
1121 initrd_read = initrd_size;
1122 initrd_more = initrd_base;
1123 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1124 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1125 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1126 if (initrd_more != initrd_want) {
1127 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1131 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1132 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1133 initrd_size += initrd_read;
1136 file.fs->close(&file);
1137 memset(&file, 0, sizeof(file));
1140 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1141 initrd_base, initrd_size >> 10);
1143 prom_printf("ramdisk load failed !\n");
1148 DEBUG_F("setting kernel args to: %s\n", params.args);
1149 prom_setargs(params.args);
1150 DEBUG_F("flushing icache...");
1151 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1156 * Fill new boot infos (only if booting a vmlinux).
1158 * The birec is low on memory, probably inside the malloc pool,
1159 * so we don't write it earlier. At this point, we should not
1160 * use anything coming from the malloc pool.
1162 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1164 /* We make sure it's mapped. We map only 64k for now, it's
1165 * plenty enough we don't claim since this precise memory
1166 * range may already be claimed by the malloc pool.
1168 prom_map (birec, birec, 0x10000);
1169 DEBUG_F("birec at %p\n", birec);
1172 birec->tag = BI_FIRST;
1173 birec->size = sizeof(struct bi_record);
1174 birec = (struct bi_record *)((ulong)birec + birec->size);
1176 birec->tag = BI_BOOTLOADER_ID;
1177 sprintf( (char *)birec->data, "yaboot");
1178 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1179 birec = (struct bi_record *)((ulong)birec + birec->size);
1181 birec->tag = BI_MACHTYPE;
1182 birec->data[0] = _machine;
1183 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1184 birec = (struct bi_record *)((ulong)birec + birec->size);
1187 birec->tag = BI_SYSMAP;
1188 birec->data[0] = (ulong)sysmap_base;
1189 birec->data[1] = sysmap_size;
1190 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1191 birec = (struct bi_record *)((ulong)birec + birec->size);
1193 birec->tag = BI_LAST;
1194 birec->size = sizeof(struct bi_record);
1195 birec = (struct bi_record *)((ulong)birec + birec->size);
1198 /* compute the kernel's entry point. */
1199 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1201 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1202 DEBUG_F("kernel: arg1 = %p,\n"
1203 " arg2 = 0x%08lx,\n"
1207 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1209 DEBUG_F("Entering kernel...\n");
1211 /* call the kernel with our stack. */
1212 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1220 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1223 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1225 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1226 unsigned long addr, loadaddr;
1228 /* Read the rest of the Elf header... */
1229 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1230 prom_printf("\nCan't read Elf32 image header\n");
1234 DEBUG_F("Elf32 header:\n");
1235 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1236 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1237 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1238 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1239 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1240 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1241 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1242 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1243 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1244 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1246 loadinfo->entry = e->e_entry;
1248 if (e->e_phnum > MAX_HEADERS) {
1249 prom_printf ("Can only load kernels with one program header\n");
1253 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1255 prom_printf ("Malloc error\n");
1259 /* Now, we read the section header */
1260 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1261 prom_printf ("seek error\n");
1264 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1265 sizeof(Elf32_Phdr) * e->e_phnum) {
1266 prom_printf ("read error\n");
1270 /* Scan through the program header
1271 * HACK: We must return the _memory size of the kernel image, not the
1272 * file size (because we have to leave room before other boot
1273 * infos. This code works as a side effect of the fact that
1274 * we have one section and vaddr == p_paddr
1276 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1278 for (i = 0; i < e->e_phnum; ++i, ++p) {
1279 if (p->p_type != PT_LOAD || p->p_offset == 0)
1281 if (loadinfo->memsize == 0) {
1282 loadinfo->offset = p->p_offset;
1283 loadinfo->memsize = p->p_memsz;
1284 loadinfo->filesize = p->p_filesz;
1285 loadinfo->load_loc = p->p_vaddr;
1287 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1288 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1292 if (loadinfo->memsize == 0) {
1293 prom_printf("Can't find a loadable segment !\n");
1297 /* leave some room (1Mb) for boot infos */
1298 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1299 /* Claim OF memory */
1300 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1302 /* Determine whether we are trying to boot a vmlinux or some
1303 * other binary image (eg, zImage). We load vmlinux's at
1304 * KERNELADDR and all other binaries at their e_entry value.
1306 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1308 loadaddr = KERNELADDR;
1311 loadaddr = loadinfo->load_loc;
1314 /* On some systems, loadaddr may already be claimed, so try some
1315 * other nearby addresses before giving up.
1317 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1318 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1319 if (loadinfo->base != (void *)-1) break;
1321 if (loadinfo->base == (void *)-1) {
1322 prom_printf("Claim error, can't allocate kernel memory\n");
1326 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1327 loadinfo->base, loadinfo->memsize);
1328 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1329 loadaddr, loadinfo->memsize);
1331 /* Load the program segments... */
1333 for (i = 0; i < e->e_phnum; ++i, ++p) {
1334 unsigned long offset;
1335 if (p->p_type != PT_LOAD || p->p_offset == 0)
1338 /* Now, we skip to the image itself */
1339 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1340 prom_printf ("Seek error\n");
1341 prom_release(loadinfo->base, loadinfo->memsize);
1344 offset = p->p_vaddr - loadinfo->load_loc;
1345 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1346 prom_printf ("Read failed\n");
1347 prom_release(loadinfo->base, loadinfo->memsize);
1354 /* Return success at loading the Elf32 kernel */
1364 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1367 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1369 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1370 unsigned long addr, loadaddr;
1372 /* Read the rest of the Elf header... */
1373 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1374 prom_printf("\nCan't read Elf64 image header\n");
1378 DEBUG_F("Elf64 header:\n");
1379 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1380 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1381 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1382 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1383 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1384 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1385 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1386 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1387 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1388 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1390 loadinfo->entry = e->e_entry;
1392 if (e->e_phnum > MAX_HEADERS) {
1393 prom_printf ("Can only load kernels with one program header\n");
1397 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1399 prom_printf ("Malloc error\n");
1403 /* Now, we read the section header */
1404 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1405 prom_printf ("Seek error\n");
1408 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1409 sizeof(Elf64_Phdr) * e->e_phnum) {
1410 prom_printf ("Read error\n");
1414 /* Scan through the program header
1415 * HACK: We must return the _memory size of the kernel image, not the
1416 * file size (because we have to leave room before other boot
1417 * infos. This code works as a side effect of the fact that
1418 * we have one section and vaddr == p_paddr
1420 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1422 for (i = 0; i < e->e_phnum; ++i, ++p) {
1423 if (p->p_type != PT_LOAD || p->p_offset == 0)
1425 if (loadinfo->memsize == 0) {
1426 loadinfo->offset = p->p_offset;
1427 loadinfo->memsize = p->p_memsz;
1428 loadinfo->filesize = p->p_filesz;
1429 loadinfo->load_loc = p->p_vaddr;
1431 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1432 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1436 if (loadinfo->memsize == 0) {
1437 prom_printf("Can't find a loadable segment !\n");
1441 /* leave some room (1Mb) for boot infos */
1442 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1443 /* Claim OF memory */
1444 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1446 /* Determine whether we are trying to boot a vmlinux or some
1447 * other binary image (eg, zImage). We load vmlinux's at
1448 * KERNELADDR and all other binaries at their e_entry value.
1450 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1452 loadaddr = KERNELADDR;
1455 loadaddr = e->e_entry;
1458 /* On some systems, loadaddr may already be claimed, so try some
1459 * other nearby addresses before giving up.
1461 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1462 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1463 if (loadinfo->base != (void *)-1) break;
1465 if (loadinfo->base == (void *)-1) {
1466 prom_printf("Claim error, can't allocate kernel memory\n");
1470 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1471 loadinfo->base, loadinfo->memsize);
1472 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1473 loadaddr, loadinfo->memsize);
1475 /* Load the program segments... */
1477 for (i = 0; i < e->e_phnum; ++i, ++p) {
1478 unsigned long offset;
1479 if (p->p_type != PT_LOAD || p->p_offset == 0)
1482 /* Now, we skip to the image itself */
1483 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1484 prom_printf ("Seek error\n");
1485 prom_release(loadinfo->base, loadinfo->memsize);
1488 offset = p->p_vaddr - loadinfo->load_loc;
1489 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1490 prom_printf ("Read failed\n");
1491 prom_release(loadinfo->base, loadinfo->memsize);
1498 /* Return success at loading the Elf64 kernel */
1508 is_elf32(loadinfo_t *loadinfo)
1510 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1512 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1513 e->e_ident[EI_MAG1] == ELFMAG1 &&
1514 e->e_ident[EI_MAG2] == ELFMAG2 &&
1515 e->e_ident[EI_MAG3] == ELFMAG3 &&
1516 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1517 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1518 e->e_type == ET_EXEC &&
1519 e->e_machine == EM_PPC);
1523 is_elf64(loadinfo_t *loadinfo)
1525 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1527 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1528 e->e_ident[EI_MAG1] == ELFMAG1 &&
1529 e->e_ident[EI_MAG2] == ELFMAG2 &&
1530 e->e_ident[EI_MAG3] == ELFMAG3 &&
1531 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1532 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1533 e->e_type == ET_EXEC &&
1534 e->e_machine == EM_PPC64);
1540 #ifdef CONFIG_SET_COLORMAP
1541 static unsigned char default_colors[] = {
1560 prom_handle scrn = PROM_INVALID_HANDLE;
1562 /* Try Apple's mac-boot screen ihandle */
1563 result = (int)call_prom_return("interpret", 1, 2,
1564 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1565 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1567 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1569 /* Hrm... check to see if stdout is a display */
1570 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1571 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1572 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1573 DEBUG_F("got it ! stdout is a screen\n");
1576 /* Else, we try to open the package */
1577 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1578 DEBUG_F("Open screen result: %p\n", scrn);
1582 if (scrn == PROM_INVALID_HANDLE) {
1583 prom_printf("No screen device found !/n");
1587 prom_set_color(scrn, i, default_colors[i*3],
1588 default_colors[i*3+1], default_colors[i*3+2]);
1590 prom_printf("\x1b[1;37m\x1b[2;40m");
1592 for (i=0;i<16; i++) {
1593 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1594 ansi_color_table[i].index,
1595 ansi_color_table[i].value,
1596 ansi_color_table[i].name,
1597 ansi_color_table[i].name);
1598 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1599 ansi_color_table[i].index,
1600 ansi_color_table[i].value+10,
1601 ansi_color_table[i].name,
1602 ansi_color_table[i].name);
1604 prom_printf("\x1b[1;37m\x1b[2;40m");
1605 #endif /* COLOR_TEST */
1611 #endif /* CONFIG_SET_COLORMAP */
1619 char conf_path[1024];
1621 if (_machine == _MACH_Pmac)
1624 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1625 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1626 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1627 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1629 /* If conf= specified on command line, it overrides
1630 Usage: conf=device:partition,/path/to/conffile
1631 Example: On Open Firmware Prompt, type
1632 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1634 if (!strncmp(bootargs, "conf=", 5)) {
1635 DEBUG_F("Using conf argument in Open Firmware\n");
1636 char *end = strchr(bootargs,' ');
1640 strcpy(bootdevice, bootargs + 5);
1642 DEBUG_F("Using conf=%s\n", bootdevice);
1644 /* Remove conf=xxx from bootargs */
1646 memmove(bootargs, end+1, strlen(end+1)+1);
1650 if (bootdevice[0] == 0) {
1651 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1652 DEBUG_F("boot-device = %s\n", bootdevice);
1654 if (bootdevice[0] == 0) {
1655 prom_printf("Couldn't determine boot device\n");
1659 if (bootoncelabel[0] == 0) {
1660 prom_get_options("boot-once", bootoncelabel,
1661 sizeof(bootoncelabel));
1662 if (bootoncelabel[0] != 0)
1663 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1665 prom_set_options("boot-once", NULL, 0);
1667 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1668 prom_printf("%s: Unable to parse\n", bootdevice);
1671 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1672 boot.dev, boot.part, boot.file);
1675 if (_machine == _MACH_chrp)
1676 boot.file = "/etc/";
1677 else if (strlen(boot.file)) {
1678 if (!strncmp(boot.file, "\\\\", 2))
1682 p = last = boot.file;
1692 if (strlen(boot.file))
1693 strcat(boot.file, "\\");
1696 strcpy(conf_path, boot.file);
1697 strcat(conf_path, CONFIG_FILE_NAME);
1698 boot.file = conf_path;
1699 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1700 boot.dev, boot.part, boot.file);
1704 * If we're doing a netboot, first look for one which matches our
1707 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1708 prom_printf("Try to netboot\n");
1709 useconf = load_my_config_file(&boot);
1713 useconf = load_config_file(&boot);
1715 prom_printf("Welcome to yaboot version " VERSION "\n");
1716 prom_printf("Enter \"help\" to get some basic usage information\n");
1718 /* I am fed up with lusers using the wrong partition type and
1719 mailing me *when* it breaks */
1721 if (_machine == _MACH_Pmac) {
1722 char *entry = cfg_get_strg(0, "ptypewarning");
1725 warn = strcmp(entry,
1726 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1728 ptype = get_part_type(boot.dev, boot.part);
1729 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1730 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1731 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1739 prom_printf("Bye.\n");
1745 * c-file-style: "k&r"