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 *password = NULL;
116 struct boot_fspec_t boot;
117 int _machine = _MACH_Pmac;
120 #ifdef CONFIG_COLOR_TEXT
122 /* Color values for text ui */
123 static struct ansi_color_t {
127 } ansi_color_table[] = {
135 { "light-gray", 0, 37 },
136 { "dark-gray", 1, 30 },
137 { "light-blue", 1, 31 },
138 { "light-green", 1, 32 },
139 { "light-cyan", 1, 33 },
140 { "light-red", 1, 34 },
141 { "light-purple", 1, 35 },
147 /* Default colors for text ui */
150 #endif /* CONFIG_COLOR_TEXT */
154 static int test_data = 0;
156 static int pause_after;
157 static char *pause_message = "Type go<return> to continue.\n";
158 static char given_bootargs[1024];
159 static int given_bootargs_by_user = 0;
161 extern unsigned char linux_logo_red[];
162 extern unsigned char linux_logo_green[];
163 extern unsigned char linux_logo_blue[];
165 #define DEFAULT_TIMEOUT -1
167 /* Entry, currently called directly by crt0 (bss not inited) */
169 extern char* __bss_start;
172 static struct first_info *quik_fip = NULL;
175 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
178 void* malloc_base = NULL;
181 /* OF seems to do it, but I'm not very confident */
182 memset(&__bss_start, 0, &_end - &__bss_start);
184 /* Check for quik first stage bootloader (but I don't think we are
185 * compatible with it anyway, I'll look into backporting to older OF
188 if (r5 == 0xdeadbeef) {
190 quik_fip = (struct first_info *)r4;
193 /* Initialize OF interface */
194 prom_init ((prom_entry) r5);
196 /* Allocate some memory for malloc'ator */
197 malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
198 if (malloc_base == (void *)-1) {
199 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
200 MALLOCSIZE, MALLOCADDR);
203 malloc_init(malloc_base, MALLOCSIZE);
204 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
205 malloc_base, MALLOCSIZE);
207 /* A few useless DEBUG_F's */
208 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
209 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
210 DEBUG_F("test_data : %d (should be 0)\n", test_data);
211 DEBUG_F("&test_data : %p\n", &test_data);
212 DEBUG_F("&test_bss : %p\n", &test_bss);
213 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
215 /* ask the OF info if we're a chrp or pmac */
216 /* we need to set _machine before calling finish_device_tree */
217 root = prom_finddevice("/");
219 static char model[256];
220 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
221 !strncmp("chrp", model, 4))
222 _machine = _MACH_chrp;
224 if (prom_getprop(root, "model", model, 256 ) > 0 &&
225 !strncmp(model, "IBM", 3))
226 _machine = _MACH_chrp;
230 DEBUG_F("Running on _machine = %d\n", _machine);
234 result = yaboot_main();
236 /* Get rid of malloc pool */
238 prom_release(malloc_base, MALLOCSIZE);
239 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
249 #ifdef CONFIG_COLOR_TEXT
251 * Validify color for text ui
254 check_color_text_ui(char *color)
257 while(ansi_color_table[i].name) {
258 if (!strcmp(color, ansi_color_table[i].name))
264 #endif /* CONFIG_COLOR_TEXT */
267 void print_message_file(char *filename)
271 char *defdev = boot.dev;
272 int defpart = boot.part;
277 struct boot_file_t file;
278 struct boot_fspec_t msgfile;
280 defdev = cfg_get_strg(0, "device");
283 p = cfg_get_strg(0, "partition");
285 n = simple_strtol(p, &endp, 10);
286 if (endp != p && *endp == 0)
290 strncpy(msgpath, filename, sizeof(msgpath));
291 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
292 prom_printf("%s: Unable to parse\n", msgpath);
296 result = open_file(&msgfile, &file);
297 if (result != FILE_ERR_OK) {
298 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
299 prom_perror(result, msgfile.file);
308 memset(msg, 0, 2001);
310 if (file.fs->read(&file, 2000, msg) <= 0)
313 prom_printf("%s", msg);
317 file.fs->close(&file);
322 /* Currently, the config file must be at the root of the filesystem.
323 * todo: recognize the full path to myself and use it to load the
324 * config file. Handle the "\\" (blessed system folder)
327 load_config_file(struct boot_fspec_t *orig_fspec)
329 char *conf_file = NULL, *p;
330 struct boot_file_t file;
331 int sz, opened = 0, result = 0;
333 struct boot_fspec_t fspec = *orig_fspec;
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");
342 /* Build the path to the file */
343 if (_machine == _MACH_chrp)
344 strcpy(conf_path, "/etc/");
347 if (fspec.file && *fspec.file)
348 strcat(conf_path, fspec.file);
350 strcat(conf_path, CONFIG_FILE_NAME);
353 fspec.file = conf_path;
354 result = open_file(&fspec, &file);
355 if (result != FILE_ERR_OK) {
356 prom_printf("%s:%d,", fspec.dev, fspec.part);
357 prom_perror(result, fspec.file);
358 prom_printf("Can't open config file\n");
364 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
366 prom_printf("Error, can't read config file\n");
369 prom_printf("Config file read, %d bytes\n", sz);
373 file.fs->close(&file);
376 /* Call the parsing code in cfg.c */
377 if (cfg_parse(conf_path, conf_file, sz) < 0) {
378 prom_printf ("Syntax error or read error config\n");
382 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
384 /* Now, we do the initialisations stored in the config file */
385 p = cfg_get_strg(0, "init-code");
389 password = cfg_get_strg(0, "password");
391 #ifdef CONFIG_COLOR_TEXT
392 p = cfg_get_strg(0, "fgcolor");
394 DEBUG_F("fgcolor=%s\n", p);
395 fgcolor = check_color_text_ui(p);
397 prom_printf("Invalid fgcolor: \"%s\".\n", p);
400 p = cfg_get_strg(0, "bgcolor");
402 DEBUG_F("bgcolor=%s\n", p);
403 bgcolor = check_color_text_ui(p);
405 prom_printf("Invalid bgcolor: \"%s\".\n", p);
409 sprintf(temp, "%x to background-color", bgcolor);
410 prom_interpret(temp);
417 sprintf(temp, "%x to foreground-color", fgcolor);
418 prom_interpret(temp);
420 #endif /* CONFIG_COLOR_TEXT */
422 p = cfg_get_strg(0, "init-message");
424 prom_printf("%s\n", p);
426 p = cfg_get_strg(0, "message");
428 print_message_file(p);
435 file.fs->close(&file);
444 * "bootp-response" is the property name which is specified in
445 * the recommended practice doc for obp-tftp. However, pmac
446 * provides a "dhcp-response" property and chrp provides a
447 * "bootpreply-packet" property. The latter appears to begin the
448 * bootp packet at offset 0x2a in the property for some reason.
451 struct bootp_property_offset {
452 char *name; /* property name */
453 int offset; /* offset into property where bootp packet occurs */
455 static const struct bootp_property_offset bootp_response_properties[] = {
456 { .name = "bootp-response", .offset = 0 },
457 { .name = "dhcp-response", .offset = 0 },
458 { .name = "bootpreply-packet", .offset = 0x2a },
461 struct bootp_packet {
462 u8 op, htype, hlen, hops;
465 u32 ciaddr, yiaddr, siaddr, giaddr;
466 unsigned char chaddr[16];
467 unsigned char sname[64];
468 unsigned char file[128];
469 /* vendor options go here if we need them */
473 * Search for config file by MAC address, then by IP address.
474 * Basically copying pxelinux's algorithm.
475 * http://syslinux.zytor.com/pxe.php#config
477 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
479 void *bootp_response = NULL;
481 struct bootp_packet *packet;
482 int i = 0, size, offset = 0, rc = 0;
484 struct boot_fspec_t fspec = *orig_fspec;
485 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
487 chosen = prom_finddevice("/chosen");
489 prom_printf("chosen=%d\n", chosen);
492 prom_printf("ici\n");
494 for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
495 propname = bootp_response_properties[i].name;
496 size = prom_getproplen(chosen, propname);
500 DEBUG_F("using /chosen/%s\n", propname);
501 offset = bootp_response_properties[i].offset;
504 prom_printf("ici 2\n");
508 prom_printf("ici 3\n");
510 if (sizeof(*packet) > size - offset) {
511 prom_printf("Malformed %s property?\n", propname);
514 prom_printf("ici 4\n");
516 bootp_response = malloc(size);
519 prom_printf("ici 5\n");
521 if (prom_getprop(chosen, propname, bootp_response, size) < 0)
523 prom_printf("ici 6\n");
525 packet = bootp_response + offset;
528 * First, try to match on mac address with the hardware type
532 /* 3 chars per byte in chaddr + 2 chars for htype + \0 */
533 fspec.file = malloc(packet->hlen * 3 + 2 + 1);
537 sprintf(fspec.file, "%02x", packet->htype);
539 for (i = 0; i < packet->hlen; i++) {
541 sprintf(tmp, "-%02x", packet->chaddr[i]);
542 strcat(fspec.file, tmp);
544 prom_printf("ici 7\n");
546 rc = load_config_file(&fspec);
552 * Now try to match on IP.
555 fspec.file = malloc(9);
556 sprintf(fspec.file, "%08X", packet->yiaddr);
558 while (strlen(fspec.file)) {
559 rc = load_config_file(&fspec);
562 /* Chop one digit off the end, try again */
563 fspec.file[strlen(fspec.file) - 1] = '\0';
567 if (rc) /* modify original only on success */
568 orig_fspec->file = fspec.file;
571 free(bootp_response);
575 void maintabfunc (void)
579 prom_printf("boot: %s", cbuff);
584 word_split(char **linep, char **paramsp)
599 while (*p != 0 && *p != ' ')
608 make_params(char *label, char *params)
611 static char buffer[2048];
616 p = cfg_get_strg(label, "literal");
628 p = cfg_get_strg(label, "root");
635 if (cfg_get_flag(label, "read-only")) {
639 if (cfg_get_flag(label, "read-write")) {
643 p = cfg_get_strg(label, "ramdisk");
645 strcpy (q, "ramdisk=");
650 p = cfg_get_strg(label, "initrd-size");
652 strcpy (q, "ramdisk_size=");
657 if (cfg_get_flag(label, "novideo")) {
658 strcpy (q, "video=ofonly");
662 p = cfg_get_strg (label, "append");
669 pause_after = cfg_get_flag (label, "pause-after");
670 p = cfg_get_strg(label, "pause-message");
679 void check_password(char *str)
683 prom_printf("\n%s", str);
684 for (i = 0; i < 3; i++) {
685 prom_printf ("\nPassword: ");
687 cmdedit ((void (*)(void)) 0, 1);
689 #ifdef USE_MD5_PASSWORDS
690 if (!strncmp (password, "$1$", 3)) {
691 if (!check_md5_password(passwdbuff, password))
694 else if (!strcmp (password, passwdbuff))
697 if (!strcmp (password, passwdbuff))
699 #endif /* USE_MD5_PASSWORDS */
702 prom_printf ("Incorrect password. Try again.");
705 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
706 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
707 " ||----w |\n || ||\n");
709 prom_interpret("reset-all");
712 int get_params(struct boot_param_t* params)
718 char *imagename = 0, *label;
723 static int first = 1;
724 static char bootargs[1024];
725 static char imagepath[1024];
726 static char initrdpath[1024];
727 static char sysmappath[1024];
730 memset(params, 0, sizeof(*params));
732 params->kernel.part = -1;
733 params->rd.part = -1;
734 params->sysmap.part = -1;
741 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
742 imagename = bootargs;
743 word_split(&imagename, ¶ms->args);
744 timeout = DEFAULT_TIMEOUT;
746 prom_printf("Default supplied on the command line: %s ", imagename);
748 prom_printf("%s", params->args);
751 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
752 timeout = simple_strtol(q, NULL, 0);
755 prom_printf("boot: ");
760 end = beg + 100 * timeout;
762 c = prom_nbgetchar();
763 } while (c == -1 && prom_getms() <= end);
767 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
773 if (c != -1 && c != '\n' && c != '\r') {
776 } else if (c >= ' ') {
779 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
782 prom_printf("%s\n", cbuff);
787 if (c == '\n' || c == '\r') {
789 imagename = cfg_get_default();
791 prom_printf("%s", imagename);
793 prom_printf(" %s", params->args);
795 } else if (!singlekey) {
796 cmdedit(maintabfunc, 0);
798 strcpy(given_bootargs, cbuff);
799 given_bootargs_by_user = 1;
801 word_split(&imagename, ¶ms->args);
804 /* chrp gets this wrong, force it -- Cort */
805 if ( useconf && (!imagename || imagename[0] == 0 ))
806 imagename = cfg_get_default();
809 defdevice = boot.dev;
812 defdevice = cfg_get_strg(0, "device");
813 p = cfg_get_strg(0, "partition");
815 n = simple_strtol(p, &endp, 10);
816 if (endp != p && *endp == 0)
819 p = cfg_get_strg(0, "pause-message");
822 if (cfg_get_flag(0, "restricted"))
824 p = cfg_get_strg(imagename, "image");
828 defdevice = cfg_get_strg(label, "device");
829 if(!defdevice) defdevice=boot.dev;
830 p = cfg_get_strg(label, "partition");
832 n = simple_strtol(p, &endp, 10);
833 if (endp != p && *endp == 0)
836 if (cfg_get_flag(label, "restricted"))
839 if (params->args && password && restricted)
840 check_password ("To specify arguments for this image "
841 "you must enter the password.");
842 else if (password && !restricted)
843 check_password ("This image is restricted.");
845 params->args = make_params(label, params->args);
849 if (!strcmp (imagename, "help")) {
850 /* FIXME: defdevice shouldn't need to be reset all over the place */
851 if(!defdevice) defdevice = boot.dev;
853 "\nPress the tab key for a list of defined images.\n"
854 "The label marked with a \"*\" is is the default image, "
855 "press <return> to boot it.\n\n"
856 "To boot any other label simply type its name and press <return>.\n\n"
857 "To boot a kernel image which is not defined in the yaboot configuration \n"
858 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
859 "\"device:\" is the OpenFirmware device path to the disk the image \n"
860 "resides on, and \"partno\" is the partition number the image resides on.\n"
861 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
862 "device, if you only specify a filename you should not start it with a \",\"\n\n"
863 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
864 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
866 "partition=%d\n\n", defdevice, defpart);
870 if (!strcmp (imagename, "halt")) {
872 check_password ("Restricted command.");
876 if (!strcmp (imagename, "bye")) {
878 check_password ("Restricted command.");
884 if (imagename[0] == '$') {
885 /* forth command string */
887 check_password ("OpenFirmware commands are restricted.");
888 prom_interpret(imagename+1);
892 strncpy(imagepath, imagename, 1024);
894 if (!label && password)
895 check_password ("To boot a custom image you must enter the password.");
897 if (!parse_device_path(imagepath, defdevice, defpart,
898 "/vmlinux", ¶ms->kernel)) {
899 prom_printf("%s: Unable to parse\n", imagepath);
902 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
903 params->kernel.part, params->kernel.file);
906 p = cfg_get_strg(label, "initrd");
908 DEBUG_F("Parsing initrd path <%s>\n", p);
909 strncpy(initrdpath, p, 1024);
910 if (!parse_device_path(initrdpath, defdevice, defpart,
911 "/root.bin", ¶ms->rd)) {
912 prom_printf("%s: Unable to parse\n", imagepath);
916 p = cfg_get_strg(label, "sysmap");
918 DEBUG_F("Parsing sysmap path <%s>\n", p);
919 strncpy(sysmappath, p, 1024);
920 if (!parse_device_path(sysmappath, defdevice, defpart,
921 "/boot/System.map", ¶ms->sysmap)) {
922 prom_printf("%s: Unable to parse\n", imagepath);
930 /* This is derived from quik core. To be changed to first parse the headers
931 * doing lazy-loading, and then claim the memory before loading the kernel
933 * We also need to add initrd support to this whole mecanism
938 #define MAX_HEADERS 32
940 struct boot_file_t file;
942 static struct boot_param_t params;
944 unsigned long initrd_size;
946 unsigned long sysmap_size;
947 kernel_entry_t kernel_entry;
948 struct bi_record* birec;
951 void *initrd_more,*initrd_want;
952 unsigned long initrd_read;
954 loadinfo.load_loc = 0;
962 if (get_params(¶ms))
964 if (!params.kernel.file)
967 prom_printf("Please wait, loading kernel...\n");
969 memset(&file, 0, sizeof(file));
971 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
972 && params.kernel.file[0] != '\\') {
973 loc=(char*)malloc(strlen(params.kernel.file)+3);
975 prom_printf ("malloc error\n");
978 strcpy(loc,boot.file);
979 strcat(loc,params.kernel.file);
980 free(params.kernel.file);
981 params.kernel.file=loc;
983 result = open_file(¶ms.kernel, &file);
984 if (result != FILE_ERR_OK) {
985 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
986 prom_perror(result, params.kernel.file);
990 /* Read the Elf e_ident, e_type and e_machine fields to
991 * determine Elf file type
993 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
994 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
995 file.fs->close(&file);
996 memset(&file, 0, sizeof(file));
1000 if (is_elf32(&loadinfo)) {
1001 if (!load_elf32(&file, &loadinfo)) {
1002 file.fs->close(&file);
1003 memset(&file, 0, sizeof(file));
1006 prom_printf(" Elf32 kernel loaded...\n");
1007 } else if (is_elf64(&loadinfo)) {
1008 if (!load_elf64(&file, &loadinfo)) {
1009 file.fs->close(&file);
1010 memset(&file, 0, sizeof(file));
1013 prom_printf(" Elf64 kernel loaded...\n");
1015 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
1016 file.fs->close(&file);
1017 memset(&file, 0, sizeof(file));
1020 file.fs->close(&file);
1021 memset(&file, 0, sizeof(file));
1023 /* If sysmap, load it (only if booting a vmlinux).
1025 if (flat_vmlinux && params.sysmap.file) {
1026 prom_printf("Loading System.map ...\n");
1027 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1028 && params.sysmap.file[0] != '\\') {
1030 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1032 prom_printf ("malloc error\n");
1035 strcpy(loc,boot.file);
1036 strcat(loc,params.sysmap.file);
1037 free(params.sysmap.file);
1038 params.sysmap.file=loc;
1041 result = open_file(¶ms.sysmap, &file);
1042 if (result != FILE_ERR_OK) {
1043 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1044 prom_perror(result, params.sysmap.file);
1047 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1048 if (sysmap_base == (void *)-1) {
1049 prom_printf("Claim failed for sysmap memory\n");
1053 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1054 if (sysmap_size == 0)
1057 ((char *)sysmap_base)[sysmap_size++] = 0;
1059 file.fs->close(&file);
1060 memset(&file, 0, sizeof(file));
1063 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1064 sysmap_base, sysmap_size >> 10);
1065 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1067 prom_printf("System.map load failed !\n");
1072 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1073 * can't tell the size it will be so we claim an arbitrary amount
1076 if (flat_vmlinux && params.rd.file) {
1077 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1078 && params.kernel.file[0] != '\\')
1081 loc=(char*)malloc(strlen(params.rd.file)+3);
1083 prom_printf ("Malloc error\n");
1086 strcpy(loc,boot.file);
1087 strcat(loc,params.rd.file);
1088 free(params.rd.file);
1091 prom_printf("Loading ramdisk...\n");
1092 result = open_file(¶ms.rd, &file);
1093 if (result != FILE_ERR_OK) {
1094 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1095 prom_perror(result, params.rd.file);
1098 #define INITRD_CHUNKSIZE 0x100000
1099 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1100 if (initrd_base == (void *)-1) {
1101 prom_printf("Claim failed for initrd memory\n");
1104 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1105 if (initrd_size == 0)
1107 initrd_read = initrd_size;
1108 initrd_more = initrd_base;
1109 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1110 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1111 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1112 if (initrd_more != initrd_want) {
1113 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1117 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1118 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1119 initrd_size += initrd_read;
1122 file.fs->close(&file);
1123 memset(&file, 0, sizeof(file));
1126 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1127 initrd_base, initrd_size >> 10);
1129 prom_printf("ramdisk load failed !\n");
1134 DEBUG_F("setting kernel args to: %s\n", params.args);
1135 prom_setargs(params.args);
1136 DEBUG_F("flushing icache...");
1137 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1142 * Fill new boot infos (only if booting a vmlinux).
1144 * The birec is low on memory, probably inside the malloc pool,
1145 * so we don't write it earlier. At this point, we should not
1146 * use anything coming from the malloc pool.
1148 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1150 /* We make sure it's mapped. We map only 64k for now, it's
1151 * plenty enough we don't claim since this precise memory
1152 * range may already be claimed by the malloc pool.
1154 prom_map (birec, birec, 0x10000);
1155 DEBUG_F("birec at %p\n", birec);
1158 birec->tag = BI_FIRST;
1159 birec->size = sizeof(struct bi_record);
1160 birec = (struct bi_record *)((ulong)birec + birec->size);
1162 birec->tag = BI_BOOTLOADER_ID;
1163 sprintf( (char *)birec->data, "yaboot");
1164 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1165 birec = (struct bi_record *)((ulong)birec + birec->size);
1167 birec->tag = BI_MACHTYPE;
1168 birec->data[0] = _machine;
1169 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1170 birec = (struct bi_record *)((ulong)birec + birec->size);
1173 birec->tag = BI_SYSMAP;
1174 birec->data[0] = (ulong)sysmap_base;
1175 birec->data[1] = sysmap_size;
1176 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1177 birec = (struct bi_record *)((ulong)birec + birec->size);
1179 birec->tag = BI_LAST;
1180 birec->size = sizeof(struct bi_record);
1181 birec = (struct bi_record *)((ulong)birec + birec->size);
1184 /* compute the kernel's entry point. */
1185 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1187 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1188 DEBUG_F("kernel: arg1 = %p,\n"
1189 " arg2 = 0x%08lx,\n"
1193 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1195 DEBUG_F("Entering kernel...\n");
1197 /* call the kernel with our stack. */
1198 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1206 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1209 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1211 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1212 unsigned long addr, loadaddr;
1214 /* Read the rest of the Elf header... */
1215 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1216 prom_printf("\nCan't read Elf32 image header\n");
1220 DEBUG_F("Elf32 header:\n");
1221 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1222 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1223 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1224 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1225 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1226 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1227 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1228 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1229 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1230 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1232 loadinfo->entry = e->e_entry;
1234 if (e->e_phnum > MAX_HEADERS) {
1235 prom_printf ("Can only load kernels with one program header\n");
1239 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1241 prom_printf ("Malloc error\n");
1245 /* Now, we read the section header */
1246 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1247 prom_printf ("seek error\n");
1250 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1251 sizeof(Elf32_Phdr) * e->e_phnum) {
1252 prom_printf ("read error\n");
1256 /* Scan through the program header
1257 * HACK: We must return the _memory size of the kernel image, not the
1258 * file size (because we have to leave room before other boot
1259 * infos. This code works as a side effect of the fact that
1260 * we have one section and vaddr == p_paddr
1262 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1264 for (i = 0; i < e->e_phnum; ++i, ++p) {
1265 if (p->p_type != PT_LOAD || p->p_offset == 0)
1267 if (loadinfo->memsize == 0) {
1268 loadinfo->offset = p->p_offset;
1269 loadinfo->memsize = p->p_memsz;
1270 loadinfo->filesize = p->p_filesz;
1271 loadinfo->load_loc = p->p_vaddr;
1273 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1274 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1278 if (loadinfo->memsize == 0) {
1279 prom_printf("Can't find a loadable segment !\n");
1283 /* leave some room (1Mb) for boot infos */
1284 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1285 /* Claim OF memory */
1286 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1288 /* Determine whether we are trying to boot a vmlinux or some
1289 * other binary image (eg, zImage). We load vmlinux's at
1290 * KERNELADDR and all other binaries at their e_entry value.
1292 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1294 loadaddr = KERNELADDR;
1297 loadaddr = loadinfo->load_loc;
1300 /* On some systems, loadaddr may already be claimed, so try some
1301 * other nearby addresses before giving up.
1303 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1304 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1305 if (loadinfo->base != (void *)-1) break;
1307 if (loadinfo->base == (void *)-1) {
1308 prom_printf("Claim error, can't allocate kernel memory\n");
1312 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1313 loadinfo->base, loadinfo->memsize);
1314 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1315 loadaddr, loadinfo->memsize);
1317 /* Load the program segments... */
1319 for (i = 0; i < e->e_phnum; ++i, ++p) {
1320 unsigned long offset;
1321 if (p->p_type != PT_LOAD || p->p_offset == 0)
1324 /* Now, we skip to the image itself */
1325 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1326 prom_printf ("Seek error\n");
1327 prom_release(loadinfo->base, loadinfo->memsize);
1330 offset = p->p_vaddr - loadinfo->load_loc;
1331 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1332 prom_printf ("Read failed\n");
1333 prom_release(loadinfo->base, loadinfo->memsize);
1340 /* Return success at loading the Elf32 kernel */
1350 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1353 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1355 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1356 unsigned long addr, loadaddr;
1358 /* Read the rest of the Elf header... */
1359 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1360 prom_printf("\nCan't read Elf64 image header\n");
1364 DEBUG_F("Elf64 header:\n");
1365 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1366 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1367 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1368 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1369 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1370 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1371 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1372 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1373 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1374 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1376 loadinfo->entry = e->e_entry;
1378 if (e->e_phnum > MAX_HEADERS) {
1379 prom_printf ("Can only load kernels with one program header\n");
1383 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1385 prom_printf ("Malloc error\n");
1389 /* Now, we read the section header */
1390 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1391 prom_printf ("Seek error\n");
1394 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1395 sizeof(Elf64_Phdr) * e->e_phnum) {
1396 prom_printf ("Read error\n");
1400 /* Scan through the program header
1401 * HACK: We must return the _memory size of the kernel image, not the
1402 * file size (because we have to leave room before other boot
1403 * infos. This code works as a side effect of the fact that
1404 * we have one section and vaddr == p_paddr
1406 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1408 for (i = 0; i < e->e_phnum; ++i, ++p) {
1409 if (p->p_type != PT_LOAD || p->p_offset == 0)
1411 if (loadinfo->memsize == 0) {
1412 loadinfo->offset = p->p_offset;
1413 loadinfo->memsize = p->p_memsz;
1414 loadinfo->filesize = p->p_filesz;
1415 loadinfo->load_loc = p->p_vaddr;
1417 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1418 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1422 if (loadinfo->memsize == 0) {
1423 prom_printf("Can't find a loadable segment !\n");
1427 /* leave some room (1Mb) for boot infos */
1428 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1429 /* Claim OF memory */
1430 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1432 /* Determine whether we are trying to boot a vmlinux or some
1433 * other binary image (eg, zImage). We load vmlinux's at
1434 * KERNELADDR and all other binaries at their e_entry value.
1436 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1438 loadaddr = KERNELADDR;
1441 loadaddr = e->e_entry;
1444 /* On some systems, loadaddr may already be claimed, so try some
1445 * other nearby addresses before giving up.
1447 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1448 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1449 if (loadinfo->base != (void *)-1) break;
1451 if (loadinfo->base == (void *)-1) {
1452 prom_printf("Claim error, can't allocate kernel memory\n");
1456 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1457 loadinfo->base, loadinfo->memsize);
1458 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1459 loadaddr, loadinfo->memsize);
1461 /* Load the program segments... */
1463 for (i = 0; i < e->e_phnum; ++i, ++p) {
1464 unsigned long offset;
1465 if (p->p_type != PT_LOAD || p->p_offset == 0)
1468 /* Now, we skip to the image itself */
1469 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1470 prom_printf ("Seek error\n");
1471 prom_release(loadinfo->base, loadinfo->memsize);
1474 offset = p->p_vaddr - loadinfo->load_loc;
1475 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1476 prom_printf ("Read failed\n");
1477 prom_release(loadinfo->base, loadinfo->memsize);
1484 /* Return success at loading the Elf64 kernel */
1494 is_elf32(loadinfo_t *loadinfo)
1496 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1498 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1499 e->e_ident[EI_MAG1] == ELFMAG1 &&
1500 e->e_ident[EI_MAG2] == ELFMAG2 &&
1501 e->e_ident[EI_MAG3] == ELFMAG3 &&
1502 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1503 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1504 e->e_type == ET_EXEC &&
1505 e->e_machine == EM_PPC);
1509 is_elf64(loadinfo_t *loadinfo)
1511 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1513 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1514 e->e_ident[EI_MAG1] == ELFMAG1 &&
1515 e->e_ident[EI_MAG2] == ELFMAG2 &&
1516 e->e_ident[EI_MAG3] == ELFMAG3 &&
1517 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1518 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1519 e->e_type == ET_EXEC &&
1520 e->e_machine == EM_PPC64);
1526 #ifdef CONFIG_SET_COLORMAP
1527 static unsigned char default_colors[] = {
1546 prom_handle scrn = PROM_INVALID_HANDLE;
1548 /* Try Apple's mac-boot screen ihandle */
1549 result = (int)call_prom_return("interpret", 1, 2,
1550 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1551 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1553 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1555 /* Hrm... check to see if stdout is a display */
1556 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1557 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1558 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1559 DEBUG_F("got it ! stdout is a screen\n");
1562 /* Else, we try to open the package */
1563 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1564 DEBUG_F("Open screen result: %p\n", scrn);
1568 if (scrn == PROM_INVALID_HANDLE) {
1569 prom_printf("No screen device found !/n");
1573 prom_set_color(scrn, i, default_colors[i*3],
1574 default_colors[i*3+1], default_colors[i*3+2]);
1576 prom_printf("\x1b[1;37m\x1b[2;40m");
1578 for (i=0;i<16; i++) {
1579 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1580 ansi_color_table[i].index,
1581 ansi_color_table[i].value,
1582 ansi_color_table[i].name,
1583 ansi_color_table[i].name);
1584 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1585 ansi_color_table[i].index,
1586 ansi_color_table[i].value+10,
1587 ansi_color_table[i].name,
1588 ansi_color_table[i].name);
1590 prom_printf("\x1b[1;37m\x1b[2;40m");
1591 #endif /* COLOR_TEST */
1597 #endif /* CONFIG_SET_COLORMAP */
1605 if (_machine == _MACH_Pmac)
1608 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1609 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1610 if (bootdevice[0] == 0) {
1611 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1612 DEBUG_F("boot-device = %s\n", bootdevice);
1614 if (bootdevice[0] == 0) {
1615 prom_printf("Couldn't determine boot device\n");
1619 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1620 prom_printf("%s: Unable to parse\n", bootdevice);
1623 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1624 boot.dev, boot.part, boot.file);
1626 if (strlen(boot.file)) {
1627 if (!strncmp(boot.file, "\\\\", 2))
1631 p = last = boot.file;
1641 if (strlen(boot.file))
1642 strcat(boot.file, "\\");
1645 DEBUG_F("After pmac path kludgeup: dev=%s, part=%d, file=%s\n",
1646 boot.dev, boot.part, boot.file);
1649 * If we're doing a netboot, first look for one which matches our
1652 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1653 prom_printf("Try to netboot\n");
1654 useconf = load_my_config_file(&boot);
1658 useconf = load_config_file(&boot);
1660 prom_printf("Welcome to yaboot version " VERSION "\n");
1661 prom_printf("Enter \"help\" to get some basic usage information\n");
1663 /* I am fed up with lusers using the wrong partition type and
1664 mailing me *when* it breaks */
1666 if (_machine == _MACH_Pmac) {
1667 char *entry = cfg_get_strg(0, "ptypewarning");
1670 warn = strcmp(entry,
1671 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1673 ptype = get_part_type(boot.dev, boot.part);
1674 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1675 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1676 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1684 prom_printf("Bye.\n");
1690 * c-file-style: "k&r"