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 strcpy(fspec.file, "/etc/");
493 strcat(fspec.file, prom_get_ip(packet));
495 while (strlen(strrchr(fspec.file, '/')+1)) {
496 rc = load_config_file(&fspec);
499 /* Chop one digit off the end, try again */
500 fspec.file[strlen(fspec.file) - 1] = '\0';
504 if (rc) /* modify original only on success */
505 orig_fspec->file = fspec.file;
511 void maintabfunc (void)
515 prom_printf("boot: %s", cbuff);
520 word_split(char **linep, char **paramsp)
535 while (*p != 0 && *p != ' ')
544 make_params(char *label, char *params)
547 static char buffer[2048];
552 p = cfg_get_strg(label, "literal");
564 p = cfg_get_strg(label, "root");
571 if (cfg_get_flag(label, "read-only")) {
575 if (cfg_get_flag(label, "read-write")) {
579 p = cfg_get_strg(label, "ramdisk");
581 strcpy (q, "ramdisk=");
586 p = cfg_get_strg(label, "initrd-size");
588 strcpy (q, "ramdisk_size=");
593 if (cfg_get_flag(label, "novideo")) {
594 strcpy (q, "video=ofonly");
598 p = cfg_get_strg (label, "append");
605 pause_after = cfg_get_flag (label, "pause-after");
606 p = cfg_get_strg(label, "pause-message");
615 void check_password(char *str)
619 prom_printf("\n%s", str);
620 for (i = 0; i < 3; i++) {
621 prom_printf ("\nPassword: ");
623 cmdedit ((void (*)(void)) 0, 1);
625 #ifdef USE_MD5_PASSWORDS
626 if (!strncmp (password, "$1$", 3)) {
627 if (!check_md5_password(passwdbuff, password))
630 else if (!strcmp (password, passwdbuff))
633 if (!strcmp (password, passwdbuff))
635 #endif /* USE_MD5_PASSWORDS */
638 prom_printf ("Incorrect password. Try again.");
641 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
642 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
643 " ||----w |\n || ||\n");
645 prom_interpret("reset-all");
648 int get_params(struct boot_param_t* params)
652 char defdevice_bak[1024];
655 char *imagename = 0, *label;
660 static int first = 1;
661 static char imagepath[1024];
662 static char initrdpath[1024];
663 static char sysmappath[1024];
666 memset(params, 0, sizeof(*params));
668 params->kernel.part = -1;
669 params->rd.part = -1;
670 params->sysmap.part = -1;
677 imagename = bootargs;
678 word_split(&imagename, ¶ms->args);
679 timeout = DEFAULT_TIMEOUT;
681 prom_printf("Default supplied on the command line: %s ", imagename);
683 prom_printf("%s", params->args);
686 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
687 timeout = simple_strtol(q, NULL, 0);
690 prom_printf("boot: ");
695 end = beg + 100 * timeout;
697 c = prom_nbgetchar();
698 } while (c == -1 && prom_getms() <= end);
702 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
708 if (c != -1 && c != '\n' && c != '\r') {
711 } else if (c >= ' ') {
714 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
717 prom_printf("%s\n", cbuff);
722 if (c == '\n' || c == '\r') {
724 if (bootoncelabel[0] != 0)
725 imagename = bootoncelabel;
727 imagename = cfg_get_default();
730 prom_printf("%s", imagename);
732 prom_printf(" %s", params->args);
734 } else if (!singlekey) {
735 cmdedit(maintabfunc, 0);
737 strcpy(given_bootargs, cbuff);
738 given_bootargs_by_user = 1;
740 word_split(&imagename, ¶ms->args);
743 /* chrp gets this wrong, force it -- Cort */
744 if ( useconf && (!imagename || imagename[0] == 0 ))
745 imagename = cfg_get_default();
748 defdevice = boot.dev;
750 strcpy(defdevice_bak,defdevice);
753 defdevice = cfg_get_strg(0, "device");
754 p = cfg_get_strg(0, "partition");
756 n = simple_strtol(p, &endp, 10);
757 if (endp != p && *endp == 0)
760 p = cfg_get_strg(0, "pause-message");
763 if (cfg_get_flag(0, "restricted"))
765 p = cfg_get_strg(imagename, "image");
769 defdevice = cfg_get_strg(label, "device");
770 if(!defdevice) defdevice=boot.dev;
771 p = cfg_get_strg(label, "partition");
773 n = simple_strtol(p, &endp, 10);
774 if (endp != p && *endp == 0)
777 if (cfg_get_flag(label, "restricted"))
780 if (params->args && password && restricted)
781 check_password ("To specify arguments for this image "
782 "you must enter the password.");
783 else if (password && !restricted)
784 check_password ("This image is restricted.");
786 params->args = make_params(label, params->args);
790 if (!strcmp (imagename, "help")) {
791 /* FIXME: defdevice shouldn't need to be reset all over the place */
792 if(!defdevice) defdevice = boot.dev;
794 "\nPress the tab key for a list of defined images.\n"
795 "The label marked with a \"*\" is is the default image, "
796 "press <return> to boot it.\n\n"
797 "To boot any other label simply type its name and press <return>.\n\n"
798 "To boot a kernel image which is not defined in the yaboot configuration \n"
799 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
800 "\"device:\" is the OpenFirmware device path to the disk the image \n"
801 "resides on, and \"partno\" is the partition number the image resides on.\n"
802 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
803 "device, if you only specify a filename you should not start it with a \",\"\n\n"
804 "To load an alternative config file rather than /etc/yaboot.conf, enter\n"
805 "its device, partno and path, on Open Firmware Prompt:\n"
806 "boot conf=device:partno,/path/to/configfile\n."
807 "To reload the config file or load a new one, use the \"conf\" command\n"
808 "on Yaboot's prompt:\n"
809 "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n"
810 "If you omit \"device\" and \"partno\", Yaboot will use their current\n"
811 "values. You can check them by entering \"conf\" on Yaboot's prompt.\n");
816 if (!strcmp (imagename, "halt")) {
818 check_password ("Restricted command.");
822 if (!strcmp (imagename, "bye")) {
824 check_password ("Restricted command.");
830 if (!strncmp (imagename, "conf", 4)) {
832 // imagename = "conf file=blah dev=bleh part=blih"
833 DEBUG_F("Loading user-specified config file: %s\n",imagename);
835 check_password ("Restricted command.");
839 // args= "file=blah dev=bleh part=blih"
840 char *args = params->args;
844 // set a pointer to the first space in args
845 char *space = strchr(args,' ');
849 char temp[1024] = "0";
851 // copy next argument to temp
852 strncpy(temp, args, space-args);
854 // parse temp and set boot arguments
855 if (!strncmp (temp, "file=", 5)){
856 DEBUG_F("conf file: %s\n", temp+5);
857 strcpy(boot.file, temp+5);
858 } else if (!strncmp (temp, "device=", 7)){
859 DEBUG_F("conf device: %s\n", temp+7);
860 strcpy(boot.dev, temp+7);
861 } else if (!strncmp (temp, "partition=", 10)){
862 DEBUG_F("conf partition: %s\n", temp+10);
863 boot.part=simple_strtol(temp+10,NULL,10);
867 // set the pointer to the next space in args;
868 // set the loop control variable
869 if (strlen(space)>1){
870 // Go to the next argument
874 if (strchr(args,' ') == NULL)
875 space = &args[strlen(args)];
877 space = strchr(args,' ');
884 prom_printf("Loading config file...\n");
885 useconf = load_config_file(&boot);
887 if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
888 timeout = simple_strtol(q, NULL, 0);
890 prom_printf("Restoring default values.\n");
891 strcpy(boot.file,"");
892 strcpy(boot.dev, defdevice_bak);
897 prom_printf("Current configuration:\n");
898 prom_printf("device: %s\n", boot.dev);
900 prom_printf("partition: auto\n");
902 prom_printf("partition: %d\n", boot.part);
903 if (strlen(boot.file))
904 prom_printf("file: %s\n", boot.file);
906 prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME);
915 if (imagename[0] == '$') {
916 /* forth command string */
918 check_password ("OpenFirmware commands are restricted.");
919 prom_interpret(imagename+1);
923 strncpy(imagepath, imagename, 1024);
925 if (!label && password)
926 check_password ("To boot a custom image you must enter the password.");
928 if (!parse_device_path(imagepath, defdevice, defpart,
929 "/vmlinux", ¶ms->kernel)) {
930 prom_printf("%s: Unable to parse\n", imagepath);
933 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
934 params->kernel.part, params->kernel.file);
937 p = cfg_get_strg(label, "initrd");
939 DEBUG_F("Parsing initrd path <%s>\n", p);
940 strncpy(initrdpath, p, 1024);
941 if (!parse_device_path(initrdpath, defdevice, defpart,
942 "/root.bin", ¶ms->rd)) {
943 prom_printf("%s: Unable to parse\n", imagepath);
947 p = cfg_get_strg(label, "sysmap");
949 DEBUG_F("Parsing sysmap path <%s>\n", p);
950 strncpy(sysmappath, p, 1024);
951 if (!parse_device_path(sysmappath, defdevice, defpart,
952 "/boot/System.map", ¶ms->sysmap)) {
953 prom_printf("%s: Unable to parse\n", imagepath);
961 /* This is derived from quik core. To be changed to first parse the headers
962 * doing lazy-loading, and then claim the memory before loading the kernel
964 * We also need to add initrd support to this whole mecanism
969 #define MAX_HEADERS 32
971 struct boot_file_t file;
973 static struct boot_param_t params;
975 unsigned long initrd_size;
977 unsigned long sysmap_size;
978 kernel_entry_t kernel_entry;
979 struct bi_record* birec;
982 void *initrd_more,*initrd_want;
983 unsigned long initrd_read;
985 loadinfo.load_loc = 0;
993 if (get_params(¶ms))
995 if (!params.kernel.file)
998 prom_printf("Please wait, loading kernel...\n");
1000 memset(&file, 0, sizeof(file));
1002 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
1003 && params.kernel.file[0] != '\\') {
1004 loc=(char*)malloc(strlen(params.kernel.file)+3);
1006 prom_printf ("malloc error\n");
1009 strcpy(loc,boot.file);
1010 strcat(loc,params.kernel.file);
1011 free(params.kernel.file);
1012 params.kernel.file=loc;
1014 result = open_file(¶ms.kernel, &file);
1015 if (result != FILE_ERR_OK) {
1016 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
1017 prom_perror(result, params.kernel.file);
1021 /* Read the Elf e_ident, e_type and e_machine fields to
1022 * determine Elf file type
1024 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
1025 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
1026 file.fs->close(&file);
1027 memset(&file, 0, sizeof(file));
1031 if (is_elf32(&loadinfo)) {
1032 if (!load_elf32(&file, &loadinfo)) {
1033 file.fs->close(&file);
1034 memset(&file, 0, sizeof(file));
1037 prom_printf(" Elf32 kernel loaded...\n");
1038 } else if (is_elf64(&loadinfo)) {
1039 if (!load_elf64(&file, &loadinfo)) {
1040 file.fs->close(&file);
1041 memset(&file, 0, sizeof(file));
1044 prom_printf(" Elf64 kernel loaded...\n");
1046 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1047 file.fs->close(&file);
1048 memset(&file, 0, sizeof(file));
1051 file.fs->close(&file);
1052 memset(&file, 0, sizeof(file));
1054 /* If sysmap, load it (only if booting a vmlinux).
1056 if (flat_vmlinux && params.sysmap.file) {
1057 prom_printf("Loading System.map ...\n");
1058 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1059 && params.sysmap.file[0] != '\\') {
1061 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1063 prom_printf ("malloc error\n");
1066 strcpy(loc,boot.file);
1067 strcat(loc,params.sysmap.file);
1068 free(params.sysmap.file);
1069 params.sysmap.file=loc;
1072 result = open_file(¶ms.sysmap, &file);
1073 if (result != FILE_ERR_OK) {
1074 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1075 prom_perror(result, params.sysmap.file);
1078 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1079 if (sysmap_base == (void *)-1) {
1080 prom_printf("Claim failed for sysmap memory\n");
1084 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1085 if (sysmap_size == 0)
1088 ((char *)sysmap_base)[sysmap_size++] = 0;
1090 file.fs->close(&file);
1091 memset(&file, 0, sizeof(file));
1094 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1095 sysmap_base, sysmap_size >> 10);
1096 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1098 prom_printf("System.map load failed !\n");
1103 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1104 * can't tell the size it will be so we claim an arbitrary amount
1107 if (flat_vmlinux && params.rd.file) {
1108 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1109 && params.kernel.file[0] != '\\')
1112 loc=(char*)malloc(strlen(params.rd.file)+3);
1114 prom_printf ("Malloc error\n");
1117 strcpy(loc,boot.file);
1118 strcat(loc,params.rd.file);
1119 free(params.rd.file);
1122 prom_printf("Loading ramdisk...\n");
1123 result = open_file(¶ms.rd, &file);
1124 if (result != FILE_ERR_OK) {
1125 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1126 prom_perror(result, params.rd.file);
1129 #define INITRD_CHUNKSIZE 0x100000
1130 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1131 if (initrd_base == (void *)-1) {
1132 prom_printf("Claim failed for initrd memory\n");
1135 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1136 if (initrd_size == 0)
1138 initrd_read = initrd_size;
1139 initrd_more = initrd_base;
1140 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1141 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1142 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1143 if (initrd_more != initrd_want) {
1144 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1148 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1149 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1150 initrd_size += initrd_read;
1153 file.fs->close(&file);
1154 memset(&file, 0, sizeof(file));
1157 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1158 initrd_base, initrd_size >> 10);
1160 prom_printf("ramdisk load failed !\n");
1165 DEBUG_F("setting kernel args to: %s\n", params.args);
1166 prom_setargs(params.args);
1167 DEBUG_F("flushing icache...");
1168 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1173 * Fill new boot infos (only if booting a vmlinux).
1175 * The birec is low on memory, probably inside the malloc pool,
1176 * so we don't write it earlier. At this point, we should not
1177 * use anything coming from the malloc pool.
1179 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1181 /* We make sure it's mapped. We map only 64k for now, it's
1182 * plenty enough we don't claim since this precise memory
1183 * range may already be claimed by the malloc pool.
1185 prom_map (birec, birec, 0x10000);
1186 DEBUG_F("birec at %p\n", birec);
1189 birec->tag = BI_FIRST;
1190 birec->size = sizeof(struct bi_record);
1191 birec = (struct bi_record *)((ulong)birec + birec->size);
1193 birec->tag = BI_BOOTLOADER_ID;
1194 sprintf( (char *)birec->data, "yaboot");
1195 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1196 birec = (struct bi_record *)((ulong)birec + birec->size);
1198 birec->tag = BI_MACHTYPE;
1199 birec->data[0] = _machine;
1200 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1201 birec = (struct bi_record *)((ulong)birec + birec->size);
1204 birec->tag = BI_SYSMAP;
1205 birec->data[0] = (ulong)sysmap_base;
1206 birec->data[1] = sysmap_size;
1207 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1208 birec = (struct bi_record *)((ulong)birec + birec->size);
1210 birec->tag = BI_LAST;
1211 birec->size = sizeof(struct bi_record);
1212 birec = (struct bi_record *)((ulong)birec + birec->size);
1215 /* compute the kernel's entry point. */
1216 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1218 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1219 DEBUG_F("kernel: arg1 = %p,\n"
1220 " arg2 = 0x%08lx,\n"
1224 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1226 DEBUG_F("Entering kernel...\n");
1228 /* call the kernel with our stack. */
1229 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1237 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1240 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1242 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1243 unsigned long addr, loadaddr;
1245 /* Read the rest of the Elf header... */
1246 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1247 prom_printf("\nCan't read Elf32 image header\n");
1251 DEBUG_F("Elf32 header:\n");
1252 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1253 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1254 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1255 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1256 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1257 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1258 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1259 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1260 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1261 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1263 loadinfo->entry = e->e_entry;
1265 if (e->e_phnum > MAX_HEADERS) {
1266 prom_printf ("Can only load kernels with one program header\n");
1270 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1272 prom_printf ("Malloc error\n");
1276 /* Now, we read the section header */
1277 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1278 prom_printf ("seek error\n");
1281 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1282 sizeof(Elf32_Phdr) * e->e_phnum) {
1283 prom_printf ("read error\n");
1287 /* Scan through the program header
1288 * HACK: We must return the _memory size of the kernel image, not the
1289 * file size (because we have to leave room before other boot
1290 * infos. This code works as a side effect of the fact that
1291 * we have one section and vaddr == p_paddr
1293 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1295 for (i = 0; i < e->e_phnum; ++i, ++p) {
1296 if (p->p_type != PT_LOAD || p->p_offset == 0)
1298 if (loadinfo->memsize == 0) {
1299 loadinfo->offset = p->p_offset;
1300 loadinfo->memsize = p->p_memsz;
1301 loadinfo->filesize = p->p_filesz;
1302 loadinfo->load_loc = p->p_vaddr;
1304 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1305 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1309 if (loadinfo->memsize == 0) {
1310 prom_printf("Can't find a loadable segment !\n");
1314 /* leave some room (1Mb) for boot infos */
1315 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1316 /* Claim OF memory */
1317 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1319 /* Determine whether we are trying to boot a vmlinux or some
1320 * other binary image (eg, zImage). We load vmlinux's at
1321 * KERNELADDR and all other binaries at their e_entry value.
1323 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1325 loadaddr = KERNELADDR;
1328 loadaddr = loadinfo->load_loc;
1331 /* On some systems, loadaddr may already be claimed, so try some
1332 * other nearby addresses before giving up.
1334 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1335 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1336 if (loadinfo->base != (void *)-1) break;
1338 if (loadinfo->base == (void *)-1) {
1339 prom_printf("Claim error, can't allocate kernel memory\n");
1343 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1344 loadinfo->base, loadinfo->memsize);
1345 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1346 loadaddr, loadinfo->memsize);
1348 /* Load the program segments... */
1350 for (i = 0; i < e->e_phnum; ++i, ++p) {
1351 unsigned long offset;
1352 if (p->p_type != PT_LOAD || p->p_offset == 0)
1355 /* Now, we skip to the image itself */
1356 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1357 prom_printf ("Seek error\n");
1358 prom_release(loadinfo->base, loadinfo->memsize);
1361 offset = p->p_vaddr - loadinfo->load_loc;
1362 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1363 prom_printf ("Read failed\n");
1364 prom_release(loadinfo->base, loadinfo->memsize);
1371 /* Return success at loading the Elf32 kernel */
1381 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1384 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1386 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1387 unsigned long addr, loadaddr;
1389 /* Read the rest of the Elf header... */
1390 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1391 prom_printf("\nCan't read Elf64 image header\n");
1395 DEBUG_F("Elf64 header:\n");
1396 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1397 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1398 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1399 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1400 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1401 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1402 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1403 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1404 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1405 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1407 loadinfo->entry = e->e_entry;
1409 if (e->e_phnum > MAX_HEADERS) {
1410 prom_printf ("Can only load kernels with one program header\n");
1414 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1416 prom_printf ("Malloc error\n");
1420 /* Now, we read the section header */
1421 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1422 prom_printf ("Seek error\n");
1425 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1426 sizeof(Elf64_Phdr) * e->e_phnum) {
1427 prom_printf ("Read error\n");
1431 /* Scan through the program header
1432 * HACK: We must return the _memory size of the kernel image, not the
1433 * file size (because we have to leave room before other boot
1434 * infos. This code works as a side effect of the fact that
1435 * we have one section and vaddr == p_paddr
1437 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1439 for (i = 0; i < e->e_phnum; ++i, ++p) {
1440 if (p->p_type != PT_LOAD || p->p_offset == 0)
1442 if (loadinfo->memsize == 0) {
1443 loadinfo->offset = p->p_offset;
1444 loadinfo->memsize = p->p_memsz;
1445 loadinfo->filesize = p->p_filesz;
1446 loadinfo->load_loc = p->p_vaddr;
1448 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1449 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1453 if (loadinfo->memsize == 0) {
1454 prom_printf("Can't find a loadable segment !\n");
1458 /* leave some room (1Mb) for boot infos */
1459 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1460 /* Claim OF memory */
1461 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1463 /* Determine whether we are trying to boot a vmlinux or some
1464 * other binary image (eg, zImage). We load vmlinux's at
1465 * KERNELADDR and all other binaries at their e_entry value.
1467 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1469 loadaddr = KERNELADDR;
1472 loadaddr = e->e_entry;
1475 /* On some systems, loadaddr may already be claimed, so try some
1476 * other nearby addresses before giving up.
1478 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1479 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1480 if (loadinfo->base != (void *)-1) break;
1482 if (loadinfo->base == (void *)-1) {
1483 prom_printf("Claim error, can't allocate kernel memory\n");
1487 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1488 loadinfo->base, loadinfo->memsize);
1489 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1490 loadaddr, loadinfo->memsize);
1492 /* Load the program segments... */
1494 for (i = 0; i < e->e_phnum; ++i, ++p) {
1495 unsigned long offset;
1496 if (p->p_type != PT_LOAD || p->p_offset == 0)
1499 /* Now, we skip to the image itself */
1500 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1501 prom_printf ("Seek error\n");
1502 prom_release(loadinfo->base, loadinfo->memsize);
1505 offset = p->p_vaddr - loadinfo->load_loc;
1506 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1507 prom_printf ("Read failed\n");
1508 prom_release(loadinfo->base, loadinfo->memsize);
1515 /* Return success at loading the Elf64 kernel */
1525 is_elf32(loadinfo_t *loadinfo)
1527 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1529 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1530 e->e_ident[EI_MAG1] == ELFMAG1 &&
1531 e->e_ident[EI_MAG2] == ELFMAG2 &&
1532 e->e_ident[EI_MAG3] == ELFMAG3 &&
1533 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1534 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1535 e->e_type == ET_EXEC &&
1536 e->e_machine == EM_PPC);
1540 is_elf64(loadinfo_t *loadinfo)
1542 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1544 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1545 e->e_ident[EI_MAG1] == ELFMAG1 &&
1546 e->e_ident[EI_MAG2] == ELFMAG2 &&
1547 e->e_ident[EI_MAG3] == ELFMAG3 &&
1548 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1549 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1550 e->e_type == ET_EXEC &&
1551 e->e_machine == EM_PPC64);
1557 #ifdef CONFIG_SET_COLORMAP
1558 static unsigned char default_colors[] = {
1577 prom_handle scrn = PROM_INVALID_HANDLE;
1579 /* Try Apple's mac-boot screen ihandle */
1580 result = (int)call_prom_return("interpret", 1, 2,
1581 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1582 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1584 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1586 /* Hrm... check to see if stdout is a display */
1587 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1588 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1589 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1590 DEBUG_F("got it ! stdout is a screen\n");
1593 /* Else, we try to open the package */
1594 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1595 DEBUG_F("Open screen result: %p\n", scrn);
1599 if (scrn == PROM_INVALID_HANDLE) {
1600 prom_printf("No screen device found !/n");
1604 prom_set_color(scrn, i, default_colors[i*3],
1605 default_colors[i*3+1], default_colors[i*3+2]);
1607 prom_printf("\x1b[1;37m\x1b[2;40m");
1609 for (i=0;i<16; i++) {
1610 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1611 ansi_color_table[i].index,
1612 ansi_color_table[i].value,
1613 ansi_color_table[i].name,
1614 ansi_color_table[i].name);
1615 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1616 ansi_color_table[i].index,
1617 ansi_color_table[i].value+10,
1618 ansi_color_table[i].name,
1619 ansi_color_table[i].name);
1621 prom_printf("\x1b[1;37m\x1b[2;40m");
1622 #endif /* COLOR_TEST */
1628 #endif /* CONFIG_SET_COLORMAP */
1636 char conf_path[1024];
1638 if (_machine == _MACH_Pmac)
1641 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1642 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1643 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1644 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1646 /* If conf= specified on command line, it overrides
1647 Usage: conf=device:partition,/path/to/conffile
1648 Example: On Open Firmware Prompt, type
1649 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1651 if (!strncmp(bootargs, "conf=", 5)) {
1652 DEBUG_F("Using conf argument in Open Firmware\n");
1653 char *end = strchr(bootargs,' ');
1657 strcpy(bootdevice, bootargs + 5);
1659 DEBUG_F("Using conf=%s\n", bootdevice);
1661 /* Remove conf=xxx from bootargs */
1663 memmove(bootargs, end+1, strlen(end+1)+1);
1667 if (bootdevice[0] == 0) {
1668 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1669 DEBUG_F("boot-device = %s\n", bootdevice);
1671 if (bootdevice[0] == 0) {
1672 prom_printf("Couldn't determine boot device\n");
1676 if (bootoncelabel[0] == 0) {
1677 prom_get_options("boot-once", bootoncelabel,
1678 sizeof(bootoncelabel));
1679 if (bootoncelabel[0] != 0)
1680 DEBUG_F("boot-once: [%s]\n", bootoncelabel);
1682 prom_set_options("boot-once", NULL, 0);
1684 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1685 prom_printf("%s: Unable to parse\n", bootdevice);
1688 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1689 boot.dev, boot.part, boot.file);
1692 if (_machine == _MACH_chrp)
1693 boot.file = "/etc/";
1694 else if (strlen(boot.file)) {
1695 if (!strncmp(boot.file, "\\\\", 2))
1699 p = last = boot.file;
1709 if (strlen(boot.file))
1710 strcat(boot.file, "\\");
1713 strcpy(conf_path, boot.file);
1714 strcat(conf_path, CONFIG_FILE_NAME);
1715 boot.file = conf_path;
1716 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1717 boot.dev, boot.part, boot.file);
1721 * If we're doing a netboot, first look for one which matches our
1724 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1725 prom_printf("Try to netboot\n");
1726 useconf = load_my_config_file(&boot);
1730 useconf = load_config_file(&boot);
1732 prom_printf("Welcome to yaboot version " VERSION "\n");
1733 prom_printf("Enter \"help\" to get some basic usage information\n");
1735 /* I am fed up with lusers using the wrong partition type and
1736 mailing me *when* it breaks */
1738 if (_machine == _MACH_Pmac) {
1739 char *entry = cfg_get_strg(0, "ptypewarning");
1742 warn = strcmp(entry,
1743 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1745 ptype = get_part_type(boot.dev, boot.part);
1746 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1747 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1748 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1756 prom_printf("Bye.\n");
1762 * c-file-style: "k&r"