diff --git a/yaboot/yaboot-fixes.patch b/yaboot/yaboot-fixes.patch new file mode 100644 index 0000000..3d4f45b --- /dev/null +++ b/yaboot/yaboot-fixes.patch @@ -0,0 +1,3350 @@ +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: ++ */ diff --git a/yaboot/yaboot-xcat.spec b/yaboot/yaboot-xcat.spec new file mode 100644 index 0000000..acbce42 --- /dev/null +++ b/yaboot/yaboot-xcat.spec @@ -0,0 +1,38 @@ +%define pkg yaboot-xcat +%define ver 1.3.14 + +Summary: yaboot binary for tftp server +Name: %{pkg} +Version: %{ver} +Release: 1 +Group: System/Administration +License: GPL2 +URL: http://yaboot.ozlabs.org/ +Source: http://yaboot.ozlabs.org/releases/yaboot-1.3.14.tar.gz +Patch: yaboot-fixes.patch +BuildRoot: %{_tmppath}/%{pkg}-buildroot +Prefix: %{_prefix} +BuildArch: noarch + +%description +This is a version of yaboot to facilitate an xCAT management node to boot +ppc nodes. + + +%prep +%{__rm} -rf %{buildroot} +%setup -q -n yaboot-%{ver} +%patch -p1 + + +%build +make + +%install +mkdir -p %{buildroot}/tftpboot/ +cp second/yaboot %{buildroot}/tftpboot/ + +%files +%defattr(-,root,root) +/tftpboot/yaboot +