diff -urN yaboot-1.3.14/include/prom.h yaboot-1.3.14-fixes/include/prom.h --- yaboot-1.3.14/include/prom.h 2007-08-17 10:29:26.000000000 -0400 +++ yaboot-1.3.14-fixes/include/prom.h 2008-01-15 13:32:06.000000000 -0500 @@ -37,6 +37,9 @@ #define PROM_INVALID_HANDLE ((prom_handle)-1UL) #define BOOTDEVSZ (2048) /* iscsi args can be in excess of 1040 bytes */ #define TOK_ISCSI "iscsi" +#define PROM_CLAIM_MAX_ADDR 0x8000000 +#define BOOTLASTSZ 1024 +#define FW_NBR_REBOOTSZ 4 struct prom_args; typedef int (*prom_entry)(struct prom_args *); @@ -85,6 +88,7 @@ /* memory */ +void *prom_claim_chunk(void *virt, unsigned int size, unsigned int align); void *prom_claim (void *virt, unsigned int size, unsigned int align); void prom_release(void *virt, unsigned int size); void prom_map (void *phys, void *virt, int size); @@ -154,5 +158,8 @@ struct bootp_packet * prom_get_netinfo (void); char * prom_get_mac (struct bootp_packet * packet); char * prom_get_ip (struct bootp_packet * packet); +char * prom_get_yiaddr (struct bootp_packet * packet); +char * prom_get_siaddr (struct bootp_packet * packet); +char * prom_get_giaddr (struct bootp_packet * packet); #endif diff -urN yaboot-1.3.14/include/prom.h.orig yaboot-1.3.14-fixes/include/prom.h.orig --- yaboot-1.3.14/include/prom.h.orig 1969-12-31 19:00:00.000000000 -0500 +++ yaboot-1.3.14-fixes/include/prom.h.orig 2008-01-15 13:32:06.000000000 -0500 @@ -0,0 +1,162 @@ +/* + * prom.h - Routines for talking to the Open Firmware PROM + * + * Copyright (C) 2001 Ethan Benson + * + * Copyright (C) 1999 Benjamin Herrenschmidt + * + * Copyright (C) 1999 Marius Vollmer + * + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PROM_H +#define PROM_H + +#include "types.h" +#include "stdarg.h" + +typedef void *prom_handle; +typedef void *ihandle; +typedef void *phandle; + +#define PROM_INVALID_HANDLE ((prom_handle)-1UL) +#define BOOTDEVSZ (2048) /* iscsi args can be in excess of 1040 bytes */ +#define TOK_ISCSI "iscsi" +#define PROM_CLAIM_MAX_ADDR 0x8000000 +#define BOOTLASTSZ 1024 +#define FW_NBR_REBOOTSZ 4 + +struct prom_args; +typedef int (*prom_entry)(struct prom_args *); + +extern void prom_init (prom_entry pe); + +extern prom_entry prom; + +/* I/O */ + +extern prom_handle prom_stdin; +extern prom_handle prom_stdout; + +prom_handle prom_open (char *spec); +int prom_read (prom_handle file, void *buf, int len); +int prom_write (prom_handle file, void *buf, int len); +int prom_seek (prom_handle file, int pos); +int prom_lseek (prom_handle file, unsigned long long pos); +int prom_readblocks (prom_handle file, int blockNum, int blockCount, void *buffer); +void prom_close (prom_handle file); +int prom_getblksize (prom_handle file); +int prom_loadmethod (prom_handle device, void* addr); + +#define K_UP 0x141 +#define K_DOWN 0x142 +#define K_LEFT 0x144 +#define K_RIGHT 0x143 + +int prom_getchar (); +void prom_putchar (char); +int prom_nbgetchar(); + +#ifdef __GNUC__ +void prom_vprintf (char *fmt, va_list ap) __attribute__ ((format (printf, 1, 0))); +void prom_fprintf (prom_handle dev, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +void prom_printf (char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +#else +void prom_vprintf (char *fmt, va_list ap); +void prom_fprintf (prom_handle dev, char *fmt, ...); +void prom_printf (char *fmt, ...); +#endif + +void prom_perror (int error, char *filename); +void prom_readline (char *prompt, char *line, int len); +int prom_set_color(prom_handle device, int color, int r, int g, int b); + +/* memory */ + +void *prom_claim_chunk(void *virt, unsigned int size, unsigned int align); +void *prom_claim (void *virt, unsigned int size, unsigned int align); +void prom_release(void *virt, unsigned int size); +void prom_map (void *phys, void *virt, int size); + +/* packages and device nodes */ + +prom_handle prom_finddevice (char *name); +prom_handle prom_findpackage (char *path); +int prom_getprop (prom_handle dev, char *name, void *buf, int len); +int prom_setprop (prom_handle dev, char *name, void *buf, int len); +int prom_getproplen(prom_handle, const char *); +int prom_get_devtype (char *device); + +/* misc */ + +char *prom_getargs (); +void prom_setargs (char *args); + +void prom_exit (); +void prom_abort (char *fmt, ...); +void prom_sleep (int seconds); + +int prom_interpret (char *forth); + +int prom_get_chosen (char *name, void *mem, int len); +int prom_get_options (char *name, void *mem, int len); +int prom_set_options (char *name, void *mem, int len); + +extern int prom_getms(void); +extern void prom_pause(void); + +extern void *call_prom (const char *service, int nargs, int nret, ...); +extern void *call_prom_return (const char *service, int nargs, int nret, ...); + +/* Netboot stuffs */ + +/* + * "bootp-response" is the property name which is specified in + * the recommended practice doc for obp-tftp. However, pmac + * provides a "dhcp-response" property and chrp provides a + * "bootpreply-packet" property. The latter appears to begin the + * bootp packet at offset 0x2a in the property for some reason. + */ + +struct bootp_property_offset { + char *name; /* property name */ + int offset; /* offset into property where bootp packet occurs */ +}; + +static const struct bootp_property_offset bootp_response_properties[] = { + { .name = "bootp-response", .offset = 0 }, + { .name = "dhcp-response", .offset = 0 }, + { .name = "bootpreply-packet", .offset = 0x2a }, +}; + +struct bootp_packet { + __u8 op, htype, hlen, hops; + __u32 xid; + __u16 secs, flags; + __u32 ciaddr, yiaddr, siaddr, giaddr; + unsigned char chaddr[16]; + unsigned char sname[64]; + unsigned char file[128]; + /* vendor options go here if we need them */ +}; + +struct bootp_packet * prom_get_netinfo (void); +char * prom_get_mac (struct bootp_packet * packet); +char * prom_get_ip (struct bootp_packet * packet); + +#endif diff -urN yaboot-1.3.14/second/fs_of.c yaboot-1.3.14-fixes/second/fs_of.c --- yaboot-1.3.14/second/fs_of.c 2007-08-17 10:29:26.000000000 -0400 +++ yaboot-1.3.14-fixes/second/fs_of.c 2008-01-15 13:32:06.000000000 -0500 @@ -44,9 +44,8 @@ #include "errors.h" #include "debug.h" -#define LOAD_BUFFER_POS 0x600000 -/* this cannot be safely increased any further */ -#define LOAD_BUFFER_SIZE 0x600000 +#define LOAD_BUFFER_POS 0x1000000 +#define LOAD_BUFFER_SIZE 0x1000000 static int of_open(struct boot_file_t* file, const char* dev_name, struct partition_t* part, const char* file_name); @@ -60,6 +59,8 @@ static int of_net_read(struct boot_file_t* file, unsigned int size, void* buffer); static int of_net_seek(struct boot_file_t* file, unsigned int newpos); +static int of_supports_real_tftp(void); +static int of_net_use_tftp = -1; struct fs_t of_filesystem = { @@ -131,6 +132,30 @@ return FILE_ERR_OK; } +/* + * older firmwares were really not capable of doing a tftp load. Ie, the + * 'boot' command line: :,, requires that + * to be running a bootp server, not simply a tftp server. The + * above syntax works with new firmwares. + * + * This function should return 1 if the running firmware fully supports + * tftp and 0 if not. + */ +static int of_supports_real_tftp() { + prom_handle h; + if(of_net_use_tftp>=0) return(of_net_use_tftp); + + h=prom_open("/packages/cas"); + if(h) { + prom_close(h); + of_net_use_tftp=1; + } else { + of_net_use_tftp=0; + } + return(of_net_use_tftp); +} + + static int of_net_open(struct boot_file_t* file, const char* dev_name, struct partition_t* part, const char* file_name) @@ -138,18 +163,33 @@ static char buffer[1024]; char *filename; char *p; + struct bootp_packet *packet; DEBUG_ENTER; DEBUG_OPEN; + strncpy(buffer, dev_name, 768); if (file_name && strlen(file_name)) { + if(of_supports_real_tftp()){ + packet = prom_get_netinfo(); + strcat(buffer, prom_get_siaddr(packet)); + } strcat(buffer, ","); filename = strdup(file_name); for (p = filename; *p; p++) if (*p == '/') *p = '\\'; strcat(buffer, filename); + if(of_supports_real_tftp()) { + strcat(buffer, ","); + strcat(buffer, prom_get_yiaddr(packet)); + strcat(buffer, ","); + /* Hack required since giaddr not returned on some systems + and required to boot on those systems. This should work + for the client and server on the same subnet. */ + strcat(buffer, prom_get_siaddr(packet)); + } free(filename); } @@ -166,7 +206,9 @@ return FILE_ERR_BAD_FSYS; } - file->buffer = prom_claim((void *)LOAD_BUFFER_POS, LOAD_BUFFER_SIZE, 0); + + file->buffer = prom_claim_chunk((void *)LOAD_BUFFER_POS, + LOAD_BUFFER_SIZE, 0); if (file->buffer == (void *)-1) { prom_printf("Can't claim memory for TFTP download\n"); prom_close(file->of_device); diff -urN yaboot-1.3.14/second/fs_of.c.orig yaboot-1.3.14-fixes/second/fs_of.c.orig --- yaboot-1.3.14/second/fs_of.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ yaboot-1.3.14-fixes/second/fs_of.c.orig 2008-01-15 13:32:06.000000000 -0500 @@ -0,0 +1,262 @@ +/* + * fs_of.c - an implementation for OpenFirmware supported filesystems + * + * Copyright (C) 2001, 2002 Ethan Benson + * + * Copyright (C) 1999 Benjamin Herrenschmidt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * BrokenFirmware cannot "read" from the network. We use tftp "load" + * method for network boot for now, we may provide our own NFS + * implementation in a later version. That means that we allocate a + * huge block of memory for the entire file before loading it. We use + * the location where the kernel puts RTAS, it's not used by the + * bootloader and if freed when the kernel is booted. This will have + * to be changed if we plan to instanciate RTAS in the bootloader + * itself + */ + +#include "ctype.h" +#include "types.h" +#include "stddef.h" +#include "stdlib.h" +#include "file.h" +#include "prom.h" +#include "string.h" +#include "partition.h" +#include "fdisk-part.h" +#include "fs.h" +#include "errors.h" +#include "debug.h" + +#define LOAD_BUFFER_POS 0x1000000 +#define LOAD_BUFFER_SIZE 0x1000000 + +static int of_open(struct boot_file_t* file, const char* dev_name, + struct partition_t* part, const char* file_name); +static int of_read(struct boot_file_t* file, unsigned int size, void* buffer); +static int of_seek(struct boot_file_t* file, unsigned int newpos); +static int of_close(struct boot_file_t* file); + + +static int of_net_open(struct boot_file_t* file, const char* dev_name, + struct partition_t* part, const char* file_name); +static int of_net_read(struct boot_file_t* file, unsigned int size, void* buffer); +static int of_net_seek(struct boot_file_t* file, unsigned int newpos); + + +struct fs_t of_filesystem = +{ + "built-in", + of_open, + of_read, + of_seek, + of_close +}; + +struct fs_t of_net_filesystem = +{ + "built-in network", + of_net_open, + of_net_read, + of_net_seek, + of_close +}; + +static int +of_open(struct boot_file_t* file, const char* dev_name, + struct partition_t* part, const char* file_name) +{ + static char buffer[1024]; + char *filename; + char *p; + + DEBUG_ENTER; + DEBUG_OPEN; + + strncpy(buffer, dev_name, 768); + strcat(buffer, ":"); + if (part) { + if (part->sys_ind == LINUX_RAID) { + DEBUG_F("skipping because partition is marked LINUX_RAID\n"); + DEBUG_LEAVE(FILE_ERR_BAD_FSYS); + return FILE_ERR_BAD_FSYS; + } + char pn[3]; + sprintf(pn, "%02d", part->part_number); + strcat(buffer, pn); + } + if (file_name && strlen(file_name)) { + if (part) + strcat(buffer, ","); + filename = strdup(file_name); + for (p = filename; *p; p++) + if (*p == '/') + *p = '\\'; + strcat(buffer, filename); + free(filename); + } + + DEBUG_F("opening: \"%s\"\n", buffer); + + file->of_device = prom_open(buffer); + + DEBUG_F("file->of_device = %p\n", file->of_device); + + file->pos = 0; + file->buffer = NULL; + if ((file->of_device == PROM_INVALID_HANDLE) || (file->of_device == 0)) + { + DEBUG_LEAVE(FILE_ERR_BAD_FSYS); + return FILE_ERR_BAD_FSYS; + } + + DEBUG_LEAVE(FILE_ERR_OK); + return FILE_ERR_OK; +} + +static int +of_net_open(struct boot_file_t* file, const char* dev_name, + struct partition_t* part, const char* file_name) +{ + static char buffer[1024]; + char *filename; + char *p; + struct bootp_packet *packet; + + DEBUG_ENTER; + DEBUG_OPEN; + + packet = prom_get_netinfo(); + + strncpy(buffer, dev_name, 768); + if (file_name && strlen(file_name)) { + strcat(buffer, prom_get_siaddr(packet)); + strcat(buffer, ","); + filename = strdup(file_name); + for (p = filename; *p; p++) + if (*p == '/') + *p = '\\'; + strcat(buffer, filename); + strcat(buffer, ","); + strcat(buffer, prom_get_yiaddr(packet)); + strcat(buffer, ","); + /* Hack required since giaddr not returned on some systems + and required to boot on those systems. This should work + for the client and server on the same subnet. */ + strcat(buffer, prom_get_siaddr(packet)); + free(filename); + } + + DEBUG_F("Opening: \"%s\"\n", buffer); + + file->of_device = prom_open(buffer); + + DEBUG_F("file->of_device = %p\n", file->of_device); + + file->pos = 0; + if ((file->of_device == PROM_INVALID_HANDLE) || (file->of_device == 0)) + { + DEBUG_LEAVE(FILE_ERR_BAD_FSYS); + return FILE_ERR_BAD_FSYS; + } + + + file->buffer = prom_claim_chunk((void *)LOAD_BUFFER_POS, + LOAD_BUFFER_SIZE, 0); + if (file->buffer == (void *)-1) { + prom_printf("Can't claim memory for TFTP download\n"); + prom_close(file->of_device); + DEBUG_LEAVE(FILE_IOERR); + return FILE_IOERR; + } + memset(file->buffer, 0, LOAD_BUFFER_SIZE); + + DEBUG_F("TFP...\n"); + + file->len = prom_loadmethod(file->of_device, file->buffer); + + DEBUG_F("result: %Ld\n", file->len); + + DEBUG_LEAVE(FILE_ERR_OK); + return FILE_ERR_OK; +} + +static int +of_read(struct boot_file_t* file, unsigned int size, void* buffer) +{ + unsigned int count; + + count = prom_read(file->of_device, buffer, size); + file->pos += count; + return count; +} + +static int +of_net_read(struct boot_file_t* file, unsigned int size, void* buffer) +{ + unsigned int count, av; + + av = file->len - file->pos; + count = size > av ? av : size; + memcpy(buffer, file->buffer + file->pos, count); + file->pos += count; + return count; +} + +static int +of_seek(struct boot_file_t* file, unsigned int newpos) +{ + if (prom_seek(file->of_device, newpos)) { + file->pos = newpos; + return FILE_ERR_OK; + } + + return FILE_CANT_SEEK; +} + +static int +of_net_seek(struct boot_file_t* file, unsigned int newpos) +{ + file->pos = (newpos > file->len) ? file->len : newpos; + return FILE_ERR_OK; +} + +static int +of_close(struct boot_file_t* file) +{ + + DEBUG_ENTER; + DEBUG_F("<@%p>\n", file->of_device); + + if (file->buffer) { + prom_release(file->buffer, LOAD_BUFFER_SIZE); + } + prom_close(file->of_device); + DEBUG_F("of_close called\n"); + + DEBUG_LEAVE(0); + return 0; +} + +/* + * Local variables: + * c-file-style: "k&r" + * c-basic-offset: 5 + * End: + */ diff -urN yaboot-1.3.14/second/prom.c yaboot-1.3.14-fixes/second/prom.c --- yaboot-1.3.14/second/prom.c 2007-08-17 10:29:26.000000000 -0400 +++ yaboot-1.3.14-fixes/second/prom.c 2008-01-15 13:32:06.000000000 -0500 @@ -568,6 +568,25 @@ while (prom_getms() <= end); } +/* if address given is claimed look for other addresses to get the needed + * space before giving up + */ +void * +prom_claim_chunk(void *virt, unsigned int size, unsigned int align) +{ + void *found, *addr; + for(addr=virt; addr <= (void*)PROM_CLAIM_MAX_ADDR; + addr+=(0x100000/sizeof(addr))) { + found = prom_claim(addr, size, 0); + if (found != (void *)-1) { + DEBUG_F("claimed %i at 0x%x (0x%x)\n",size,(int)found,(int)virt); + return(found); + } + } + prom_printf("Claim error, can't allocate %x at 0x%x\n",size,(int)virt); + return((void*)-1); +} + void * prom_claim (void *virt, unsigned int size, unsigned int align) { @@ -752,6 +771,78 @@ } /* + * prom_get_yiaddr() + * returns the ip addr of the client in dotted decimal format + */ +char * prom_get_yiaddr (struct bootp_packet * packet) +{ + char * conf_path; + + if (!packet) + return NULL; + + /* 15 chars in yiaddr + \0 */ + conf_path = malloc(16); + if (!conf_path) + return NULL; + sprintf(conf_path, "%d.%d.%d.%d", + packet->yiaddr >> 24, + (packet->yiaddr << 8) >> 24, + (packet->yiaddr << 16) >> 24, + (packet->yiaddr << 24) >> 24); + + return conf_path; +} + +/* + * prom_get_siaddr() + * returns the ip addr of the server in dotted decimal format + */ +char * prom_get_siaddr (struct bootp_packet * packet) +{ + char * conf_path; + + if (!packet) + return NULL; + + /* 15 chars in siaddr + \0 */ + conf_path = malloc(16); + if (!conf_path) + return NULL; + sprintf(conf_path, "%d.%d.%d.%d", + packet->siaddr >> 24, + (packet->siaddr << 8) >> 24, + (packet->siaddr << 16) >> 24, + (packet->siaddr << 24) >> 24); + + return conf_path; +} + +/* + * prom_get_giaddr() + * returns the ip addr of the gateway in dotted decimal format + */ +char * prom_get_giaddr (struct bootp_packet * packet) +{ + char * conf_path; + + if (!packet) + return NULL; + + /* 15 chars in giaddr + \0 */ + conf_path = malloc(16); + if (!conf_path) + return NULL; + sprintf(conf_path, "%d.%d.%d.%d", + packet->giaddr >> 24, + (packet->giaddr << 8) >> 24, + (packet->giaddr << 16) >> 24, + (packet->giaddr << 24) >> 24); + + return conf_path; +} + +/* * Local variables: * c-file-style: "k&r" * c-basic-offset: 5 diff -urN yaboot-1.3.14/second/prom.c.orig yaboot-1.3.14-fixes/second/prom.c.orig --- yaboot-1.3.14/second/prom.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ yaboot-1.3.14-fixes/second/prom.c.orig 2008-01-15 13:32:06.000000000 -0500 @@ -0,0 +1,778 @@ +/* + * prom.c - Routines for talking to the Open Firmware PROM + * + * Copyright (C) 2001, 2002 Ethan Benson + * + * Copyright (C) 1999 Benjamin Herrenschmidt + * + * Copyright (C) 1999 Marius Vollmer + * + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "prom.h" +#include "stdarg.h" +#include "stddef.h" +#include "stdlib.h" +#include "types.h" +#include "ctype.h" +#include "asm/processor.h" +#include "errors.h" +#include "debug.h" +#include "string.h" + +#define READ_BLOCKS_USE_READ 1 + +prom_entry prom; + +ihandle prom_stdin, prom_stdout; + +//extern int vsprintf(char *buf, const char *fmt, va_list args); + +static ihandle prom_mem, prom_mmu; +static ihandle prom_chosen, prom_options; + +struct prom_args { + const char *service; + int nargs; + int nret; + void *args[10]; +}; + +void * +call_prom (const char *service, int nargs, int nret, ...) +{ + va_list list; + int i; + struct prom_args prom_args; + + prom_args.service = service; + prom_args.nargs = nargs; + prom_args.nret = nret; + va_start (list, nret); + for (i = 0; i < nargs; ++i) + prom_args.args[i] = va_arg(list, void *); + va_end(list); + for (i = 0; i < nret; ++i) + prom_args.args[i + nargs] = 0; + prom (&prom_args); + if (nret > 0) + return prom_args.args[nargs]; + else + return 0; +} + +void * +call_prom_return (const char *service, int nargs, int nret, ...) +{ + va_list list; + int i; + void* result; + struct prom_args prom_args; + + prom_args.service = service; + prom_args.nargs = nargs; + prom_args.nret = nret; + va_start (list, nret); + for (i = 0; i < nargs; ++i) + prom_args.args[i] = va_arg(list, void *); + for (i = 0; i < nret; ++i) + prom_args.args[i + nargs] = 0; + if (prom (&prom_args) != 0) + return PROM_INVALID_HANDLE; + if (nret > 0) { + result = prom_args.args[nargs]; + for (i=1; i for device: %s\n", device); + return FILE_ERR_BADDEV; + } + tmp[result] = 0; + if (!strcmp(tmp, "block")) + return FILE_DEVICE_BLOCK; + else if (!strcmp(tmp, "network")) + return FILE_DEVICE_NET; + else { + prom_printf("Unkown device type <%s>\n", tmp); + return FILE_ERR_BADDEV; + } +} + +void +prom_init (prom_entry pp) +{ + prom = pp; + + prom_chosen = prom_finddevice ("/chosen"); + if (prom_chosen == (void *)-1) + prom_exit (); + prom_options = prom_finddevice ("/options"); + if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0) + prom_exit(); + if (prom_get_chosen ("stdin", &prom_stdin, sizeof(prom_stdin)) <= 0) + prom_abort ("\nCan't open stdin"); + if (prom_get_chosen ("memory", &prom_mem, sizeof(prom_mem)) <= 0) + prom_abort ("\nCan't get mem handle"); + if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0) + prom_abort ("\nCan't get mmu handle"); + + // move cursor to fresh line + prom_printf ("\n"); + + /* Add a few OF methods (thanks Darwin) */ +#if DEBUG + prom_printf ("Adding OF methods...\n"); +#endif + + prom_interpret ( + /* All values in this forth code are in hex */ + "hex " + /* Those are a few utilities ripped from Apple */ + ": D2NIP decode-int nip nip ;\r" // A useful function to save space + ": GPP$ get-package-property 0= ;\r" // Another useful function to save space + ": ^on0 0= if -1 throw then ;\r" // Bail if result zero + ": $CM $call-method ;\r" + ); + + /* Some forth words used by the release method */ + prom_interpret ( + " \" /chosen\" find-package if " + "dup \" memory\" rot GPP$ if " + "D2NIP swap " // ( MEMORY-ihandle "/chosen"-phandle ) + "\" mmu\" rot GPP$ if " + "D2NIP " // ( MEMORY-ihandle MMU-ihandle ) + "else " + "0 " // ( MEMORY-ihandle 0 ) + "then " + "else " + "0 0 " // ( 0 0 ) + "then " + "else " + "0 0 " // ( 0 0 ) + "then\r" + "value mmu# " + "value mem# " + ); + + prom_interpret ( + ": ^mem mem# $CM ; " + ": ^mmu mmu# $CM ; " + ); + + DEBUG_F("OF interface initialized.\n"); +} + +prom_handle +prom_open (char *spec) +{ + return call_prom ("open", 1, 1, spec, strlen(spec)); +} + +void +prom_close (prom_handle file) +{ + call_prom ("close", 1, 0, file); +} + +int +prom_read (prom_handle file, void *buf, int n) +{ + int result = 0; + int retries = 10; + + if (n == 0) + return 0; + while(--retries) { + result = (int)call_prom ("read", 3, 1, file, buf, n); + if (result != 0) + break; + call_prom("interpret", 1, 1, " 10 ms"); + } + + return result; +} + +int +prom_write (prom_handle file, void *buf, int n) +{ + return (int)call_prom ("write", 3, 1, file, buf, n); +} + +int +prom_seek (prom_handle file, int pos) +{ + int status = (int)call_prom ("seek", 3, 1, file, 0, pos); + return status == 0 || status == 1; +} + +int +prom_lseek (prom_handle file, unsigned long long pos) +{ + int status = (int)call_prom ("seek", 3, 1, file, + (unsigned int)(pos >> 32), (unsigned int)(pos & 0xffffffffUL)); + return status == 0 || status == 1; +} + +int +prom_loadmethod (prom_handle device, void* addr) +{ + return (int)call_method_1 ("load", device, 1, addr); +} + +int +prom_getblksize (prom_handle file) +{ + return (int)call_method_1 ("block-size", file, 0); +} + +int +prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer) +{ +#if READ_BLOCKS_USE_READ + int status; + unsigned int blksize; + + blksize = prom_getblksize(dev); + if (blksize <= 1) + blksize = 512; + status = prom_seek(dev, blockNum * blksize); + if (status != 1) { + return 0; + prom_printf("Can't seek to 0x%x\n", blockNum * blksize); + } + + status = prom_read(dev, buffer, blockCount * blksize); +// prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n", +// blockNum, blockCount, status); + + return status == (blockCount * blksize); +#else + int result; + int retries = 10; + + if (blockCount == 0) + return blockCount; + while(--retries) { + result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount); + if (result != 0) + break; + call_prom("interpret", 1, 1, " 10 ms"); + } + + return result; +#endif +} + +int +prom_getchar () +{ + char c[4]; + int a; + + while ((a = (int)call_prom ("read", 3, 1, prom_stdin, c, 4)) == 0) + ; + if (a == -1) + prom_abort ("EOF on console\n"); + if (a == 3 && c[0] == '\e' && c[1] == '[') + return 0x100 | c[2]; + return c[0]; +} + +int +prom_nbgetchar() +{ + char ch; + + return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1; +} + +void +prom_putchar (char c) +{ + if (c == '\n') + call_prom ("write", 3, 1, prom_stdout, "\r\n", 2); + else + call_prom ("write", 3, 1, prom_stdout, &c, 1); +} + +void +prom_puts (prom_handle file, char *s) +{ + const char *p, *q; + + for (p = s; *p != 0; p = q) + { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom ("write", 3, 1, file, p, q - p); + if (*q != 0) + { + ++q; + call_prom ("write", 3, 1, file, "\r\n", 2); + } + } +} + +void +prom_vfprintf (prom_handle file, char *fmt, va_list ap) +{ + static char printf_buf[2048]; + vsprintf (printf_buf, fmt, ap); + prom_puts (file, printf_buf); +} + +void +prom_vprintf (char *fmt, va_list ap) +{ + static char printf_buf[2048]; + vsprintf (printf_buf, fmt, ap); + prom_puts (prom_stdout, printf_buf); +} + +void +prom_fprintf (prom_handle file, char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + prom_vfprintf (file, fmt, ap); + va_end (ap); +} + +void +prom_printf (char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + prom_vfprintf (prom_stdout, fmt, ap); + va_end (ap); +} + +void +prom_perror (int error, char *filename) +{ + if (error == FILE_ERR_EOF) + prom_printf("%s: Unexpected End Of File\n", filename); + else if (error == FILE_ERR_NOTFOUND) + prom_printf("%s: No such file or directory\n", filename); + else if (error == FILE_CANT_SEEK) + prom_printf("%s: Seek error\n", filename); + else if (error == FILE_IOERR) + prom_printf("%s: Input/output error\n", filename); + else if (error == FILE_BAD_PATH) + prom_printf("%s: Path too long\n", filename); + else if (error == FILE_ERR_BAD_TYPE) + prom_printf("%s: Not a regular file\n", filename); + else if (error == FILE_ERR_NOTDIR) + prom_printf("%s: Not a directory\n", filename); + else if (error == FILE_ERR_BAD_FSYS) + prom_printf("%s: Unknown or corrupt filesystem\n", filename); + else if (error == FILE_ERR_SYMLINK_LOOP) + prom_printf("%s: Too many levels of symbolic links\n", filename); + else if (error == FILE_ERR_LENGTH) + prom_printf("%s: File too large\n", filename); + else if (error == FILE_ERR_FSBUSY) + prom_printf("%s: Filesystem busy\n", filename); + else if (error == FILE_ERR_BADDEV) + prom_printf("%s: Unable to open file, Invalid device\n", filename); + else + prom_printf("%s: Unknown error\n", filename); +} + +void +prom_readline (char *prompt, char *buf, int len) +{ + int i = 0; + int c; + + if (prompt) + prom_puts (prom_stdout, prompt); + + while (i < len-1 && (c = prom_getchar ()) != '\r') + { + if (c >= 0x100) + continue; + if (c == 8) + { + if (i > 0) + { + prom_puts (prom_stdout, "\b \b"); + i--; + } + else + prom_putchar ('\a'); + } + else if (isprint (c)) + { + prom_putchar (c); + buf[i++] = c; + } + else + prom_putchar ('\a'); + } + prom_putchar ('\n'); + buf[i] = 0; +} + +#ifdef CONFIG_SET_COLORMAP +int prom_set_color(prom_handle device, int color, int r, int g, int b) +{ + return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r ); +} +#endif /* CONFIG_SET_COLORMAP */ + +void +prom_exit () +{ + call_prom ("exit", 0, 0); +} + +void +prom_abort (char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + prom_vfprintf (prom_stdout, fmt, ap); + va_end (ap); + prom_exit (); +} + +void +prom_sleep (int seconds) +{ + int end; + end = (prom_getms() + (seconds * 1000)); + while (prom_getms() <= end); +} + +/* if address given is claimed look for other addresses to get the needed + * space before giving up + */ +void * +prom_claim_chunk(void *virt, unsigned int size, unsigned int align) +{ + void *found, *addr; + for(addr=virt; addr <= (void*)PROM_CLAIM_MAX_ADDR; + addr+=(0x100000/sizeof(addr))) { + found = prom_claim(addr, size, 0); + if (found != (void *)-1) { + DEBUG_F("claimed %i at 0x%x (0x%x)\n",size,(int)found,(int)virt); + return(found); + } + } + prom_printf("Claim error, can't allocate %x at 0x%x\n",size,(int)virt); + return((void*)-1); +} + +void * +prom_claim (void *virt, unsigned int size, unsigned int align) +{ + return call_prom ("claim", 3, 1, virt, size, align); +} + +void +prom_release(void *virt, unsigned int size) +{ + call_prom ("release", 2, 0, virt, size); +#if 0 /* this is bullshit, newworld OF RELEASE method works fine. */ + + /* release in not enough, it needs also an unmap call. This bit of forth + * code inspired from Darwin's bootloader but could be replaced by direct + * calls to the MMU package if needed + */ + call_prom ("interpret", 3, 1, +#if DEBUG + ".\" ReleaseMem:\" 2dup . . cr " +#endif + "over \" translate\" ^mmu " // Find out physical base + "^on0 " // Bail if translation failed + "drop " // Leaving phys on top of stack + "2dup \" unmap\" ^mmu " // Unmap the space first + "2dup \" release\" ^mmu " // Then free the virtual pages + "\" release\" ^mem " // Then free the physical pages + ,size, virt + ); +#endif /* bullshit */ +} + +void +prom_map (void *phys, void *virt, int size) +{ + unsigned long msr = mfmsr(); + + /* Only create a mapping if we're running with relocation enabled. */ + if ( (msr & MSR_IR) && (msr & MSR_DR) ) + call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys); +} + +void +prom_unmap (void *phys, void *virt, int size) +{ + unsigned long msr = mfmsr(); + + /* Only unmap if we're running with relocation enabled. */ + if ( (msr & MSR_IR) && (msr & MSR_DR) ) + call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys); +} + +char * +prom_getargs () +{ + static char args[256]; + int l; + + l = prom_get_chosen ("bootargs", args, 255); + args[l] = '\0'; + return args; +} + +void +prom_setargs (char *args) +{ + int l = strlen (args)+1; + if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l) + prom_printf ("can't set args\n"); +} + +int prom_interpret (char *forth) +{ + return (int)call_prom("interpret", 1, 1, forth); +} + +int +prom_getms(void) +{ + return (int) call_prom("milliseconds", 0, 1); +} + +void +prom_pause(void) +{ + call_prom("enter", 0, 0); +} + +/* + * prom_get_netinfo() + * returns the packet with all needed info for netboot + */ +struct bootp_packet * prom_get_netinfo (void) +{ + void *bootp_response = NULL; + char *propname; + struct bootp_packet *packet; + int i = 0, size, offset = 0; + prom_handle chosen; +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + + chosen = prom_finddevice("/chosen"); + if (chosen < 0) { + DEBUG_F("chosen=%d\n", chosen); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) { + propname = bootp_response_properties[i].name; + size = prom_getproplen(chosen, propname); + if (size <= 0) + continue; + + DEBUG_F("using /chosen/%s\n", propname); + offset = bootp_response_properties[i].offset; + break; + } + + if (size <= 0) + return NULL; + + if (sizeof(*packet) > size - offset) { + prom_printf("Malformed %s property?\n", propname); + return NULL; + } + + bootp_response = malloc(size); + if (!bootp_response) + return NULL; + + if (prom_getprop(chosen, propname, bootp_response, size) < 0) + return NULL; + + packet = bootp_response + offset; + return packet; +} + +/* + * prom_get_mac() + * returns the mac addr of an net card + */ +char * prom_get_mac (struct bootp_packet * packet) +{ + char * conf_path; + int i; + + if (!packet) + return NULL; + + /* 3 chars per byte in chaddr + \0 */ + conf_path = malloc(packet->hlen * 3 + 1); + if (!conf_path) + return NULL; + sprintf(conf_path, "%02x", packet->chaddr[0]); + + for (i = 1; i < packet->hlen; i++) { + char tmp[4]; + sprintf(tmp, "-%02x", packet->chaddr[i]); + strcat(conf_path, tmp); + } + + return conf_path; +} + +/* + * prom_get_ip() + * returns the ip addr of an net card + */ +char * prom_get_ip (struct bootp_packet * packet) +{ + char * conf_path; + + if (!packet) + return NULL; + + /* 8 chars in yiaddr + \0 */ + conf_path = malloc(9); + if (!conf_path) + return NULL; + sprintf(conf_path, "%08x", packet->yiaddr); + + return conf_path; +} + +/* + * Local variables: + * c-file-style: "k&r" + * c-basic-offset: 5 + * End: + */ diff -urN yaboot-1.3.14/second/yaboot.c yaboot-1.3.14-fixes/second/yaboot.c --- yaboot-1.3.14/second/yaboot.c 2007-08-17 10:29:26.000000000 -0400 +++ yaboot-1.3.14-fixes/second/yaboot.c 2008-01-15 13:32:06.000000000 -0500 @@ -114,6 +114,9 @@ char bootdevice[BOOTDEVSZ]; char bootoncelabel[1024]; char bootargs[1024]; +char bootlastlabel[BOOTLASTSZ] = {0}; +char fw_nbr_reboots[FW_NBR_REBOOTSZ] = {0}; +long fw_reboot_cnt = 0; char *password = NULL; struct boot_fspec_t boot; int _machine = _MACH_Pmac; @@ -665,7 +668,7 @@ cmdinit(); - if (first) { + if (first && !fw_reboot_cnt) { first = 0; imagename = bootargs; word_split(&imagename, ¶ms->args); @@ -680,6 +683,13 @@ timeout = simple_strtol(q, NULL, 0); } + /* If this is a reboot due to FW detecting CAS changes then + * set timeout to 1. The last kernel booted will be booted + * again automatically. It should seem seamless to the user + */ + if (fw_reboot_cnt) + timeout = 1; + prom_printf("boot: "); c = -1; if (timeout != -1) { @@ -716,7 +726,9 @@ if (!imagename) { if (bootoncelabel[0] != 0) imagename = bootoncelabel; - else + else if (bootlastlabel[0] != 0) + imagename = bootlastlabel; + else imagename = cfg_get_default(); } if (imagename) @@ -737,6 +749,9 @@ if ( useconf && (!imagename || imagename[0] == 0 )) imagename = cfg_get_default(); + /* write the imagename out so it can be reused on reboot if necessary */ + prom_set_options("boot-last-label", imagename, strlen(imagename)); + label = 0; defdevice = boot.dev; @@ -1233,7 +1248,7 @@ Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr); Elf32_Phdr *p, *ph; int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident); - unsigned long addr, loadaddr; + unsigned long loadaddr; /* Read the rest of the Elf header... */ if ((*(file->fs->read))(file, size, &e->e_version) < size) { @@ -1321,13 +1336,7 @@ loadaddr = loadinfo->load_loc; } - /* On some systems, loadaddr may already be claimed, so try some - * other nearby addresses before giving up. - */ - for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) { - loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0); - if (loadinfo->base != (void *)-1) break; - } + loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0); if (loadinfo->base == (void *)-1) { prom_printf("Claim error, can't allocate kernel memory\n"); goto bail; @@ -1377,7 +1386,7 @@ Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr); Elf64_Phdr *p, *ph; int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident); - unsigned long addr, loadaddr; + unsigned long loadaddr; /* Read the rest of the Elf header... */ if ((*(file->fs->read))(file, size, &e->e_version) < size) { @@ -1465,13 +1474,7 @@ loadaddr = e->e_entry; } - /* On some systems, loadaddr may already be claimed, so try some - * other nearby addresses before giving up. - */ - for(addr=loadaddr; addr <= loadaddr * 8 ;addr+=0x100000) { - loadinfo->base = prom_claim((void *)addr, loadinfo->memsize, 0); - if (loadinfo->base != (void *)-1) break; - } + loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0); if (loadinfo->base == (void *)-1) { prom_printf("Claim error, can't allocate kernel memory\n"); goto bail; @@ -1625,8 +1628,10 @@ yaboot_main(void) { char *ptype; + char *endp; int conf_given = 0; char conf_path[1024]; + int ret; if (_machine == _MACH_Pmac) setup_display(); @@ -1635,6 +1640,11 @@ DEBUG_F("/chosen/bootargs = %s\n", bootargs); prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ); DEBUG_F("/chosen/bootpath = %s\n", bootdevice); + if (prom_get_options("ibm,#reconfig-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ) == -1 ) + prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ); + fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10); + if (fw_reboot_cnt > 0L) + prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ); /* If conf= specified on command line, it overrides Usage: conf=device:partition,/path/to/conffile diff -urN yaboot-1.3.14/second/yaboot.c.orig yaboot-1.3.14-fixes/second/yaboot.c.orig --- yaboot-1.3.14/second/yaboot.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ yaboot-1.3.14-fixes/second/yaboot.c.orig 2008-01-15 13:32:06.000000000 -0500 @@ -0,0 +1,1766 @@ +/* + * Yaboot - secondary boot loader for Linux on PowerPC. + * + * Copyright (C) 2001, 2002 Ethan Benson + * + * Copyright (C) 1999, 2000, 2001 Benjamin Herrenschmidt + * + * IBM CHRP support + * + * Copyright (C) 2001 Peter Bergner + * + * portions based on poof + * + * Copyright (C) 1999 Marius Vollmer + * + * portions based on quik + * + * Copyright (C) 1996 Paul Mackerras. + * + * Because this program is derived from the corresponding file in the + * silo-0.64 distribution, it is also + * + * Copyright (C) 1996 Pete A. Zaitcev + * 1996 Maurizio Plaza + * 1996 David S. Miller + * 1996 Miguel de Icaza + * 1996 Jakub Jelinek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdarg.h" +#include "string.h" +#include "ctype.h" +#include "stdlib.h" +#include "prom.h" +#include "file.h" +#include "errors.h" +#include "cfg.h" +#include "cmdline.h" +#include "yaboot.h" +#include "linux/elf.h" +#include "bootinfo.h" +#include "debug.h" + +#define CONFIG_FILE_NAME "yaboot.conf" +#define CONFIG_FILE_MAX 0x8000 /* 32k */ + +#ifdef USE_MD5_PASSWORDS +#include "md5.h" +#endif /* USE_MD5_PASSWORDS */ + +/* align addr on a size boundry - adjust address up if needed -- Cort */ +#define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1))) + +/* Addresses where the PPC32 and PPC64 vmlinux kernels are linked at. + * These are used to determine whether we are booting a vmlinux, in + * which case, it will be loaded at KERNELADDR. Otherwise (eg zImage), + * we load the binary where it was linked at (ie, e_entry field in + * the ELF header). + */ +#define KERNEL_LINK_ADDR_PPC32 0xC0000000UL +#define KERNEL_LINK_ADDR_PPC64 0xC000000000000000ULL + +typedef struct { + union { + Elf32_Ehdr elf32hdr; + Elf64_Ehdr elf64hdr; + } elf; + void* base; + unsigned long memsize; + unsigned long filesize; + unsigned long offset; + unsigned long load_loc; + unsigned long entry; +} loadinfo_t; + +typedef void (*kernel_entry_t)( void *, + unsigned long, + prom_entry, + unsigned long, + unsigned long ); + +/* Imported functions */ +extern unsigned long reloc_offset(void); +extern long flush_icache_range(unsigned long start, unsigned long stop); + +/* Exported functions */ +int yaboot_start(unsigned long r3, unsigned long r4, unsigned long r5); + +/* Local functions */ +static int yaboot_main(void); +static int is_elf32(loadinfo_t *loadinfo); +static int is_elf64(loadinfo_t *loadinfo); +static int load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo); +static int load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo); +static void setup_display(void); + +/* Locals & globals */ + +int useconf = 0; +char bootdevice[BOOTDEVSZ]; +char bootoncelabel[1024]; +char bootargs[1024]; +char bootlastlabel[BOOTLASTSZ] = {0}; +char fw_nbr_reboots[FW_NBR_REBOOTSZ] = {0}; +long fw_reboot_cnt = 0; +char *password = NULL; +struct boot_fspec_t boot; +int _machine = _MACH_Pmac; +int flat_vmlinux; + +#ifdef CONFIG_COLOR_TEXT + +/* Color values for text ui */ +static struct ansi_color_t { + char* name; + int index; + int value; +} ansi_color_table[] = { + { "black", 2, 30 }, + { "blue", 0, 31 }, + { "green", 0, 32 }, + { "cyan", 0, 33 }, + { "red", 0, 34 }, + { "purple", 0, 35 }, + { "brown", 0, 36 }, + { "light-gray", 0, 37 }, + { "dark-gray", 1, 30 }, + { "light-blue", 1, 31 }, + { "light-green", 1, 32 }, + { "light-cyan", 1, 33 }, + { "light-red", 1, 34 }, + { "light-purple", 1, 35 }, + { "yellow", 1, 36 }, + { "white", 1, 37 }, + { NULL, 0, 0 }, +}; + +/* Default colors for text ui */ +int fgcolor = 15; +int bgcolor = 0; +#endif /* CONFIG_COLOR_TEXT */ + +#if DEBUG +static int test_bss; +static int test_data = 0; +#endif +static int pause_after; +static char *pause_message = "Type go to continue.\n"; +static char given_bootargs[1024]; +static int given_bootargs_by_user = 0; + +extern unsigned char linux_logo_red[]; +extern unsigned char linux_logo_green[]; +extern unsigned char linux_logo_blue[]; + +#define DEFAULT_TIMEOUT -1 + +/* Entry, currently called directly by crt0 (bss not inited) */ + +extern char* __bss_start; +extern char* _end; + +static struct first_info *quik_fip = NULL; + +int +yaboot_start (unsigned long r3, unsigned long r4, unsigned long r5) +{ + int result; + void* malloc_base = NULL; + prom_handle root; + + /* OF seems to do it, but I'm not very confident */ + memset(&__bss_start, 0, &_end - &__bss_start); + + /* Check for quik first stage bootloader (but I don't think we are + * compatible with it anyway, I'll look into backporting to older OF + * versions later + */ + if (r5 == 0xdeadbeef) { + r5 = r3; + quik_fip = (struct first_info *)r4; + } + + /* Initialize OF interface */ + prom_init ((prom_entry) r5); + + /* Allocate some memory for malloc'ator */ + malloc_base = prom_claim((void *)MALLOCADDR, MALLOCSIZE, 0); + if (malloc_base == (void *)-1) { + prom_printf("Can't claim malloc buffer (%d bytes at 0x%08x)\n", + MALLOCSIZE, MALLOCADDR); + return -1; + } + malloc_init(malloc_base, MALLOCSIZE); + DEBUG_F("Malloc buffer allocated at %p (%d bytes)\n", + malloc_base, MALLOCSIZE); + + /* A few useless DEBUG_F's */ + DEBUG_F("reloc_offset : %ld (should be 0)\n", reloc_offset()); + DEBUG_F("test_bss : %d (should be 0)\n", test_bss); + DEBUG_F("test_data : %d (should be 0)\n", test_data); + DEBUG_F("&test_data : %p\n", &test_data); + DEBUG_F("&test_bss : %p\n", &test_bss); + DEBUG_F("linked at : 0x%08x\n", TEXTADDR); + + /* ask the OF info if we're a chrp or pmac */ + /* we need to set _machine before calling finish_device_tree */ + root = prom_finddevice("/"); + if (root != 0) { + static char model[256]; + if (prom_getprop(root, "device_type", model, 256 ) > 0 && + !strncmp("chrp", model, 4)) + _machine = _MACH_chrp; + else { + if (prom_getprop(root, "model", model, 256 ) > 0 && + !strncmp(model, "IBM", 3)) + _machine = _MACH_chrp; + } + } + + DEBUG_F("Running on _machine = %d\n", _machine); + DEBUG_SLEEP; + + /* Call out main */ + result = yaboot_main(); + + /* Get rid of malloc pool */ + malloc_dispose(); + prom_release(malloc_base, MALLOCSIZE); + DEBUG_F("Malloc buffer released. Exiting with code %d\n", + result); + + /* Return to OF */ + prom_exit(); + + return result; + +} + +#ifdef CONFIG_COLOR_TEXT +/* + * Validify color for text ui + */ +static int +check_color_text_ui(char *color) +{ + int i = 0; + while(ansi_color_table[i].name) { + if (!strcmp(color, ansi_color_table[i].name)) + return i; + i++; + } + return -1; +} +#endif /* CONFIG_COLOR_TEXT */ + + +void print_message_file(char *filename) +{ + char *msg = NULL; + char *p, *endp; + char *defdev = boot.dev; + int defpart = boot.part; + char msgpath[1024]; + int opened = 0; + int result = 0; + int n; + struct boot_file_t file; + struct boot_fspec_t msgfile; + + defdev = cfg_get_strg(0, "device"); + if (!defdev) + defdev = boot.dev; + p = cfg_get_strg(0, "partition"); + if (p) { + n = simple_strtol(p, &endp, 10); + if (endp != p && *endp == 0) + defpart = n; + } + + strncpy(msgpath, filename, sizeof(msgpath)); + if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) { + prom_printf("%s: Unable to parse\n", msgpath); + goto done; + } + + result = open_file(&msgfile, &file); + if (result != FILE_ERR_OK) { + prom_printf("%s:%d,", msgfile.dev, msgfile.part); + prom_perror(result, msgfile.file); + goto done; + } else + opened = 1; + + msg = malloc(2001); + if (!msg) + goto done; + else + memset(msg, 0, 2001); + + if (file.fs->read(&file, 2000, msg) <= 0) + goto done; + else + prom_printf("%s", msg); + +done: + if (opened) + file.fs->close(&file); + if (msg) + free(msg); +} + +/* Currently, the config file must be at the root of the filesystem. + * todo: recognize the full path to myself and use it to load the + * config file. Handle the "\\" (blessed system folder) + */ +static int +load_config_file(struct boot_fspec_t *fspec) +{ + char *conf_file = NULL, *p; + struct boot_file_t file; + int sz, opened = 0, result = 0; + + /* Allocate a buffer for the config file */ + conf_file = malloc(CONFIG_FILE_MAX); + if (!conf_file) { + prom_printf("Can't alloc config file buffer\n"); + goto bail; + } + + /* Open it */ + result = open_file(fspec, &file); + if (result != FILE_ERR_OK) { + prom_printf("%s:%d,", fspec->dev, fspec->part); + prom_perror(result, fspec->file); + prom_printf("Can't open config file\n"); + goto bail; + } + opened = 1; + + /* Read it */ + sz = file.fs->read(&file, CONFIG_FILE_MAX, conf_file); + if (sz <= 0) { + prom_printf("Error, can't read config file\n"); + goto bail; + } + prom_printf("Config file read, %d bytes\n", sz); + + /* Close the file */ + if (opened) + file.fs->close(&file); + opened = 0; + + /* Call the parsing code in cfg.c */ + if (cfg_parse(fspec->file, conf_file, sz) < 0) { + prom_printf ("Syntax error or read error config\n"); + goto bail; + } + + /* + * set the default cf_option to label that has the same MAC addr + * it only works if there is a label with the MAC addr on yaboot.conf + */ + if (prom_get_devtype(fspec->dev) == FILE_DEVICE_NET) { + /* change the variable bellow to get the MAC dinamicaly */ + char * macaddr = NULL; + int default_mac = 0; + + macaddr = prom_get_mac(prom_get_netinfo()); + default_mac = cfg_set_default_by_mac(macaddr); + if (default_mac >= 1) { + prom_printf("Default label was changed to macaddr label.\n"); + } + } + + DEBUG_F("Config file successfully parsed, %d bytes\n", sz); + + /* Now, we do the initialisations stored in the config file */ + p = cfg_get_strg(0, "init-code"); + if (p) + prom_interpret(p); + + password = cfg_get_strg(0, "password"); + +#ifdef CONFIG_COLOR_TEXT + p = cfg_get_strg(0, "fgcolor"); + if (p) { + DEBUG_F("fgcolor=%s\n", p); + fgcolor = check_color_text_ui(p); + if (fgcolor == -1) { + prom_printf("Invalid fgcolor: \"%s\".\n", p); + } + } + p = cfg_get_strg(0, "bgcolor"); + if (p) { + DEBUG_F("bgcolor=%s\n", p); + bgcolor = check_color_text_ui(p); + if (bgcolor == -1) + prom_printf("Invalid bgcolor: \"%s\".\n", p); + } + if (bgcolor >= 0) { + char temp[64]; + sprintf(temp, "%x to background-color", bgcolor); + prom_interpret(temp); +#if !DEBUG + prom_printf("\xc"); +#endif /* !DEBUG */ + } + if (fgcolor >= 0) { + char temp[64]; + sprintf(temp, "%x to foreground-color", fgcolor); + prom_interpret(temp); + } +#endif /* CONFIG_COLOR_TEXT */ + + p = cfg_get_strg(0, "init-message"); + if (p) + prom_printf("%s\n", p); + + p = cfg_get_strg(0, "message"); + if (p) + print_message_file(p); + + result = 1; + +bail: + + if (opened) + file.fs->close(&file); + + if (conf_file) + free(conf_file); + + return result; +} + +/* + * Search for config file by MAC address, then by IP address. + * Basically copying pxelinux's algorithm. + * http://syslinux.zytor.com/pxe.php#config + */ +static int load_my_config_file(struct boot_fspec_t *orig_fspec) +{ + struct bootp_packet *packet; + int rc = 0; + struct boot_fspec_t fspec = *orig_fspec; + char *cfgpath = (_machine == _MACH_chrp) ? "/etc/" : ""; + int flen; + int minlen; + + packet = prom_get_netinfo(); + + /* + * First, try to match on mac address with the hardware type + * prepended. + */ + + /* 3 chars per byte in chaddr + 2 chars for htype + /etc/ +\0 */ + fspec.file = malloc(packet->hlen * 3 + 2 + 6); + if (!fspec.file) + goto out; + + sprintf(fspec.file, "%s%02x-", cfgpath, packet->htype); + strcat(fspec.file, prom_get_mac(packet)); + + rc = load_config_file(&fspec); + if (rc) + goto out; + + /* + * Now try to match on IP. + */ + /* no need to realloc for /etc/ + 8 chars in yiaddr + \0 */ + sprintf(fspec.file, "%s%s", cfgpath, prom_get_ip(packet)); + + for (flen = strlen(fspec.file), + minlen = strlen(cfgpath); flen > minlen; flen--) { + rc = load_config_file(&fspec); + if (rc) + goto out; + /* Chop one digit off the end, try again */ + fspec.file[flen - 1] = '\0'; + } + + out: + if (rc) /* modify original only on success */ + orig_fspec->file = fspec.file; + else + free(fspec.file); + return rc; +} + +void maintabfunc (void) +{ + if (useconf) { + cfg_print_images(); + prom_printf("boot: %s", cbuff); + } +} + +void +word_split(char **linep, char **paramsp) +{ + char *p; + + *paramsp = 0; + p = *linep; + if (p == 0) + return; + while (*p == ' ') + ++p; + if (*p == 0) { + *linep = 0; + return; + } + *linep = p; + while (*p != 0 && *p != ' ') + ++p; + while (*p == ' ') + *p++ = 0; + if (*p != 0) + *paramsp = p; +} + +char * +make_params(char *label, char *params) +{ + char *p, *q; + static char buffer[2048]; + + q = buffer; + *q = 0; + + p = cfg_get_strg(label, "literal"); + if (p) { + strcpy(q, p); + q = strchr(q, 0); + if (params) { + if (*p) + *q++ = ' '; + strcpy(q, params); + } + return buffer; + } + + p = cfg_get_strg(label, "root"); + if (p) { + strcpy (q, "root="); + strcpy (q + 5, p); + q = strchr (q, 0); + *q++ = ' '; + } + if (cfg_get_flag(label, "read-only")) { + strcpy (q, "ro "); + q += 3; + } + if (cfg_get_flag(label, "read-write")) { + strcpy (q, "rw "); + q += 3; + } + p = cfg_get_strg(label, "ramdisk"); + if (p) { + strcpy (q, "ramdisk="); + strcpy (q + 8, p); + q = strchr (q, 0); + *q++ = ' '; + } + p = cfg_get_strg(label, "initrd-size"); + if (p) { + strcpy (q, "ramdisk_size="); + strcpy (q + 13, p); + q = strchr (q, 0); + *q++ = ' '; + } + if (cfg_get_flag(label, "novideo")) { + strcpy (q, "video=ofonly"); + q = strchr (q, 0); + *q++ = ' '; + } + p = cfg_get_strg (label, "append"); + if (p) { + strcpy (q, p); + q = strchr (q, 0); + *q++ = ' '; + } + *q = 0; + pause_after = cfg_get_flag (label, "pause-after"); + p = cfg_get_strg(label, "pause-message"); + if (p) + pause_message = p; + if (params) + strcpy(q, params); + + return buffer; +} + +void check_password(char *str) +{ + int i; + + prom_printf("\n%s", str); + for (i = 0; i < 3; i++) { + prom_printf ("\nPassword: "); + passwdbuff[0] = 0; + cmdedit ((void (*)(void)) 0, 1); + prom_printf ("\n"); +#ifdef USE_MD5_PASSWORDS + if (!strncmp (password, "$1$", 3)) { + if (!check_md5_password(passwdbuff, password)) + return; + } + else if (!strcmp (password, passwdbuff)) + return; +#else /* !MD5 */ + if (!strcmp (password, passwdbuff)) + return; +#endif /* USE_MD5_PASSWORDS */ + if (i < 2) { + prom_sleep(1); + prom_printf ("Incorrect password. Try again."); + } + } + prom_printf(" ___________________\n< Permission denied >\n -------------------\n" + " \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n" + " ||----w |\n || ||\n"); + prom_sleep(4); + prom_interpret("reset-all"); +} + +int get_params(struct boot_param_t* params) +{ + int defpart; + char *defdevice = 0; + char defdevice_bak[1024]; + char *p, *q, *endp; + int c, n; + char *imagename = 0, *label; + int timeout = -1; + int beg = 0, end; + int singlekey = 0; + int restricted = 0; + static int first = 1; + static char imagepath[1024]; + static char initrdpath[1024]; + static char sysmappath[1024]; + + pause_after = 0; + memset(params, 0, sizeof(*params)); + params->args = ""; + params->kernel.part = -1; + params->rd.part = -1; + params->sysmap.part = -1; + defpart = boot.part; + + cmdinit(); + + if (first && !fw_reboot_cnt) { + first = 0; + imagename = bootargs; + word_split(&imagename, ¶ms->args); + timeout = DEFAULT_TIMEOUT; + if (imagename) { + prom_printf("Default supplied on the command line: %s ", imagename); + if (params->args) + prom_printf("%s", params->args); + prom_printf("\n"); + } + if (useconf && (q = cfg_get_strg(0, "timeout")) != 0 && *q != 0) + timeout = simple_strtol(q, NULL, 0); + } + + /* If this is a reboot due to FW detecting CAS changes then + * set timeout to 1. The last kernel booted will be booted + * again automatically. It should seem seamless to the user + */ + if (fw_reboot_cnt) + timeout = 1; + + prom_printf("boot: "); + c = -1; + if (timeout != -1) { + beg = prom_getms(); + if (timeout > 0) { + end = beg + 100 * timeout; + do { + c = prom_nbgetchar(); + } while (c == -1 && prom_getms() <= end); + } + if (c == -1) + c = '\n'; + else if (c != '\n' && c != '\t' && c != '\r' && c != '\b' ) { + cbuff[0] = c; + cbuff[1] = 0; + } + } + + if (c != -1 && c != '\n' && c != '\r') { + if (c == '\t') { + maintabfunc (); + } else if (c >= ' ') { + cbuff[0] = c; + cbuff[1] = 0; + if ((cfg_get_flag (cbuff, "single-key")) && useconf) { + imagename = cbuff; + singlekey = 1; + prom_printf("%s\n", cbuff); + } + } + } + + if (c == '\n' || c == '\r') { + if (!imagename) { + if (bootoncelabel[0] != 0) + imagename = bootoncelabel; + else if (bootlastlabel[0] != 0) + imagename = bootlastlabel; + else + imagename = cfg_get_default(); + } + if (imagename) + prom_printf("%s", imagename); + if (params->args) + prom_printf(" %s", params->args); + prom_printf("\n"); + } else if (!singlekey) { + cmdedit(maintabfunc, 0); + prom_printf("\n"); + strcpy(given_bootargs, cbuff); + given_bootargs_by_user = 1; + imagename = cbuff; + word_split(&imagename, ¶ms->args); + } + + /* chrp gets this wrong, force it -- Cort */ + if ( useconf && (!imagename || imagename[0] == 0 )) + imagename = cfg_get_default(); + + /* write the imagename out so it can be reused on reboot if necessary */ + prom_set_options("boot-last-label", imagename, strlen(imagename)); + + label = 0; + defdevice = boot.dev; + + strcpy(defdevice_bak,defdevice); + + if (useconf) { + defdevice = cfg_get_strg(0, "device"); + p = cfg_get_strg(0, "partition"); + if (p) { + n = simple_strtol(p, &endp, 10); + if (endp != p && *endp == 0) + defpart = n; + } + p = cfg_get_strg(0, "pause-message"); + if (p) + pause_message = p; + if (cfg_get_flag(0, "restricted")) + restricted = 1; + p = cfg_get_strg(imagename, "image"); + if (p && *p) { + label = imagename; + imagename = p; + defdevice = cfg_get_strg(label, "device"); + if(!defdevice) defdevice=boot.dev; + p = cfg_get_strg(label, "partition"); + if (p) { + n = simple_strtol(p, &endp, 10); + if (endp != p && *endp == 0) + defpart = n; + } + if (cfg_get_flag(label, "restricted")) + restricted = 1; + if (label) { + if (params->args && password && restricted) + check_password ("To specify arguments for this image " + "you must enter the password."); + else if (password && !restricted) + check_password ("This image is restricted."); + } + params->args = make_params(label, params->args); + } + } + + if (!strcmp (imagename, "help")) { + /* FIXME: defdevice shouldn't need to be reset all over the place */ + if(!defdevice) defdevice = boot.dev; + prom_printf( + "\nPress the tab key for a list of defined images.\n" + "The label marked with a \"*\" is is the default image, " + "press to boot it.\n\n" + "To boot any other label simply type its name and press .\n\n" + "To boot a kernel image which is not defined in the yaboot configuration \n" + "file, enter the kernel image name as [[device:][partno],]/path, where \n" + "\"device:\" is the OpenFirmware device path to the disk the image \n" + "resides on, and \"partno\" is the partition number the image resides on.\n" + "Note that the comma (,) is only required if you specify an OpenFirmware\n" + "device, if you only specify a filename you should not start it with a \",\"\n\n" + "To load an alternative config file rather than /etc/yaboot.conf, enter\n" + "its device, partno and path, on Open Firmware Prompt:\n" + "boot conf=device:partno,/path/to/configfile\n." + "To reload the config file or load a new one, use the \"conf\" command\n" + "on Yaboot's prompt:\n" + "conf [device=device] [partition=partno] [file=/path/to/configfile]\n\n" + "If you omit \"device\" and \"partno\", Yaboot will use their current\n" + "values. You can check them by entering \"conf\" on Yaboot's prompt.\n"); + + return 0; + } + + if (!strcmp (imagename, "halt")) { + if (password) + check_password ("Restricted command."); + prom_pause(); + return 0; + } + if (!strcmp (imagename, "bye")) { + if (password) { + check_password ("Restricted command."); + return 1; + } + return 1; + } + + if (!strncmp (imagename, "conf", 4)) { + + // imagename = "conf file=blah dev=bleh part=blih" + DEBUG_F("Loading user-specified config file: %s\n",imagename); + if (password) { + check_password ("Restricted command."); + return 1; + } + + // args= "file=blah dev=bleh part=blih" + char *args = params->args; + + if (strlen(args)){ + + // set a pointer to the first space in args + char *space = strchr(args,' '); + + int loop = 3; + while (loop > 0){ + char temp[1024] = "0"; + + // copy next argument to temp + strncpy(temp, args, space-args); + + // parse temp and set boot arguments + if (!strncmp (temp, "file=", 5)){ + DEBUG_F("conf file: %s\n", temp+5); + strcpy(boot.file, temp+5); + } else if (!strncmp (temp, "device=", 7)){ + DEBUG_F("conf device: %s\n", temp+7); + strcpy(boot.dev, temp+7); + } else if (!strncmp (temp, "partition=", 10)){ + DEBUG_F("conf partition: %s\n", temp+10); + boot.part=simple_strtol(temp+10,NULL,10); + } else + space = NULL; + + // set the pointer to the next space in args; + // set the loop control variable + if (strlen(space)>1){ + // Go to the next argument + args = space+1; + + loop--; + if (strchr(args,' ') == NULL) + space = &args[strlen(args)]; + else + space = strchr(args,' '); + } else { + loop = -1; + space = NULL; + } + } + + prom_printf("Loading config file...\n"); + useconf = load_config_file(&boot); + if (useconf > 0){ + if ((q = cfg_get_strg(0, "timeout")) != 0 && *q != 0) + timeout = simple_strtol(q, NULL, 0); + } else { + prom_printf("Restoring default values.\n"); + strcpy(boot.file,""); + strcpy(boot.dev, defdevice_bak); + boot.part = defpart; + } + + } else { + prom_printf("Current configuration:\n"); + prom_printf("device: %s\n", boot.dev); + if (boot.part < 0) + prom_printf("partition: auto\n"); + else + prom_printf("partition: %d\n", boot.part); + if (strlen(boot.file)) + prom_printf("file: %s\n", boot.file); + else + prom_printf("file: /etc/%s\n",CONFIG_FILE_NAME); + } + + imagename = "\0"; + params->args = "\0"; + + return 0; + } + + if (imagename[0] == '$') { + /* forth command string */ + if (password) + check_password ("OpenFirmware commands are restricted."); + prom_interpret(imagename+1); + return 0; + } + + strncpy(imagepath, imagename, 1024); + + if (!label && password) + check_password ("To boot a custom image you must enter the password."); + + if (!parse_device_path(imagepath, defdevice, defpart, + "/vmlinux", ¶ms->kernel)) { + prom_printf("%s: Unable to parse\n", imagepath); + return 0; + } + DEBUG_F("after parse_device_path: dev=%s part=%d file=%s\n", params->kernel.dev, + params->kernel.part, params->kernel.file); + + if (useconf) { + p = cfg_get_strg(label, "initrd"); + if (p && *p) { + DEBUG_F("Parsing initrd path <%s>\n", p); + strncpy(initrdpath, p, 1024); + if (!parse_device_path(initrdpath, defdevice, defpart, + "/root.bin", ¶ms->rd)) { + prom_printf("%s: Unable to parse\n", imagepath); + return 0; + } + } + p = cfg_get_strg(label, "sysmap"); + if (p && *p) { + DEBUG_F("Parsing sysmap path <%s>\n", p); + strncpy(sysmappath, p, 1024); + if (!parse_device_path(sysmappath, defdevice, defpart, + "/boot/System.map", ¶ms->sysmap)) { + prom_printf("%s: Unable to parse\n", imagepath); + return 0; + } + } + } + return 0; +} + +/* This is derived from quik core. To be changed to first parse the headers + * doing lazy-loading, and then claim the memory before loading the kernel + * to it + * We also need to add initrd support to this whole mecanism + */ +void +yaboot_text_ui(void) +{ +#define MAX_HEADERS 32 + + struct boot_file_t file; + int result; + static struct boot_param_t params; + void *initrd_base; + unsigned long initrd_size; + void *sysmap_base; + unsigned long sysmap_size; + kernel_entry_t kernel_entry; + struct bi_record* birec; + char* loc=NULL; + loadinfo_t loadinfo; + void *initrd_more,*initrd_want; + unsigned long initrd_read; + + loadinfo.load_loc = 0; + + for (;;) { + initrd_size = 0; + initrd_base = 0; + sysmap_base = 0; + sysmap_size = 0; + + if (get_params(¶ms)) + return; + if (!params.kernel.file) + continue; + + prom_printf("Please wait, loading kernel...\n"); + + memset(&file, 0, sizeof(file)); + + if (strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.kernel.file[0] != '/' + && params.kernel.file[0] != '\\') { + loc=(char*)malloc(strlen(params.kernel.file)+3); + if (!loc) { + prom_printf ("malloc error\n"); + goto next; + } + strcpy(loc,boot.file); + strcat(loc,params.kernel.file); + free(params.kernel.file); + params.kernel.file=loc; + } + result = open_file(¶ms.kernel, &file); + if (result != FILE_ERR_OK) { + prom_printf("%s:%d,", params.kernel.dev, params.kernel.part); + prom_perror(result, params.kernel.file); + goto next; + } + + /* Read the Elf e_ident, e_type and e_machine fields to + * determine Elf file type + */ + if (file.fs->read(&file, sizeof(Elf_Ident), &loadinfo.elf) < sizeof(Elf_Ident)) { + prom_printf("\nCan't read Elf e_ident/e_type/e_machine info\n"); + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + goto next; + } + + if (is_elf32(&loadinfo)) { + if (!load_elf32(&file, &loadinfo)) { + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + goto next; + } + prom_printf(" Elf32 kernel loaded...\n"); + } else if (is_elf64(&loadinfo)) { + if (!load_elf64(&file, &loadinfo)) { + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + goto next; + } + prom_printf(" Elf64 kernel loaded...\n"); + } else { + prom_printf ("%s: Not a valid ELF image\n", params.kernel.file); + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + goto next; + } + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + + /* If sysmap, load it (only if booting a vmlinux). + */ + if (flat_vmlinux && params.sysmap.file) { + prom_printf("Loading System.map ...\n"); + if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.sysmap.file[0] != '/' + && params.sysmap.file[0] != '\\') { + if (loc) free(loc); + loc=(char*)malloc(strlen(params.sysmap.file)+3); + if (!loc) { + prom_printf ("malloc error\n"); + goto next; + } + strcpy(loc,boot.file); + strcat(loc,params.sysmap.file); + free(params.sysmap.file); + params.sysmap.file=loc; + } + + result = open_file(¶ms.sysmap, &file); + if (result != FILE_ERR_OK) { + prom_printf("%s:%d,", params.sysmap.dev, params.sysmap.part); + prom_perror(result, params.sysmap.file); + } + else { + sysmap_base = prom_claim(loadinfo.base+loadinfo.memsize, 0x100000, 0); + if (sysmap_base == (void *)-1) { + prom_printf("Claim failed for sysmap memory\n"); + prom_pause(); + sysmap_base = 0; + } else { + sysmap_size = file.fs->read(&file, 0xfffff, sysmap_base); + if (sysmap_size == 0) + sysmap_base = 0; + else + ((char *)sysmap_base)[sysmap_size++] = 0; + } + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + } + if (sysmap_base) { + prom_printf("System.map loaded at %p, size: %lu Kbytes\n", + sysmap_base, sysmap_size >> 10); + loadinfo.memsize += _ALIGN(0x100000, 0x1000); + } else { + prom_printf("System.map load failed !\n"); + prom_pause(); + } + } + + /* If ramdisk, load it (only if booting a vmlinux). For now, we + * can't tell the size it will be so we claim an arbitrary amount + * of 4Mb. + */ + if (flat_vmlinux && params.rd.file) { + if(strlen(boot.file) && !strcmp(boot.file,"\\\\") && params.rd.file[0] != '/' + && params.kernel.file[0] != '\\') + { + if (loc) free(loc); + loc=(char*)malloc(strlen(params.rd.file)+3); + if (!loc) { + prom_printf ("Malloc error\n"); + goto next; + } + strcpy(loc,boot.file); + strcat(loc,params.rd.file); + free(params.rd.file); + params.rd.file=loc; + } + prom_printf("Loading ramdisk...\n"); + result = open_file(¶ms.rd, &file); + if (result != FILE_ERR_OK) { + prom_printf("%s:%d,", params.rd.dev, params.rd.part); + prom_perror(result, params.rd.file); + } + else { +#define INITRD_CHUNKSIZE 0x100000 + initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0); + if (initrd_base == (void *)-1) { + prom_printf("Claim failed for initrd memory\n"); + initrd_base = 0; + } else { + initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base); + if (initrd_size == 0) + initrd_base = 0; + initrd_read = initrd_size; + initrd_more = initrd_base; + while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */ + initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE); + initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0); + if (initrd_more != initrd_want) { + prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more); + prom_pause(); + break; + } + initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more); + DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read); + initrd_size += initrd_read; + } + } + file.fs->close(&file); + memset(&file, 0, sizeof(file)); + } + if (initrd_base) + prom_printf("ramdisk loaded at %p, size: %lu Kbytes\n", + initrd_base, initrd_size >> 10); + else { + prom_printf("ramdisk load failed !\n"); + prom_pause(); + } + } + + DEBUG_F("setting kernel args to: %s\n", params.args); + prom_setargs(params.args); + DEBUG_F("flushing icache..."); + flush_icache_range ((long)loadinfo.base, (long)loadinfo.base+loadinfo.memsize); + DEBUG_F(" done\n"); + + if (flat_vmlinux) { + /* + * Fill new boot infos (only if booting a vmlinux). + * + * The birec is low on memory, probably inside the malloc pool, + * so we don't write it earlier. At this point, we should not + * use anything coming from the malloc pool. + */ + birec = (struct bi_record *)_ALIGN(loadinfo.filesize+(1<<20)-1,(1<<20)); + + /* We make sure it's mapped. We map only 64k for now, it's + * plenty enough we don't claim since this precise memory + * range may already be claimed by the malloc pool. + */ + prom_map (birec, birec, 0x10000); + DEBUG_F("birec at %p\n", birec); + DEBUG_SLEEP; + + birec->tag = BI_FIRST; + birec->size = sizeof(struct bi_record); + birec = (struct bi_record *)((ulong)birec + birec->size); + + birec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)birec->data, "yaboot"); + birec->size = sizeof(struct bi_record) + strlen("yaboot") + 1; + birec = (struct bi_record *)((ulong)birec + birec->size); + + birec->tag = BI_MACHTYPE; + birec->data[0] = _machine; + birec->size = sizeof(struct bi_record) + sizeof(ulong); + birec = (struct bi_record *)((ulong)birec + birec->size); + + if (sysmap_base) { + birec->tag = BI_SYSMAP; + birec->data[0] = (ulong)sysmap_base; + birec->data[1] = sysmap_size; + birec->size = sizeof(struct bi_record) + sizeof(ulong)*2; + birec = (struct bi_record *)((ulong)birec + birec->size); + } + birec->tag = BI_LAST; + birec->size = sizeof(struct bi_record); + birec = (struct bi_record *)((ulong)birec + birec->size); + } + + /* compute the kernel's entry point. */ + kernel_entry = loadinfo.base + loadinfo.entry - loadinfo.load_loc; + + DEBUG_F("Kernel entry point = %p\n", kernel_entry); + DEBUG_F("kernel: arg1 = %p,\n" + " arg2 = 0x%08lx,\n" + " prom = %p,\n" + " arg4 = %d,\n" + " arg5 = %d\n\n", + initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0); + + DEBUG_F("Entering kernel...\n"); + + /* call the kernel with our stack. */ + kernel_entry(initrd_base + loadinfo.load_loc, initrd_size, prom, 0, 0); + continue; + next: + ; /* do nothing */ + } +} + +static int +load_elf32(struct boot_file_t *file, loadinfo_t *loadinfo) +{ + int i; + Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr); + Elf32_Phdr *p, *ph; + int size = sizeof(Elf32_Ehdr) - sizeof(Elf_Ident); + unsigned long loadaddr; + + /* Read the rest of the Elf header... */ + if ((*(file->fs->read))(file, size, &e->e_version) < size) { + prom_printf("\nCan't read Elf32 image header\n"); + goto bail; + } + + DEBUG_F("Elf32 header:\n"); + DEBUG_F(" e.e_type = %d\n", (int)e->e_type); + DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine); + DEBUG_F(" e.e_version = %d\n", (int)e->e_version); + DEBUG_F(" e.e_entry = 0x%08x\n", (int)e->e_entry); + DEBUG_F(" e.e_phoff = 0x%08x\n", (int)e->e_phoff); + DEBUG_F(" e.e_shoff = 0x%08x\n", (int)e->e_shoff); + DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags); + DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize); + DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize); + DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum); + + loadinfo->entry = e->e_entry; + + if (e->e_phnum > MAX_HEADERS) { + prom_printf ("Can only load kernels with one program header\n"); + goto bail; + } + + ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * e->e_phnum); + if (!ph) { + prom_printf ("Malloc error\n"); + goto bail; + } + + /* Now, we read the section header */ + if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) { + prom_printf ("seek error\n"); + goto bail; + } + if ((*(file->fs->read))(file, sizeof(Elf32_Phdr) * e->e_phnum, ph) != + sizeof(Elf32_Phdr) * e->e_phnum) { + prom_printf ("read error\n"); + goto bail; + } + + /* Scan through the program header + * HACK: We must return the _memory size of the kernel image, not the + * file size (because we have to leave room before other boot + * infos. This code works as a side effect of the fact that + * we have one section and vaddr == p_paddr + */ + loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0; + p = ph; + for (i = 0; i < e->e_phnum; ++i, ++p) { + if (p->p_type != PT_LOAD || p->p_offset == 0) + continue; + if (loadinfo->memsize == 0) { + loadinfo->offset = p->p_offset; + loadinfo->memsize = p->p_memsz; + loadinfo->filesize = p->p_filesz; + loadinfo->load_loc = p->p_vaddr; + } else { + loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */ + loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset; + } + } + + if (loadinfo->memsize == 0) { + prom_printf("Can't find a loadable segment !\n"); + goto bail; + } + + /* leave some room (1Mb) for boot infos */ + loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000; + /* Claim OF memory */ + DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize); + + /* Determine whether we are trying to boot a vmlinux or some + * other binary image (eg, zImage). We load vmlinux's at + * KERNELADDR and all other binaries at their e_entry value. + */ + if (e->e_entry == KERNEL_LINK_ADDR_PPC32) { + flat_vmlinux = 1; + loadaddr = KERNELADDR; + } else { + flat_vmlinux = 0; + loadaddr = loadinfo->load_loc; + } + + loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0); + if (loadinfo->base == (void *)-1) { + prom_printf("Claim error, can't allocate kernel memory\n"); + goto bail; + } + + DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n", + loadinfo->base, loadinfo->memsize); + DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n", + loadaddr, loadinfo->memsize); + + /* Load the program segments... */ + p = ph; + for (i = 0; i < e->e_phnum; ++i, ++p) { + unsigned long offset; + if (p->p_type != PT_LOAD || p->p_offset == 0) + continue; + + /* Now, we skip to the image itself */ + if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) { + prom_printf ("Seek error\n"); + prom_release(loadinfo->base, loadinfo->memsize); + goto bail; + } + offset = p->p_vaddr - loadinfo->load_loc; + if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) { + prom_printf ("Read failed\n"); + prom_release(loadinfo->base, loadinfo->memsize); + goto bail; + } + } + + free(ph); + + /* Return success at loading the Elf32 kernel */ + return 1; + +bail: + if (ph) + free(ph); + return 0; +} + +static int +load_elf64(struct boot_file_t *file, loadinfo_t *loadinfo) +{ + int i; + Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr); + Elf64_Phdr *p, *ph; + int size = sizeof(Elf64_Ehdr) - sizeof(Elf_Ident); + unsigned long loadaddr; + + /* Read the rest of the Elf header... */ + if ((*(file->fs->read))(file, size, &e->e_version) < size) { + prom_printf("\nCan't read Elf64 image header\n"); + goto bail; + } + + DEBUG_F("Elf64 header:\n"); + DEBUG_F(" e.e_type = %d\n", (int)e->e_type); + DEBUG_F(" e.e_machine = %d\n", (int)e->e_machine); + DEBUG_F(" e.e_version = %d\n", (int)e->e_version); + DEBUG_F(" e.e_entry = 0x%016lx\n", (long)e->e_entry); + DEBUG_F(" e.e_phoff = 0x%016lx\n", (long)e->e_phoff); + DEBUG_F(" e.e_shoff = 0x%016lx\n", (long)e->e_shoff); + DEBUG_F(" e.e_flags = %d\n", (int)e->e_flags); + DEBUG_F(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize); + DEBUG_F(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize); + DEBUG_F(" e.e_phnum = %d\n", (int)e->e_phnum); + + loadinfo->entry = e->e_entry; + + if (e->e_phnum > MAX_HEADERS) { + prom_printf ("Can only load kernels with one program header\n"); + goto bail; + } + + ph = (Elf64_Phdr *)malloc(sizeof(Elf64_Phdr) * e->e_phnum); + if (!ph) { + prom_printf ("Malloc error\n"); + goto bail; + } + + /* Now, we read the section header */ + if ((*(file->fs->seek))(file, e->e_phoff) != FILE_ERR_OK) { + prom_printf ("Seek error\n"); + goto bail; + } + if ((*(file->fs->read))(file, sizeof(Elf64_Phdr) * e->e_phnum, ph) != + sizeof(Elf64_Phdr) * e->e_phnum) { + prom_printf ("Read error\n"); + goto bail; + } + + /* Scan through the program header + * HACK: We must return the _memory size of the kernel image, not the + * file size (because we have to leave room before other boot + * infos. This code works as a side effect of the fact that + * we have one section and vaddr == p_paddr + */ + loadinfo->memsize = loadinfo->filesize = loadinfo->offset = 0; + p = ph; + for (i = 0; i < e->e_phnum; ++i, ++p) { + if (p->p_type != PT_LOAD || p->p_offset == 0) + continue; + if (loadinfo->memsize == 0) { + loadinfo->offset = p->p_offset; + loadinfo->memsize = p->p_memsz; + loadinfo->filesize = p->p_filesz; + loadinfo->load_loc = p->p_vaddr; + } else { + loadinfo->memsize = p->p_offset + p->p_memsz - loadinfo->offset; /* XXX Bogus */ + loadinfo->filesize = p->p_offset + p->p_filesz - loadinfo->offset; + } + } + + if (loadinfo->memsize == 0) { + prom_printf("Can't find a loadable segment !\n"); + goto bail; + } + + /* leave some room (1Mb) for boot infos */ + loadinfo->memsize = _ALIGN(loadinfo->memsize,(1<<20)) + 0x100000; + /* Claim OF memory */ + DEBUG_F("Before prom_claim, mem_sz: 0x%08lx\n", loadinfo->memsize); + + /* Determine whether we are trying to boot a vmlinux or some + * other binary image (eg, zImage). We load vmlinux's at + * KERNELADDR and all other binaries at their e_entry value. + */ + if (e->e_entry == KERNEL_LINK_ADDR_PPC64) { + flat_vmlinux = 1; + loadaddr = KERNELADDR; + } else { + flat_vmlinux = 0; + loadaddr = e->e_entry; + } + + loadinfo->base = prom_claim_chunk((void *)loadaddr, loadinfo->memsize, 0); + if (loadinfo->base == (void *)-1) { + prom_printf("Claim error, can't allocate kernel memory\n"); + goto bail; + } + + DEBUG_F("After ELF parsing, load base: %p, mem_sz: 0x%08lx\n", + loadinfo->base, loadinfo->memsize); + DEBUG_F(" wanted load base: 0x%08lx, mem_sz: 0x%08lx\n", + loadaddr, loadinfo->memsize); + + /* Load the program segments... */ + p = ph; + for (i = 0; i < e->e_phnum; ++i, ++p) { + unsigned long offset; + if (p->p_type != PT_LOAD || p->p_offset == 0) + continue; + + /* Now, we skip to the image itself */ + if ((*(file->fs->seek))(file, p->p_offset) != FILE_ERR_OK) { + prom_printf ("Seek error\n"); + prom_release(loadinfo->base, loadinfo->memsize); + goto bail; + } + offset = p->p_vaddr - loadinfo->load_loc; + if ((*(file->fs->read))(file, p->p_filesz, loadinfo->base+offset) != p->p_filesz) { + prom_printf ("Read failed\n"); + prom_release(loadinfo->base, loadinfo->memsize); + goto bail; + } + } + + free(ph); + + /* Return success at loading the Elf64 kernel */ + return 1; + +bail: + if (ph) + free(ph); + return 0; +} + +static int +is_elf32(loadinfo_t *loadinfo) +{ + Elf32_Ehdr *e = &(loadinfo->elf.elf32hdr); + + return (e->e_ident[EI_MAG0] == ELFMAG0 && + e->e_ident[EI_MAG1] == ELFMAG1 && + e->e_ident[EI_MAG2] == ELFMAG2 && + e->e_ident[EI_MAG3] == ELFMAG3 && + e->e_ident[EI_CLASS] == ELFCLASS32 && + e->e_ident[EI_DATA] == ELFDATA2MSB && + e->e_type == ET_EXEC && + e->e_machine == EM_PPC); +} + +static int +is_elf64(loadinfo_t *loadinfo) +{ + Elf64_Ehdr *e = &(loadinfo->elf.elf64hdr); + + return (e->e_ident[EI_MAG0] == ELFMAG0 && + e->e_ident[EI_MAG1] == ELFMAG1 && + e->e_ident[EI_MAG2] == ELFMAG2 && + e->e_ident[EI_MAG3] == ELFMAG3 && + e->e_ident[EI_CLASS] == ELFCLASS64 && + e->e_ident[EI_DATA] == ELFDATA2MSB && + e->e_type == ET_EXEC && + e->e_machine == EM_PPC64); +} + +static void +setup_display(void) +{ +#ifdef CONFIG_SET_COLORMAP + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0x55, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + int i, result; + prom_handle scrn = PROM_INVALID_HANDLE; + + /* Try Apple's mac-boot screen ihandle */ + result = (int)call_prom_return("interpret", 1, 2, + "\" _screen-ihandle\" $find if execute else 0 then", &scrn); + DEBUG_F("Trying to get screen ihandle, result: %d, scrn: %p\n", result, scrn); + + if (scrn == 0 || scrn == PROM_INVALID_HANDLE) { + char type[32]; + /* Hrm... check to see if stdout is a display */ + scrn = call_prom ("instance-to-package", 1, 1, prom_stdout); + DEBUG_F("instance-to-package of stdout is: %p\n", scrn); + if (prom_getprop(scrn, "device_type", type, 32) > 0 && !strncmp(type, "display", 7)) { + DEBUG_F("got it ! stdout is a screen\n"); + scrn = prom_stdout; + } else { + /* Else, we try to open the package */ + scrn = (prom_handle)call_prom( "open", 1, 1, "screen" ); + DEBUG_F("Open screen result: %p\n", scrn); + } + } + + if (scrn == PROM_INVALID_HANDLE) { + prom_printf("No screen device found !\n"); + return; + } + for(i=0;i<16;i++) { + prom_set_color(scrn, i, default_colors[i*3], + default_colors[i*3+1], default_colors[i*3+2]); + } + prom_printf("\x1b[1;37m\x1b[2;40m"); +#ifdef COLOR_TEST + for (i=0;i<16; i++) { + prom_printf("\x1b[%d;%dm\x1b[1;47m%s \x1b[2;40m %s\n", + ansi_color_table[i].index, + ansi_color_table[i].value, + ansi_color_table[i].name, + ansi_color_table[i].name); + prom_printf("\x1b[%d;%dm\x1b[1;37m%s \x1b[2;30m %s\n", + ansi_color_table[i].index, + ansi_color_table[i].value+10, + ansi_color_table[i].name, + ansi_color_table[i].name); + } + prom_printf("\x1b[1;37m\x1b[2;40m"); +#endif /* COLOR_TEST */ + +#if !DEBUG + prom_printf("\xc"); +#endif /* !DEBUG */ + +#endif /* CONFIG_SET_COLORMAP */ +} + +int +yaboot_main(void) +{ + char *ptype; + char *endp; + int conf_given = 0; + char conf_path[1024]; + + if (_machine == _MACH_Pmac) + setup_display(); + + prom_get_chosen("bootargs", bootargs, sizeof(bootargs)); + DEBUG_F("/chosen/bootargs = %s\n", bootargs); + prom_get_chosen("bootpath", bootdevice, BOOTDEVSZ); + DEBUG_F("/chosen/bootpath = %s\n", bootdevice); + prom_get_options("ibm,fw-nbr-reboots",fw_nbr_reboots, FW_NBR_REBOOTSZ); + fw_reboot_cnt = simple_strtol(fw_nbr_reboots,&endp,10); + if (fw_reboot_cnt > 0L) + prom_get_options("boot-last-label", bootlastlabel, BOOTLASTSZ); + + /* If conf= specified on command line, it overrides + Usage: conf=device:partition,/path/to/conffile + Example: On Open Firmware Prompt, type + boot conf=/pci@8000000f8000000/pci@1/pci1014,028C@1/scsi@0/sd@1,0:3,/etc/yaboot.conf */ + + if (!strncmp(bootargs, "conf=", 5)) { + DEBUG_F("Using conf argument in Open Firmware\n"); + char *end = strchr(bootargs,' '); + if (end) + *end = 0; + + strcpy(bootdevice, bootargs + 5); + conf_given = 1; + DEBUG_F("Using conf=%s\n", bootdevice); + + /* Remove conf=xxx from bootargs */ + if (end) + memmove(bootargs, end+1, strlen(end+1)+1); + else + bootargs[0] = 0; + } + if (bootdevice[0] == 0) { + prom_get_options("boot-device", bootdevice, BOOTDEVSZ); + DEBUG_F("boot-device = %s\n", bootdevice); + } + if (bootdevice[0] == 0) { + prom_printf("Couldn't determine boot device\n"); + return -1; + } + + if (bootoncelabel[0] == 0) { + prom_get_options("boot-once", bootoncelabel, + sizeof(bootoncelabel)); + if (bootoncelabel[0] != 0) + DEBUG_F("boot-once: [%s]\n", bootoncelabel); + } + prom_set_options("boot-once", NULL, 0); + + if (!parse_device_path(bootdevice, NULL, -1, "", &boot)) { + prom_printf("%s: Unable to parse\n", bootdevice); + return -1; + } + DEBUG_F("After parse_device_path: dev=%s, part=%d, file=%s\n", + boot.dev, boot.part, boot.file); + + if (!conf_given) { + if (_machine == _MACH_chrp) + boot.file = "/etc/"; + else if (strlen(boot.file)) { + if (!strncmp(boot.file, "\\\\", 2)) + boot.file = "\\\\"; + else { + char *p, *last; + p = last = boot.file; + while(*p) { + if (*p == '\\') + last = p; + p++; + } + if (p) + *(last) = 0; + else + boot.file = ""; + if (strlen(boot.file)) + strcat(boot.file, "\\"); + } + } + strcpy(conf_path, boot.file); + strcat(conf_path, CONFIG_FILE_NAME); + boot.file = conf_path; + DEBUG_F("After path kludgeup: dev=%s, part=%d, file=%s\n", + boot.dev, boot.part, boot.file); + } + + /* + * If we're doing a netboot, first look for one which matches our + * MAC address. + */ + if (prom_get_devtype(boot.dev) == FILE_DEVICE_NET) { + prom_printf("Try to netboot\n"); + useconf = load_my_config_file(&boot); + } + + if (!useconf) + useconf = load_config_file(&boot); + + prom_printf("Welcome to yaboot version " VERSION "\n"); + prom_printf("Enter \"help\" to get some basic usage information\n"); + + /* I am fed up with lusers using the wrong partition type and + mailing me *when* it breaks */ + + if (_machine == _MACH_Pmac) { + char *entry = cfg_get_strg(0, "ptypewarning"); + int warn = 1; + if (entry) + warn = strcmp(entry, + "I_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaks"); + if (warn) { + ptype = get_part_type(boot.dev, boot.part); + if ((ptype != NULL) && (strcmp(ptype, "Apple_Bootstrap"))) + prom_printf("\nWARNING: Bootstrap partition type is wrong: \"%s\"\n" + " type should be: \"Apple_Bootstrap\"\n\n", ptype); + if (ptype) + free(ptype); + } + } + + yaboot_text_ui(); + + prom_printf("Bye.\n"); + return 0; +} + +/* + * Local variables: + * c-file-style: "k&r" + * c-basic-offset: 5 + * End: + */