mirror of
https://github.com/xcat2/xcat-dep.git
synced 2024-11-22 01:21:44 +00:00
3351 lines
95 KiB
Diff
3351 lines
95 KiB
Diff
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: <device>:<siaddr>,<file>,<ciaddr> requires that
|
|
+ * <siaddr> 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<nret; i++) {
|
|
+ void** rp = va_arg(list, void**);
|
|
+ *rp = prom_args.args[i+nargs];
|
|
+ }
|
|
+ } else
|
|
+ result = 0;
|
|
+ va_end(list);
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static void *
|
|
+call_method_1 (char *method, prom_handle h, int nargs, ...)
|
|
+{
|
|
+ va_list list;
|
|
+ int i;
|
|
+ struct prom_args prom_args;
|
|
+
|
|
+ prom_args.service = "call-method";
|
|
+ prom_args.nargs = nargs+2;
|
|
+ prom_args.nret = 2;
|
|
+ prom_args.args[0] = method;
|
|
+ prom_args.args[1] = h;
|
|
+ va_start (list, nargs);
|
|
+ for (i = 0; i < nargs; ++i)
|
|
+ prom_args.args[2+i] = va_arg(list, void *);
|
|
+ va_end(list);
|
|
+ prom_args.args[2+nargs] = 0;
|
|
+ prom_args.args[2+nargs+1] = 0;
|
|
+
|
|
+ prom (&prom_args);
|
|
+
|
|
+ if (prom_args.args[2+nargs] != 0)
|
|
+ {
|
|
+ prom_printf ("method '%s' failed %p\n", method, prom_args.args[2+nargs]);
|
|
+ return 0;
|
|
+ }
|
|
+ return prom_args.args[2+nargs+1];
|
|
+}
|
|
+
|
|
+
|
|
+prom_handle
|
|
+prom_finddevice (char *name)
|
|
+{
|
|
+ return call_prom ("finddevice", 1, 1, name);
|
|
+}
|
|
+
|
|
+prom_handle
|
|
+prom_findpackage(char *path)
|
|
+{
|
|
+ return call_prom ("find-package", 1, 1, path);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_getprop (prom_handle pack, char *name, void *mem, int len)
|
|
+{
|
|
+ return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_getproplen(prom_handle pack, const char *name)
|
|
+{
|
|
+ return (int)call_prom("getproplen", 2, 1, pack, name);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_setprop (prom_handle pack, char *name, void *mem, int len)
|
|
+{
|
|
+ return (int)call_prom ("setprop", 4, 1, pack, name, mem, len);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_get_chosen (char *name, void *mem, int len)
|
|
+{
|
|
+ return prom_getprop (prom_chosen, name, mem, len);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_get_options (char *name, void *mem, int len)
|
|
+{
|
|
+ if (prom_options == (void *)-1)
|
|
+ return -1;
|
|
+ return prom_getprop (prom_options, name, mem, len);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_set_options (char *name, void *mem, int len)
|
|
+{
|
|
+ if (prom_options == (void *)-1)
|
|
+ return -1;
|
|
+ return prom_setprop (prom_options, name, mem, len);
|
|
+}
|
|
+
|
|
+int
|
|
+prom_get_devtype (char *device)
|
|
+{
|
|
+ phandle dev;
|
|
+ int result;
|
|
+ char tmp[64];
|
|
+
|
|
+ if (strstr(device, TOK_ISCSI))
|
|
+ device = strcpy(tmp, "/vdevice/gscsi/disk");
|
|
+
|
|
+ /* Find OF device phandle */
|
|
+ dev = prom_finddevice(device);
|
|
+ if (dev == PROM_INVALID_HANDLE) {
|
|
+ return FILE_ERR_BADDEV;
|
|
+ }
|
|
+
|
|
+ /* Check the kind of device */
|
|
+ result = prom_getprop(dev, "device_type", tmp, 63);
|
|
+ if (result == -1) {
|
|
+ prom_printf("can't get <device_type> 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<return> 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 <return> to boot it.\n\n"
|
|
+ "To boot any other label simply type its name and press <return>.\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:
|
|
+ */
|