patch-2.1.124 linux/arch/ppc/kernel/prom.c
Next file: linux/arch/ppc/kernel/residual.c
Previous file: linux/arch/ppc/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 233
- Date:
Wed Sep 30 10:14:17 1998
- Orig file:
v2.1.123/linux/arch/ppc/kernel/prom.c
- Orig date:
Thu Aug 6 14:06:29 1998
diff -u --recursive --new-file v2.1.123/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
@@ -1,5 +1,5 @@
/*
- * $Id: prom.c,v 1.32 1998/07/28 20:28:46 geert Exp $
+ * $Id: prom.c,v 1.39 1998/09/18 09:14:52 paulus Exp $
*
* Procedures for interfacing to the Open Firmware PROM on
* Power Macintosh computers.
@@ -20,6 +20,8 @@
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/bootx.h>
/*
* Properties whose value is longer than this get excluded from our
@@ -67,8 +69,12 @@
static interpret_func interpret_macio_props;
static interpret_func interpret_root_props;
+#ifndef FB_MAX /* avoid pulling in all of the fb stuff */
+#define FB_MAX 8
+#endif
char *prom_display_paths[FB_MAX] __initdata = { 0, };
unsigned int prom_num_displays = 0;
+char *of_stdout_device = 0;
prom_entry prom = 0;
ihandle prom_chosen = 0, prom_stdout = 0;
@@ -85,19 +91,22 @@
static struct device_node *allnodes = 0;
static void *call_prom(const char *service, int nargs, int nret, ...);
- void prom_print(const char *msg);
static void prom_exit(void);
static unsigned long copy_device_tree(unsigned long, unsigned long);
static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
unsigned long, struct device_node ***);
static unsigned long finish_node(struct device_node *, unsigned long,
interpret_func *);
+static void relocate_nodes(void);
static unsigned long check_display(unsigned long);
static int prom_next_node(phandle *);
extern void enter_rtas(void *);
extern unsigned long reloc_offset(void);
+extern char cmd_line[512]; /* XXX */
+boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */
+
/*
* prom_init() is called very early on, before the kernel text
* and data have been mapped to KERNELBASE. At this point the code
@@ -208,15 +217,44 @@
unsigned long offset = reloc_offset();
int l;
char *p, *d;
-
- /* check if we're prep, return if we are */
- if ( *(unsigned long *)(0) == 0xdeadc0de )
+#ifdef __SMP__
+ if ( RELOC(first_cpu_booted) )
return;
-
+#endif /* __SMP__ */
+
/* check if we're apus, return if we are */
if ( r3 == 0x61707573 )
return;
+ /* If we came here from BootX, clear the screen,
+ * set up some pointers and return. */
+ if (r3 == 0x426f6f58 && pp == NULL) {
+ boot_infos_t *bi = (boot_infos_t *) r4;
+ unsigned int *screen;
+ int nw, ln;
+ unsigned long space;
+
+ /* first clear the screen */
+ for (ln = 0; ln < bi->dispDeviceRect[3]; ++ln) {
+ screen = (unsigned int *) (bi->dispDeviceBase
+ + ln * bi->dispDeviceRowBytes);
+ nw = bi->dispDeviceRect[2] * bi->dispDeviceDepth / 32;
+ for (; nw > 0; --nw)
+ *screen++ = 0;
+ }
+
+ RELOC(boot_infos) = PTRUNRELOC(bi);
+ space = bi->deviceTreeOffset + bi->deviceTreeSize;
+ if (bi->ramDisk)
+ space = bi->ramDisk + bi->ramDiskSize;
+ RELOC(klimit) = PTRUNRELOC((char *) bi + space);
+ return;
+ }
+
+ /* check if we're prep, return if we are */
+ if ( *(unsigned long *)(0) == 0xdeadc0de )
+ return;
+
/* First get a handle for the stdout device */
RELOC(prom) = pp;
RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,
@@ -228,9 +266,16 @@
sizeof(prom_stdout)) <= 0)
prom_exit();
- /* Get the boot device and translate it to a full OF pathname. */
+ /* Get the full OF pathname of the stdout device */
mem = (unsigned long) RELOC(klimit) + offset;
p = (char *) mem;
+ memset(p, 0, 256);
+ call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255);
+ RELOC(of_stdout_device) = PTRUNRELOC(p);
+ mem += strlen(p) + 1;
+
+ /* Get the boot device and translate it to a full OF pathname. */
+ p = (char *) mem;
l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
RELOC("bootpath"), p, 1<<20);
if (l > 0) {
@@ -303,8 +348,9 @@
{
phandle node;
ihandle ih;
+ int i;
unsigned long offset = reloc_offset();
- char type[16], name[16], *path;
+ char type[16], *path;
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
@@ -323,20 +369,23 @@
ih = call_prom(RELOC("open"), 1, 1, path);
if (ih == 0 || ih == (ihandle) -1) {
prom_print(RELOC("... failed\n"));
- /* platinum kludge. platinum is a valid display,
- * but not handled by OF. Make sure prom_num_display
- * is incremented anyway
- */
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
- name, sizeof(name));
- if (strncmp(name, RELOC("platinum"), 8))
- continue;
- } else {
- prom_print(RELOC("... ok\n"));
+ continue;
}
+ prom_print(RELOC("... ok\n"));
+
+ /*
+ * If this display is the device that OF is using for stdout,
+ * move it to the front of the list.
+ */
mem += strlen(path) + 1;
- RELOC(prom_display_paths[RELOC(prom_num_displays)++])
- = PTRUNRELOC(path);
+ i = RELOC(prom_num_displays)++;
+ if (RELOC(of_stdout_device) != 0 && i > 0
+ && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {
+ for (; i > 0; --i)
+ RELOC(prom_display_paths[i])
+ = RELOC(prom_display_paths[i-1]);
+ }
+ RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
if (RELOC(prom_num_displays) >= FB_MAX)
break;
}
@@ -478,6 +527,8 @@
{
unsigned long mem = (unsigned long) klimit;
+ if (boot_infos)
+ relocate_nodes();
mem = finish_node(allnodes, mem, NULL);
printk(KERN_INFO "device tree used %lu bytes\n",
mem - (unsigned long) allnodes);
@@ -517,10 +568,56 @@
else
ifunc = NULL;
+ /* if we were booted from BootX, convert the full name */
+ if (boot_infos
+ && strncmp(np->full_name, "Devices:device-tree", 19) == 0) {
+ if (np->full_name[19] == 0) {
+ strcpy(np->full_name, "/");
+ } else if (np->full_name[19] == ':') {
+ char *p = np->full_name + 19;
+ np->full_name = p;
+ for (; *p; ++p)
+ if (*p == ':')
+ *p = '/';
+ }
+ }
+
for (child = np->child; child != NULL; child = child->sibling)
mem_start = finish_node(child, mem_start, ifunc);
return mem_start;
+}
+
+/*
+ * When BootX makes a copy of the device tree from the MacOS
+ * Name Registry, it is in the format we use but all of the pointers
+ * are offsets from the start of the tree.
+ * This procedure updates the pointers.
+ */
+__openfirmware
+static void relocate_nodes(void)
+{
+ unsigned long base;
+ struct device_node *np;
+ struct property *pp;
+
+#define ADDBASE(x) (x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0)
+
+ base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset;
+ allnodes = (struct device_node *)(base + 4);
+ for (np = allnodes; np != 0; np = np->allnext) {
+ ADDBASE(np->full_name);
+ ADDBASE(np->properties);
+ ADDBASE(np->parent);
+ ADDBASE(np->child);
+ ADDBASE(np->sibling);
+ ADDBASE(np->allnext);
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ ADDBASE(pp->name);
+ ADDBASE(pp->value);
+ ADDBASE(pp->next);
+ }
+ }
}
__openfirmware
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov