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];
116 char *password = NULL;
117 struct boot_fspec_t boot;
118 int _machine = _MACH_Pmac;
121 #ifdef CONFIG_COLOR_TEXT
123 /* Color values for text ui */
124 static struct ansi_color_t {
128 } ansi_color_table[] = {
136 { "light-gray", 0, 37 },
137 { "dark-gray", 1, 30 },
138 { "light-blue", 1, 31 },
139 { "light-green", 1, 32 },
140 { "light-cyan", 1, 33 },
141 { "light-red", 1, 34 },
142 { "light-purple", 1, 35 },
148 /* Default colors for text ui */
151 #endif /* CONFIG_COLOR_TEXT */
155 static int test_data = 0;
157 static int pause_after;
158 static char *pause_message = "Type go<return> to continue.\n";
159 static char given_bootargs[1024];
160 static int given_bootargs_by_user = 0;
162 extern unsigned char linux_logo_red[];
163 extern unsigned char linux_logo_green[];
164 extern unsigned char linux_logo_blue[];
166 #define DEFAULT_TIMEOUT -1
168 /* Entry, currently called directly by crt0 (bss not inited) */
170 extern char* __bss_start;
173 static struct first_info *quik_fip = NULL;
176 yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5)
179 void* malloc_base = NULL;
182 /* OF seems to do it, but I'm not very confident */
183 memset(&__bss_start, 0, &_end - &__bss_start);
185 /* Check for quik first stage bootloader (but I don't think we are
186 * compatible with it anyway, I'll look into backporting to older OF
189 if (r5 == 0xdeadbeef) {
191 quik_fip = (struct first_info *)r4;
194 /* Initialize OF interface */
195 prom_init ((prom_entry) r5);
197 /* Allocate some memory for malloc'ator */
198 malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0);
199 if (malloc_base == (void *)-1) {
200 prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n",
201 MALLOCSIZE, MALLOCADDR);
204 malloc_init(malloc_base, MALLOCSIZE);
205 DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n",
206 malloc_base, MALLOCSIZE);
208 /* A few useless DEBUG_F's */
209 DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset());
210 DEBUG_F("test_bss : %d (should be 0)\n", test_bss);
211 DEBUG_F("test_data : %d (should be 0)\n", test_data);
212 DEBUG_F("&test_data : %p\n", &test_data);
213 DEBUG_F("&test_bss : %p\n", &test_bss);
214 DEBUG_F("linked at : 0x%08x\n", TEXTADDR);
216 /* ask the OF info if we're a chrp or pmac */
217 /* we need to set _machine before calling finish_device_tree */
218 root = prom_finddevice("/");
220 static char model[256];
221 if (prom_getprop(root, "device_type", model, 256 ) > 0 &&
222 !strncmp("chrp", model, 4))
223 _machine = _MACH_chrp;
225 if (prom_getprop(root, "model", model, 256 ) > 0 &&
226 !strncmp(model, "IBM", 3))
227 _machine = _MACH_chrp;
231 DEBUG_F("Running on _machine = %d\n", _machine);
235 result = yaboot_main();
237 /* Get rid of malloc pool */
239 prom_release(malloc_base, MALLOCSIZE);
240 DEBUG_F("Malloc buffer released. Exiting with code %d\n",
250 #ifdef CONFIG_COLOR_TEXT
252 * Validify color for text ui
255 check_color_text_ui(char *color)
258 while(ansi_color_table[i].name) {
259 if (!strcmp(color, ansi_color_table[i].name))
265 #endif /* CONFIG_COLOR_TEXT */
268 void print_message_file(char *filename)
272 char *defdev = boot.dev;
273 int defpart = boot.part;
278 struct boot_file_t file;
279 struct boot_fspec_t msgfile;
281 defdev = cfg_get_strg(0, "device");
284 p = cfg_get_strg(0, "partition");
286 n = simple_strtol(p, &endp, 10);
287 if (endp != p && *endp == 0)
291 strncpy(msgpath, filename, sizeof(msgpath));
292 if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
293 prom_printf("%s: Unable to parse\n", msgpath);
297 result = open_file(&msgfile, &file);
298 if (result != FILE_ERR_OK) {
299 prom_printf("%s:%d,", msgfile.dev, msgfile.part);
300 prom_perror(result, msgfile.file);
309 memset(msg, 0, 2001);
311 if (file.fs->read(&file, 2000, msg) <= 0)
314 prom_printf("%s", msg);
318 file.fs->close(&file);
323 /* Currently, the config file must be at the root of the filesystem.
324 * todo: recognize the full path to myself and use it to load the
325 * config file. Handle the "\\" (blessed system folder)
328 load_config_file(struct boot_fspec_t *fspec)
330 char *conf_file = NULL, *p;
331 struct boot_file_t file;
332 int sz, opened = 0, result = 0;
334 /* Allocate a buffer for the config file */
335 conf_file = malloc(CONFIG_FILE_MAX);
337 prom_printf("Can't alloc config file buffer\n");
342 result = open_file(fspec, &file);
343 if (result != FILE_ERR_OK) {
344 prom_printf("%s:%d,", fspec->dev, fspec->part);
345 prom_perror(result, fspec->file);
346 prom_printf("Can't open config file\n");
352 sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file);
354 prom_printf("Error, can't read config file\n");
357 prom_printf("Config file read, %d bytes\n", sz);
361 file.fs->close(&file);
364 /* Call the parsing code in cfg.c */
365 if (cfg_parse(fspec->file, conf_file, sz) < 0) {
366 prom_printf ("Syntax error or read error config\n");
370 DEBUG_F("Config file successfully parsed, %d bytes\n", sz);
372 /* Now, we do the initialisations stored in the config file */
373 p = cfg_get_strg(0, "init-code");
377 password = cfg_get_strg(0, "password");
379 #ifdef CONFIG_COLOR_TEXT
380 p = cfg_get_strg(0, "fgcolor");
382 DEBUG_F("fgcolor=%s\n", p);
383 fgcolor = check_color_text_ui(p);
385 prom_printf("Invalid fgcolor: \"%s\".\n", p);
388 p = cfg_get_strg(0, "bgcolor");
390 DEBUG_F("bgcolor=%s\n", p);
391 bgcolor = check_color_text_ui(p);
393 prom_printf("Invalid bgcolor: \"%s\".\n", p);
397 sprintf(temp, "%x to background-color", bgcolor);
398 prom_interpret(temp);
405 sprintf(temp, "%x to foreground-color", fgcolor);
406 prom_interpret(temp);
408 #endif /* CONFIG_COLOR_TEXT */
410 p = cfg_get_strg(0, "init-message");
412 prom_printf("%s\n", p);
414 p = cfg_get_strg(0, "message");
416 print_message_file(p);
423 file.fs->close(&file);
432 * "bootp-response" is the property name which is specified in
433 * the recommended practice doc for obp-tftp. However, pmac
434 * provides a "dhcp-response" property and chrp provides a
435 * "bootpreply-packet" property. The latter appears to begin the
436 * bootp packet at offset 0x2a in the property for some reason.
439 struct bootp_property_offset {
440 char *name; /* property name */
441 int offset; /* offset into property where bootp packet occurs */
443 static const struct bootp_property_offset bootp_response_properties[] = {
444 { .name = "bootp-response", .offset = 0 },
445 { .name = "dhcp-response", .offset = 0 },
446 { .name = "bootpreply-packet", .offset = 0x2a },
449 struct bootp_packet {
450 u8 op, htype, hlen, hops;
453 u32 ciaddr, yiaddr, siaddr, giaddr;
454 unsigned char chaddr[16];
455 unsigned char sname[64];
456 unsigned char file[128];
457 /* vendor options go here if we need them */
461 * Search for config file by MAC address, then by IP address.
462 * Basically copying pxelinux's algorithm.
463 * http://syslinux.zytor.com/pxe.php#config
465 static int load_my_config_file(struct boot_fspec_t *orig_fspec)
467 void *bootp_response = NULL;
469 struct bootp_packet *packet;
470 int i = 0, size, offset = 0, rc = 0;
472 struct boot_fspec_t fspec = *orig_fspec;
473 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
475 chosen = prom_finddevice("/chosen");
477 prom_printf("chosen=%d\n", chosen);
481 for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
482 propname = bootp_response_properties[i].name;
483 size = prom_getproplen(chosen, propname);
487 DEBUG_F("using /chosen/%s\n", propname);
488 offset = bootp_response_properties[i].offset;
495 if (sizeof(*packet) > size - offset) {
496 prom_printf("Malformed %s property?\n", propname);
500 bootp_response = malloc(size);
504 if (prom_getprop(chosen, propname, bootp_response, size) < 0)
507 packet = bootp_response + offset;
510 * First, try to match on mac address with the hardware type
514 /* 3 chars per byte in chaddr + 2 chars for htype + \0 */
515 fspec.file = malloc(packet->hlen * 3 + 2 + 1);
519 sprintf(fspec.file, "%02x", packet->htype);
521 for (i = 0; i < packet->hlen; i++) {
523 sprintf(tmp, "-%02x", packet->chaddr[i]);
524 strcat(fspec.file, tmp);
527 rc = load_config_file(&fspec);
533 * Now try to match on IP.
536 fspec.file = malloc(9);
537 sprintf(fspec.file, "%08X", packet->yiaddr);
539 while (strlen(fspec.file)) {
540 rc = load_config_file(&fspec);
543 /* Chop one digit off the end, try again */
544 fspec.file[strlen(fspec.file) - 1] = '\0';
548 if (rc) /* modify original only on success */
549 orig_fspec->file = fspec.file;
552 free(bootp_response);
556 void maintabfunc (void)
560 prom_printf("boot: %s", cbuff);
565 word_split(char **linep, char **paramsp)
580 while (*p != 0 && *p != ' ')
589 make_params(char *label, char *params)
592 static char buffer[2048];
597 p = cfg_get_strg(label, "literal");
609 p = cfg_get_strg(label, "root");
616 if (cfg_get_flag(label, "read-only")) {
620 if (cfg_get_flag(label, "read-write")) {
624 p = cfg_get_strg(label, "ramdisk");
626 strcpy (q, "ramdisk=");
631 p = cfg_get_strg(label, "initrd-size");
633 strcpy (q, "ramdisk_size=");
638 if (cfg_get_flag(label, "novideo")) {
639 strcpy (q, "video=ofonly");
643 p = cfg_get_strg (label, "append");
650 pause_after = cfg_get_flag (label, "pause-after");
651 p = cfg_get_strg(label, "pause-message");
660 void check_password(char *str)
664 prom_printf("\n%s", str);
665 for (i = 0; i < 3; i++) {
666 prom_printf ("\nPassword: ");
668 cmdedit ((void (*)(void)) 0, 1);
670 #ifdef USE_MD5_PASSWORDS
671 if (!strncmp (password, "$1$", 3)) {
672 if (!check_md5_password(passwdbuff, password))
675 else if (!strcmp (password, passwdbuff))
678 if (!strcmp (password, passwdbuff))
680 #endif /* USE_MD5_PASSWORDS */
683 prom_printf ("Incorrect password. Try again.");
686 prom_printf(" ___________________\n< Permission denied >\n -------------------\n"
687 " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n"
688 " ||----w |\n || ||\n");
690 prom_interpret("reset-all");
693 int get_params(struct boot_param_t* params)
699 char *imagename = 0, *label;
704 static int first = 1;
705 static char imagepath[1024];
706 static char initrdpath[1024];
707 static char sysmappath[1024];
710 memset(params, 0, sizeof(*params));
712 params->kernel.part = -1;
713 params->rd.part = -1;
714 params->sysmap.part = -1;
721 imagename = bootargs;
722 word_split(&imagename, ¶ms->args);
723 timeout = DEFAULT_TIMEOUT;
725 prom_printf("Default supplied on the command line: %s ", imagename);
727 prom_printf("%s", params->args);
730 if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0)
731 timeout = simple_strtol(q, NULL, 0);
734 prom_printf("boot: ");
739 end = beg + 100 * timeout;
741 c = prom_nbgetchar();
742 } while (c == -1 && prom_getms() <= end);
746 else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) {
752 if (c != -1 && c != '\n' && c != '\r') {
755 } else if (c >= ' ') {
758 if ((cfg_get_flag (cbuff, "single-key")) && useconf) {
761 prom_printf("%s\n", cbuff);
766 if (c == '\n' || c == '\r') {
768 imagename = cfg_get_default();
770 prom_printf("%s", imagename);
772 prom_printf(" %s", params->args);
774 } else if (!singlekey) {
775 cmdedit(maintabfunc, 0);
777 strcpy(given_bootargs, cbuff);
778 given_bootargs_by_user = 1;
780 word_split(&imagename, ¶ms->args);
783 /* chrp gets this wrong, force it -- Cort */
784 if ( useconf && (!imagename || imagename[0] == 0 ))
785 imagename = cfg_get_default();
788 defdevice = boot.dev;
791 defdevice = cfg_get_strg(0, "device");
792 p = cfg_get_strg(0, "partition");
794 n = simple_strtol(p, &endp, 10);
795 if (endp != p && *endp == 0)
798 p = cfg_get_strg(0, "pause-message");
801 if (cfg_get_flag(0, "restricted"))
803 p = cfg_get_strg(imagename, "image");
807 defdevice = cfg_get_strg(label, "device");
808 if(!defdevice) defdevice=boot.dev;
809 p = cfg_get_strg(label, "partition");
811 n = simple_strtol(p, &endp, 10);
812 if (endp != p && *endp == 0)
815 if (cfg_get_flag(label, "restricted"))
818 if (params->args && password && restricted)
819 check_password ("To specify arguments for this image "
820 "you must enter the password.");
821 else if (password && !restricted)
822 check_password ("This image is restricted.");
824 params->args = make_params(label, params->args);
828 if (!strcmp (imagename, "help")) {
829 /* FIXME: defdevice shouldn't need to be reset all over the place */
830 if(!defdevice) defdevice = boot.dev;
832 "\nPress the tab key for a list of defined images.\n"
833 "The label marked with a \"*\" is is the default image, "
834 "press <return> to boot it.\n\n"
835 "To boot any other label simply type its name and press <return>.\n\n"
836 "To boot a kernel image which is not defined in the yaboot configuration \n"
837 "file, enter the kernel image name as [[device:][partno],]/path, where \n"
838 "\"device:\" is the OpenFirmware device path to the disk the image \n"
839 "resides on, and \"partno\" is the partition number the image resides on.\n"
840 "Note that the comma (,) is only required if you specify an OpenFirmware\n"
841 "device, if you only specify a filename you should not start it with a \",\"\n\n"
842 "If you omit \"device:\" and \"partno\" yaboot will use the values of \n"
843 "\"device=\" and \"partition=\" in yaboot.conf, right now those are set to: \n"
846 "To use an alternative config file rather than /etc/yaboot.conf, type on\n"
847 " Open FirmWare Prompt: \"boot conf=device:partition,/path/to/configfile\"\n"
848 "where \"device\" and \"partition\" are defined like above.\n\n", defdevice, defpart);
853 if (!strcmp (imagename, "halt")) {
855 check_password ("Restricted command.");
859 if (!strcmp (imagename, "bye")) {
861 check_password ("Restricted command.");
867 if (imagename[0] == '$') {
868 /* forth command string */
870 check_password ("OpenFirmware commands are restricted.");
871 prom_interpret(imagename+1);
875 strncpy(imagepath, imagename, 1024);
877 if (!label && password)
878 check_password ("To boot a custom image you must enter the password.");
880 if (!parse_device_path(imagepath, defdevice, defpart,
881 "/vmlinux", ¶ms->kernel)) {
882 prom_printf("%s: Unable to parse\n", imagepath);
885 DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev,
886 params->kernel.part, params->kernel.file);
889 p = cfg_get_strg(label, "initrd");
891 DEBUG_F("Parsing initrd path <%s>\n", p);
892 strncpy(initrdpath, p, 1024);
893 if (!parse_device_path(initrdpath, defdevice, defpart,
894 "/root.bin", ¶ms->rd)) {
895 prom_printf("%s: Unable to parse\n", imagepath);
899 p = cfg_get_strg(label, "sysmap");
901 DEBUG_F("Parsing sysmap path <%s>\n", p);
902 strncpy(sysmappath, p, 1024);
903 if (!parse_device_path(sysmappath, defdevice, defpart,
904 "/boot/System.map", ¶ms->sysmap)) {
905 prom_printf("%s: Unable to parse\n", imagepath);
913 /* This is derived from quik core. To be changed to first parse the headers
914 * doing lazy-loading, and then claim the memory before loading the kernel
916 * We also need to add initrd support to this whole mecanism
921 #define MAX_HEADERS 32
923 struct boot_file_t file;
925 static struct boot_param_t params;
927 unsigned long initrd_size;
929 unsigned long sysmap_size;
930 kernel_entry_t kernel_entry;
931 struct bi_record* birec;
934 void *initrd_more,*initrd_want;
935 unsigned long initrd_read;
937 loadinfo.load_loc = 0;
945 if (get_params(¶ms))
947 if (!params.kernel.file)
950 prom_printf("Please wait, loading kernel...\n");
952 memset(&file, 0, sizeof(file));
954 if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/'
955 && params.kernel.file[0] != '\\') {
956 loc=(char*)malloc(strlen(params.kernel.file)+3);
958 prom_printf ("malloc error\n");
961 strcpy(loc,boot.file);
962 strcat(loc,params.kernel.file);
963 free(params.kernel.file);
964 params.kernel.file=loc;
966 result = open_file(¶ms.kernel, &file);
967 if (result != FILE_ERR_OK) {
968 prom_printf("%s:%d,", params.kernel.dev, params.kernel.part);
969 prom_perror(result, params.kernel.file);
973 /* Read the Elf e_ident, e_type and e_machine fields to
974 * determine Elf file type
976 if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) {
977 prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n");
978 file.fs->close(&file);
979 memset(&file, 0, sizeof(file));
983 if (is_elf32(&loadinfo)) {
984 if (!load_elf32(&file, &loadinfo)) {
985 file.fs->close(&file);
986 memset(&file, 0, sizeof(file));
989 prom_printf(" Elf32 kernel loaded...\n");
990 } else if (is_elf64(&loadinfo)) {
991 if (!load_elf64(&file, &loadinfo)) {
992 file.fs->close(&file);
993 memset(&file, 0, sizeof(file));
996 prom_printf(" Elf64 kernel loaded...\n");
998 prom_printf ("%s: Not a valid ELF image\n", params.kernel.file);
999 file.fs->close(&file);
1000 memset(&file, 0, sizeof(file));
1003 file.fs->close(&file);
1004 memset(&file, 0, sizeof(file));
1006 /* If sysmap, load it (only if booting a vmlinux).
1008 if (flat_vmlinux && params.sysmap.file) {
1009 prom_printf("Loading System.map ...\n");
1010 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/'
1011 && params.sysmap.file[0] != '\\') {
1013 loc=(char*)malloc(strlen(params.sysmap.file)+3);
1015 prom_printf ("malloc error\n");
1018 strcpy(loc,boot.file);
1019 strcat(loc,params.sysmap.file);
1020 free(params.sysmap.file);
1021 params.sysmap.file=loc;
1024 result = open_file(¶ms.sysmap, &file);
1025 if (result != FILE_ERR_OK) {
1026 prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part);
1027 prom_perror(result, params.sysmap.file);
1030 sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0);
1031 if (sysmap_base == (void *)-1) {
1032 prom_printf("Claim failed for sysmap memory\n");
1036 sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base);
1037 if (sysmap_size == 0)
1040 ((char *)sysmap_base)[sysmap_size++] = 0;
1042 file.fs->close(&file);
1043 memset(&file, 0, sizeof(file));
1046 prom_printf("System.map loaded at %p, size: %lu Kbytes\n",
1047 sysmap_base, sysmap_size >> 10);
1048 loadinfo.memsize += _ALIGN(0x100000, 0x1000);
1050 prom_printf("System.map load failed !\n");
1055 /* If ramdisk, load it (only if booting a vmlinux). For now, we
1056 * can't tell the size it will be so we claim an arbitrary amount
1059 if (flat_vmlinux && params.rd.file) {
1060 if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/'
1061 && params.kernel.file[0] != '\\')
1064 loc=(char*)malloc(strlen(params.rd.file)+3);
1066 prom_printf ("Malloc error\n");
1069 strcpy(loc,boot.file);
1070 strcat(loc,params.rd.file);
1071 free(params.rd.file);
1074 prom_printf("Loading ramdisk...\n");
1075 result = open_file(¶ms.rd, &file);
1076 if (result != FILE_ERR_OK) {
1077 prom_printf("%s:%d,", params.rd.dev, params.rd.part);
1078 prom_perror(result, params.rd.file);
1081 #define INITRD_CHUNKSIZE 0x100000
1082 initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0);
1083 if (initrd_base == (void *)-1) {
1084 prom_printf("Claim failed for initrd memory\n");
1087 initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base);
1088 if (initrd_size == 0)
1090 initrd_read = initrd_size;
1091 initrd_more = initrd_base;
1092 while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */
1093 initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE);
1094 initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0);
1095 if (initrd_more != initrd_want) {
1096 prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more);
1100 initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more);
1101 DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read);
1102 initrd_size += initrd_read;
1105 file.fs->close(&file);
1106 memset(&file, 0, sizeof(file));
1109 prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n",
1110 initrd_base, initrd_size >> 10);
1112 prom_printf("ramdisk load failed !\n");
1117 DEBUG_F("setting kernel args to: %s\n", params.args);
1118 prom_setargs(params.args);
1119 DEBUG_F("flushing icache...");
1120 flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize);
1125 * Fill new boot infos (only if booting a vmlinux).
1127 * The birec is low on memory, probably inside the malloc pool,
1128 * so we don't write it earlier. At this point, we should not
1129 * use anything coming from the malloc pool.
1131 birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20));
1133 /* We make sure it's mapped. We map only 64k for now, it's
1134 * plenty enough we don't claim since this precise memory
1135 * range may already be claimed by the malloc pool.
1137 prom_map (birec, birec, 0x10000);
1138 DEBUG_F("birec at %p\n", birec);
1141 birec->tag = BI_FIRST;
1142 birec->size = sizeof(struct bi_record);
1143 birec = (struct bi_record *)((ulong)birec + birec->size);
1145 birec->tag = BI_BOOTLOADER_ID;
1146 sprintf( (char *)birec->data, "yaboot");
1147 birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1;
1148 birec = (struct bi_record *)((ulong)birec + birec->size);
1150 birec->tag = BI_MACHTYPE;
1151 birec->data[0] = _machine;
1152 birec->size = sizeof(struct bi_record) + sizeof(ulong);
1153 birec = (struct bi_record *)((ulong)birec + birec->size);
1156 birec->tag = BI_SYSMAP;
1157 birec->data[0] = (ulong)sysmap_base;
1158 birec->data[1] = sysmap_size;
1159 birec->size = sizeof(struct bi_record) + sizeof(ulong)*2;
1160 birec = (struct bi_record *)((ulong)birec + birec->size);
1162 birec->tag = BI_LAST;
1163 birec->size = sizeof(struct bi_record);
1164 birec = (struct bi_record *)((ulong)birec + birec->size);
1167 /* compute the kernel's entry point. */
1168 kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc;
1170 DEBUG_F("Kernel entry point = %p\n", kernel_entry);
1171 DEBUG_F("kernel: arg1 = %p,\n"
1172 " arg2 = 0x%08lx,\n"
1176 initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1178 DEBUG_F("Entering kernel...\n");
1180 /* call the kernel with our stack. */
1181 kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0);
1189 load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo)
1192 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1194 int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident);
1195 unsigned long addr, loadaddr;
1197 /* Read the rest of the Elf header... */
1198 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1199 prom_printf("\nCan't read Elf32 image header\n");
1203 DEBUG_F("Elf32 header:\n");
1204 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1205 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1206 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1207 DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry);
1208 DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff);
1209 DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff);
1210 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1211 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1212 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1213 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1215 loadinfo->entry = e->e_entry;
1217 if (e->e_phnum > MAX_HEADERS) {
1218 prom_printf ("Can only load kernels with one program header\n");
1222 ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum);
1224 prom_printf ("Malloc error\n");
1228 /* Now, we read the section header */
1229 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1230 prom_printf ("seek error\n");
1233 if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) !=
1234 sizeof(Elf32_Phdr) * e->e_phnum) {
1235 prom_printf ("read error\n");
1239 /* Scan through the program header
1240 * HACK: We must return the _memory size of the kernel image, not the
1241 * file size (because we have to leave room before other boot
1242 * infos. This code works as a side effect of the fact that
1243 * we have one section and vaddr == p_paddr
1245 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1247 for (i = 0; i < e->e_phnum; ++i, ++p) {
1248 if (p->p_type != PT_LOAD || p->p_offset == 0)
1250 if (loadinfo->memsize == 0) {
1251 loadinfo->offset = p->p_offset;
1252 loadinfo->memsize = p->p_memsz;
1253 loadinfo->filesize = p->p_filesz;
1254 loadinfo->load_loc = p->p_vaddr;
1256 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1257 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1261 if (loadinfo->memsize == 0) {
1262 prom_printf("Can't find a loadable segment !\n");
1266 /* leave some room (1Mb) for boot infos */
1267 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1268 /* Claim OF memory */
1269 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1271 /* Determine whether we are trying to boot a vmlinux or some
1272 * other binary image (eg, zImage). We load vmlinux's at
1273 * KERNELADDR and all other binaries at their e_entry value.
1275 if (e->e_entry == KERNEL_LINK_ADDR_PPC32) {
1277 loadaddr = KERNELADDR;
1280 loadaddr = loadinfo->load_loc;
1283 /* On some systems, loadaddr may already be claimed, so try some
1284 * other nearby addresses before giving up.
1286 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1287 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1288 if (loadinfo->base != (void *)-1) break;
1290 if (loadinfo->base == (void *)-1) {
1291 prom_printf("Claim error, can't allocate kernel memory\n");
1295 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1296 loadinfo->base, loadinfo->memsize);
1297 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1298 loadaddr, loadinfo->memsize);
1300 /* Load the program segments... */
1302 for (i = 0; i < e->e_phnum; ++i, ++p) {
1303 unsigned long offset;
1304 if (p->p_type != PT_LOAD || p->p_offset == 0)
1307 /* Now, we skip to the image itself */
1308 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1309 prom_printf ("Seek error\n");
1310 prom_release(loadinfo->base, loadinfo->memsize);
1313 offset = p->p_vaddr - loadinfo->load_loc;
1314 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1315 prom_printf ("Read failed\n");
1316 prom_release(loadinfo->base, loadinfo->memsize);
1323 /* Return success at loading the Elf32 kernel */
1333 load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo)
1336 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1338 int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident);
1339 unsigned long addr, loadaddr;
1341 /* Read the rest of the Elf header... */
1342 if ((*(file->fs->read))(file, size, &e->e_version) < size) {
1343 prom_printf("\nCan't read Elf64 image header\n");
1347 DEBUG_F("Elf64 header:\n");
1348 DEBUG_F(" e.e_type = %d\n", (int)e->e_type);
1349 DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine);
1350 DEBUG_F(" e.e_version = %d\n", (int)e->e_version);
1351 DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry);
1352 DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff);
1353 DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff);
1354 DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags);
1355 DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize);
1356 DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize);
1357 DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum);
1359 loadinfo->entry = e->e_entry;
1361 if (e->e_phnum > MAX_HEADERS) {
1362 prom_printf ("Can only load kernels with one program header\n");
1366 ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum);
1368 prom_printf ("Malloc error\n");
1372 /* Now, we read the section header */
1373 if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) {
1374 prom_printf ("Seek error\n");
1377 if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) !=
1378 sizeof(Elf64_Phdr) * e->e_phnum) {
1379 prom_printf ("Read error\n");
1383 /* Scan through the program header
1384 * HACK: We must return the _memory size of the kernel image, not the
1385 * file size (because we have to leave room before other boot
1386 * infos. This code works as a side effect of the fact that
1387 * we have one section and vaddr == p_paddr
1389 loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0;
1391 for (i = 0; i < e->e_phnum; ++i, ++p) {
1392 if (p->p_type != PT_LOAD || p->p_offset == 0)
1394 if (loadinfo->memsize == 0) {
1395 loadinfo->offset = p->p_offset;
1396 loadinfo->memsize = p->p_memsz;
1397 loadinfo->filesize = p->p_filesz;
1398 loadinfo->load_loc = p->p_vaddr;
1400 loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */
1401 loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset;
1405 if (loadinfo->memsize == 0) {
1406 prom_printf("Can't find a loadable segment !\n");
1410 /* leave some room (1Mb) for boot infos */
1411 loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000;
1412 /* Claim OF memory */
1413 DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize);
1415 /* Determine whether we are trying to boot a vmlinux or some
1416 * other binary image (eg, zImage). We load vmlinux's at
1417 * KERNELADDR and all other binaries at their e_entry value.
1419 if (e->e_entry == KERNEL_LINK_ADDR_PPC64) {
1421 loadaddr = KERNELADDR;
1424 loadaddr = e->e_entry;
1427 /* On some systems, loadaddr may already be claimed, so try some
1428 * other nearby addresses before giving up.
1430 for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) {
1431 loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0);
1432 if (loadinfo->base != (void *)-1) break;
1434 if (loadinfo->base == (void *)-1) {
1435 prom_printf("Claim error, can't allocate kernel memory\n");
1439 DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n",
1440 loadinfo->base, loadinfo->memsize);
1441 DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n",
1442 loadaddr, loadinfo->memsize);
1444 /* Load the program segments... */
1446 for (i = 0; i < e->e_phnum; ++i, ++p) {
1447 unsigned long offset;
1448 if (p->p_type != PT_LOAD || p->p_offset == 0)
1451 /* Now, we skip to the image itself */
1452 if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) {
1453 prom_printf ("Seek error\n");
1454 prom_release(loadinfo->base, loadinfo->memsize);
1457 offset = p->p_vaddr - loadinfo->load_loc;
1458 if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) {
1459 prom_printf ("Read failed\n");
1460 prom_release(loadinfo->base, loadinfo->memsize);
1467 /* Return success at loading the Elf64 kernel */
1477 is_elf32(loadinfo_t *loadinfo)
1479 Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr);
1481 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1482 e->e_ident[EI_MAG1] == ELFMAG1 &&
1483 e->e_ident[EI_MAG2] == ELFMAG2 &&
1484 e->e_ident[EI_MAG3] == ELFMAG3 &&
1485 e->e_ident[EI_CLASS] == ELFCLASS32 &&
1486 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1487 e->e_type == ET_EXEC &&
1488 e->e_machine == EM_PPC);
1492 is_elf64(loadinfo_t *loadinfo)
1494 Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr);
1496 return (e->e_ident[EI_MAG0] == ELFMAG0 &&
1497 e->e_ident[EI_MAG1] == ELFMAG1 &&
1498 e->e_ident[EI_MAG2] == ELFMAG2 &&
1499 e->e_ident[EI_MAG3] == ELFMAG3 &&
1500 e->e_ident[EI_CLASS] == ELFCLASS64 &&
1501 e->e_ident[EI_DATA] == ELFDATA2MSB &&
1502 e->e_type == ET_EXEC &&
1503 e->e_machine == EM_PPC64);
1509 #ifdef CONFIG_SET_COLORMAP
1510 static unsigned char default_colors[] = {
1529 prom_handle scrn = PROM_INVALID_HANDLE;
1531 /* Try Apple's mac-boot screen ihandle */
1532 result = (int)call_prom_return("interpret", 1, 2,
1533 "\" _screen-ihandle\" $find if execute else 0 then", &scrn);
1534 DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn);
1536 if (scrn == 0 || scrn == PROM_INVALID_HANDLE) {
1538 /* Hrm... check to see if stdout is a display */
1539 scrn = call_prom ("instance-to-package", 1, 1, prom_stdout);
1540 DEBUG_F("instance-to-package of stdout is: %p\n", scrn);
1541 if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) {
1542 DEBUG_F("got it ! stdout is a screen\n");
1545 /* Else, we try to open the package */
1546 scrn = (prom_handle)call_prom( "open", 1, 1, "screen" );
1547 DEBUG_F("Open screen result: %p\n", scrn);
1551 if (scrn == PROM_INVALID_HANDLE) {
1552 prom_printf("No screen device found !/n");
1556 prom_set_color(scrn, i, default_colors[i*3],
1557 default_colors[i*3+1], default_colors[i*3+2]);
1559 prom_printf("\x1b[1;37m\x1b[2;40m");
1561 for (i=0;i<16; i++) {
1562 prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n",
1563 ansi_color_table[i].index,
1564 ansi_color_table[i].value,
1565 ansi_color_table[i].name,
1566 ansi_color_table[i].name);
1567 prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n",
1568 ansi_color_table[i].index,
1569 ansi_color_table[i].value+10,
1570 ansi_color_table[i].name,
1571 ansi_color_table[i].name);
1573 prom_printf("\x1b[1;37m\x1b[2;40m");
1574 #endif /* COLOR_TEST */
1580 #endif /* CONFIG_SET_COLORMAP */
1588 char conf_path[1024];
1590 if (_machine == _MACH_Pmac)
1593 prom_get_chosen("bootargs", bootargs, sizeof(bootargs));
1594 DEBUG_F("/chosen/bootargs = %s\n", bootargs);
1595 prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ);
1596 DEBUG_F("/chosen/bootpath = %s\n", bootdevice);
1598 /* If conf= specified on command line, it overrides
1599 Usage: conf=device:partition,/path/to/conffile
1600 Example: On Open Firmware Prompt, type
1601 boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */
1603 if (!strncmp(bootargs, "conf=", 5)) {
1604 DEBUG_F("Using conf argument in Open Firmware\n");
1605 char *end = strchr(bootargs,' ');
1609 strcpy(bootdevice, bootargs + 5);
1611 DEBUG_F("Using conf=%s\n", bootdevice);
1613 /* Remove conf=xxx from bootargs */
1615 memmove(bootargs, end+1, strlen(end+1)+1);
1619 if (bootdevice[0] == 0) {
1620 prom_get_options("boot-device", bootdevice, BOOTDEVSZ);
1621 DEBUG_F("boot-device = %s\n", bootdevice);
1623 if (bootdevice[0] == 0) {
1624 prom_printf("Couldn't determine boot device\n");
1628 if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) {
1629 prom_printf("%s: Unable to parse\n", bootdevice);
1632 DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n",
1633 boot.dev, boot.part, boot.file);
1636 if (_machine == _MACH_chrp)
1637 boot.file = "/etc/";
1638 else if (strlen(boot.file)) {
1639 if (!strncmp(boot.file, "\\\\", 2))
1643 p = last = boot.file;
1653 if (strlen(boot.file))
1654 strcat(boot.file, "\\");
1657 strcpy(conf_path, boot.file);
1658 strcat(conf_path, CONFIG_FILE_NAME);
1659 boot.file = conf_path;
1660 DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n",
1661 boot.dev, boot.part, boot.file);
1665 * If we're doing a netboot, first look for one which matches our
1668 if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) {
1669 prom_printf("Try to netboot\n");
1670 useconf = load_my_config_file(&boot);
1674 useconf = load_config_file(&boot);
1676 prom_printf("Welcome to yaboot version " VERSION "\n");
1677 prom_printf("Enter \"help\" to get some basic usage information\n");
1679 /* I am fed up with lusers using the wrong partition type and
1680 mailing me *when* it breaks */
1682 if (_machine == _MACH_Pmac) {
1683 char *entry = cfg_get_strg(0, "ptypewarning");
1686 warn = strcmp(entry,
1687 "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks");
1689 ptype = get_part_type(boot.dev, boot.part);
1690 if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap")))
1691 prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n"
1692 " type should be: \"Apple_Bootstrap\"\n\n", ptype);
1700 prom_printf("Bye.\n");
1706 * c-file-style: "k&r"