prom_init.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:23k
- /*
- * Procedures for interfacing to the Open Firmware PROM on
- * Power Macintosh computers.
- *
- * In particular, we are interested in the device tree
- * and in using some of its services (exit, write to stdout).
- *
- * Paul Mackerras August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
- /*
- * Note that prom_init() and anything called from prom_init()
- * may be running at an address that is different from the address
- * that it was linked at. References to static data items are
- * handled by compiling this file with -mrelocatable-lib.
- */
- #include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <asm/prom.h>
- #include <asm/io.h>
- #include <asm/bootx.h>
- #include <asm/btext.h>
- #include <asm/mmu.h>
- #include <asm/pgtable.h>
- #ifdef CONFIG_FB
- #include <asm/linux_logo.h>
- #endif
- /*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree. This way we don't waste space storing
- * things like "driver,AAPL,MacOS,PowerPC" properties. But this value
- * does need to be big enough to ensure that we don't lose things
- * like the interrupt-map property on a PCI-PCI bridge.
- */
- #define MAX_PROPERTY_LENGTH 4096
- #ifndef FB_MAX /* avoid pulling in all of the fb stuff */
- #define FB_MAX 8
- #endif
- #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
- struct prom_args {
- const char *service;
- int nargs;
- int nret;
- void *args[10];
- };
- struct pci_address {
- unsigned a_hi;
- unsigned a_mid;
- unsigned a_lo;
- };
- struct pci_reg_property {
- struct pci_address addr;
- unsigned size_hi;
- unsigned size_lo;
- };
- struct pci_range {
- struct pci_address addr;
- unsigned phys;
- unsigned size_hi;
- unsigned size_lo;
- };
- struct isa_reg_property {
- unsigned space;
- unsigned address;
- unsigned size;
- };
- struct pci_intr_map {
- struct pci_address addr;
- unsigned dunno;
- phandle int_ctrler;
- unsigned intr;
- };
- static void prom_exit(void);
- static void *call_prom(const char *service, int nargs, int nret, ...);
- static void *call_prom_ret(const char *service, int nargs, int nret,
- void **rets, ...);
- static void prom_print_hex(unsigned int v);
- static int prom_set_color(ihandle ih, int i, int r, int g, int b);
- static int prom_next_node(phandle *nodep);
- static unsigned long check_display(unsigned long mem);
- static void setup_disp_fake_bi(ihandle dp);
- static unsigned long copy_device_tree(unsigned long mem_start,
- unsigned long mem_end);
- static unsigned long inspect_node(phandle node, struct device_node *dad,
- unsigned long mem_start, unsigned long mem_end,
- struct device_node ***allnextpp);
- static void prom_hold_cpus(unsigned long mem);
- static void prom_instantiate_rtas(void);
- static void * early_get_property(unsigned long base, unsigned long node,
- char *prop);
- prom_entry prom __initdata = 0;
- ihandle prom_chosen __initdata = 0;
- ihandle prom_stdout __initdata = 0;
- char *prom_display_paths[FB_MAX] __initdata = { 0, };
- phandle prom_display_nodes[FB_MAX] __initdata;
- unsigned int prom_num_displays __initdata = 0;
- static char *of_stdout_device __initdata = 0;
- static ihandle prom_disp_node __initdata = 0;
- unsigned int rtas_data; /* physical pointer */
- unsigned int rtas_entry; /* physical pointer */
- unsigned int rtas_size;
- unsigned int old_rtas;
- boot_infos_t *boot_infos;
- char *bootpath;
- char *bootdevice;
- struct device_node *allnodes;
- extern char *klimit;
- extern char _stext;
- static void __init
- prom_exit(void)
- {
- struct prom_args args;
- args.service = "exit";
- args.nargs = 0;
- args.nret = 0;
- prom(&args);
- for (;;) /* should never get here */
- ;
- }
- static void * __init
- 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);
- return prom_args.args[nargs];
- }
- static void * __init
- call_prom_ret(const char *service, int nargs, int nret, void **rets, ...)
- {
- 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, rets);
- 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);
- for (i = 1; i < nret; ++i)
- rets[i-1] = prom_args.args[nargs + i];
- return prom_args.args[nargs];
- }
- void __init
- prom_print(const char *msg)
- {
- const char *p, *q;
- if (prom_stdout == 0)
- return;
- for (p = msg; *p != 0; p = q) {
- for (q = p; *q != 0 && *q != 'n'; ++q)
- ;
- if (q > p)
- call_prom("write", 3, 1, prom_stdout, p, q - p);
- if (*q != 0) {
- ++q;
- call_prom("write", 3, 1, prom_stdout, "rn", 2);
- }
- }
- }
- static void __init
- prom_print_hex(unsigned int v)
- {
- char buf[16];
- int i, c;
- for (i = 0; i < 8; ++i) {
- c = (v >> ((7-i)*4)) & 0xf;
- c += (c >= 10)? ('a' - 10): '0';
- buf[i] = c;
- }
- buf[i] = ' ';
- buf[i+1] = 0;
- prom_print(buf);
- }
- static int __init
- prom_set_color(ihandle ih, int i, int r, int g, int b)
- {
- struct prom_args prom_args;
- prom_args.service = "call-method";
- prom_args.nargs = 6;
- prom_args.nret = 1;
- prom_args.args[0] = "color!";
- prom_args.args[1] = ih;
- prom_args.args[2] = (void *) i;
- prom_args.args[3] = (void *) b;
- prom_args.args[4] = (void *) g;
- prom_args.args[5] = (void *) r;
- prom(&prom_args);
- return (int) prom_args.args[6];
- }
- static int __init
- prom_next_node(phandle *nodep)
- {
- phandle node;
- if ((node = *nodep) != 0
- && (*nodep = call_prom("child", 1, 1, node)) != 0)
- return 1;
- if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
- return 1;
- for (;;) {
- if ((node = call_prom("parent", 1, 1, node)) == 0)
- return 0;
- if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
- return 1;
- }
- }
- /*
- * If we have a display that we don't know how to drive,
- * we will want to try to execute OF's open method for it
- * later. However, OF will probably fall over if we do that
- * we've taken over the MMU.
- * So we check whether we will need to open the display,
- * and if so, open it now.
- */
- static unsigned long __init
- check_display(unsigned long mem)
- {
- phandle node;
- ihandle ih;
- int i;
- char type[16], *path;
- static unsigned char default_colors[] = {
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xaa,
- 0x00, 0xaa, 0x00,
- 0x00, 0xaa, 0xaa,
- 0xaa, 0x00, 0x00,
- 0xaa, 0x00, 0xaa,
- 0xaa, 0xaa, 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
- };
- prom_disp_node = 0;
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom("getprop", 4, 1, node, "device_type",
- type, sizeof(type));
- if (strcmp(type, "display") != 0)
- continue;
- /* It seems OF doesn't null-terminate the path :-( */
- path = (char *) mem;
- memset(path, 0, 256);
- if ((int) call_prom("package-to-path", 3, 1,
- node, path, 255) < 0)
- continue;
- /*
- * If this display is the device that OF is using for stdout,
- * move it to the front of the list.
- */
- mem += strlen(path) + 1;
- i = prom_num_displays++;
- if (of_stdout_device != 0 && i > 0
- && strcmp(of_stdout_device, path) == 0) {
- for (; i > 0; --i) {
- prom_display_paths[i]
- = prom_display_paths[i-1];
- prom_display_nodes[i]
- = prom_display_nodes[i-1];
- }
- }
- prom_display_paths[i] = path;
- prom_display_nodes[i] = node;
- if (i == 0)
- prom_disp_node = node;
- if (prom_num_displays >= FB_MAX)
- break;
- }
- try_again:
- /*
- * Open the first display and set its colormap.
- */
- if (prom_num_displays > 0) {
- path = prom_display_paths[0];
- prom_print("opening display ");
- prom_print(path);
- ih = call_prom("open", 1, 1, path);
- if (ih == 0 || ih == (ihandle) -1) {
- prom_print("... failedn");
- for (i=1; i<prom_num_displays; i++) {
- prom_display_paths[i-1] = prom_display_paths[i];
- prom_display_nodes[i-1] = prom_display_nodes[i];
- }
- if (--prom_num_displays > 0)
- prom_disp_node = prom_display_nodes[0];
- else
- prom_disp_node = NULL;
- goto try_again;
- } else {
- prom_print("... okn");
- /*
- * Setup a usable color table when the appropriate
- * method is available.
- * Should update this to use set-colors.
- */
- for (i = 0; i < 32; i++)
- if (prom_set_color(ih, i, default_colors[i*3],
- default_colors[i*3+1],
- default_colors[i*3+2]) != 0)
- break;
- #ifdef CONFIG_FB
- for (i = 0; i < LINUX_LOGO_COLORS; i++)
- if (prom_set_color(ih, i + 32,
- linux_logo_red[i],
- linux_logo_green[i],
- linux_logo_blue[i]) != 0)
- break;
- #endif /* CONFIG_FB */
- }
- }
- return ALIGN(mem);
- }
- /* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
- static void __init
- setup_disp_fake_bi(ihandle dp)
- {
- #ifdef CONFIG_BOOTX_TEXT
- int width = 640, height = 480, depth = 8, pitch;
- unsigned address;
- struct pci_reg_property addrs[8];
- int i, naddrs;
- char name[32];
- char *getprop = "getprop";
- prom_print("Initializing fake screen: ");
- memset(name, 0, sizeof(name));
- call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
- name[sizeof(name)-1] = 0;
- prom_print(name);
- prom_print("n");
- call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
- call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
- call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
- pitch = width * ((depth + 7) / 8);
- call_prom(getprop, 4, 1, dp, "linebytes",
- &pitch, sizeof(pitch));
- if (pitch == 1)
- pitch = 0x1000; /* for strange IBM display */
- address = 0;
- call_prom(getprop, 4, 1, dp, "address",
- &address, sizeof(address));
- if (address == 0) {
- /* look for an assigned address with a size of >= 1MB */
- naddrs = (int) call_prom(getprop, 4, 1, dp,
- "assigned-addresses",
- addrs, sizeof(addrs));
- naddrs /= sizeof(struct pci_reg_property);
- for (i = 0; i < naddrs; ++i) {
- if (addrs[i].size_lo >= (1 << 20)) {
- address = addrs[i].addr.a_lo;
- /* use the BE aperture if possible */
- if (addrs[i].size_lo >= (16 << 20))
- address += (8 << 20);
- break;
- }
- }
- if (address == 0) {
- prom_print("Failed to get addressn");
- return;
- }
- }
- /* kludge for valkyrie */
- if (strcmp(name, "valkyrie") == 0)
- address += 0x1000;
- btext_setup_display(width, height, depth, pitch, address);
- btext_prepare_BAT();
- #endif /* CONFIG_BOOTX_TEXT */
- }
- /*
- * Make a copy of the device tree from the PROM.
- */
- static unsigned long __init
- copy_device_tree(unsigned long mem_start, unsigned long mem_end)
- {
- phandle root;
- unsigned long new_start;
- struct device_node **allnextp;
- root = call_prom("peer", 1, 1, (phandle)0);
- if (root == (phandle)0) {
- prom_print("couldn't get device tree rootn");
- prom_exit();
- }
- allnextp = &allnodes;
- mem_start = ALIGN(mem_start);
- new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
- *allnextp = 0;
- return new_start;
- }
- static unsigned long __init
- inspect_node(phandle node, struct device_node *dad,
- unsigned long mem_start, unsigned long mem_end,
- struct device_node ***allnextpp)
- {
- int l;
- phandle child;
- struct device_node *np;
- struct property *pp, **prev_propp;
- char *prev_name, *namep;
- unsigned char *valp;
- np = (struct device_node *) mem_start;
- mem_start += sizeof(struct device_node);
- memset(np, 0, sizeof(*np));
- np->node = node;
- **allnextpp = PTRUNRELOC(np);
- *allnextpp = &np->allnext;
- if (dad != 0) {
- np->parent = PTRUNRELOC(dad);
- /* we temporarily use the `next' field as `last_child'. */
- if (dad->next == 0)
- dad->child = PTRUNRELOC(np);
- else
- dad->next->sibling = PTRUNRELOC(np);
- dad->next = np;
- }
- /* get and store all properties */
- prev_propp = &np->properties;
- prev_name = "";
- for (;;) {
- pp = (struct property *) mem_start;
- namep = (char *) (pp + 1);
- pp->name = PTRUNRELOC(namep);
- if ((int) call_prom("nextprop", 3, 1, node, prev_name,
- namep) <= 0)
- break;
- mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
- prev_name = namep;
- valp = (unsigned char *) mem_start;
- pp->value = PTRUNRELOC(valp);
- pp->length = (int)
- call_prom("getprop", 4, 1, node, namep,
- valp, mem_end - mem_start);
- if (pp->length < 0)
- continue;
- #ifdef MAX_PROPERTY_LENGTH
- if (pp->length > MAX_PROPERTY_LENGTH)
- continue; /* ignore this property */
- #endif
- mem_start = ALIGN(mem_start + pp->length);
- *prev_propp = PTRUNRELOC(pp);
- prev_propp = &pp->next;
- }
- if (np->node != NULL) {
- /* Add a "linux,phandle" property" */
- pp = (struct property *) mem_start;
- *prev_propp = PTRUNRELOC(pp);
- prev_propp = &pp->next;
- namep = (char *) (pp + 1);
- pp->name = PTRUNRELOC(namep);
- strcpy(namep, "linux,phandle");
- mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
- pp->value = (unsigned char *) PTRUNRELOC(&np->node);
- pp->length = sizeof(np->node);
- }
- *prev_propp = NULL;
- /* get the node's full name */
- l = (int) call_prom("package-to-path", 3, 1, node,
- (char *) mem_start, mem_end - mem_start);
- if (l >= 0) {
- np->full_name = PTRUNRELOC((char *) mem_start);
- *(char *)(mem_start + l) = 0;
- mem_start = ALIGN(mem_start + l + 1);
- }
- /* do all our children */
- child = call_prom("child", 1, 1, node);
- while (child != (void *)0) {
- mem_start = inspect_node(child, np, mem_start, mem_end,
- allnextpp);
- child = call_prom("peer", 1, 1, child);
- }
- return mem_start;
- }
- unsigned long smp_chrp_cpu_nr __initdata = 0;
- /*
- * With CHRP SMP we need to use the OF to start the other
- * processors so we can't wait until smp_boot_cpus (the OF is
- * trashed by then) so we have to put the processors into
- * a holding pattern controlled by the kernel (not OF) before
- * we destroy the OF.
- *
- * This uses a chunk of high memory, puts some holding pattern
- * code there and sends the other processors off to there until
- * smp_boot_cpus tells them to do something. We do that by using
- * physical address 0x0. The holding pattern checks that address
- * until its cpu # is there, when it is that cpu jumps to
- * __secondary_start(). smp_boot_cpus() takes care of setting those
- * values.
- *
- * We also use physical address 0x4 here to tell when a cpu
- * is in its holding pattern code.
- *
- * -- Cort
- *
- * Note that we have to do this if we have more than one CPU,
- * even if this is a UP kernel. Otherwise when we trash OF
- * the other CPUs will start executing some random instructions
- * and crash the system. -- paulus
- */
- static void __init
- prom_hold_cpus(unsigned long mem)
- {
- extern void __secondary_hold(void);
- unsigned long i;
- int cpu;
- phandle node;
- char type[16], *path;
- unsigned int reg;
- /*
- * XXX: hack to make sure we're chrp, assume that if we're
- * chrp we have a device_type property -- Cort
- */
- node = call_prom("finddevice", 1, 1, "/");
- if ((int)call_prom("getprop", 4, 1, node,
- "device_type",type, sizeof(type)) <= 0)
- return;
- /* copy the holding pattern code to someplace safe (0) */
- /* the holding pattern is now within the first 0x100
- bytes of the kernel image -- paulus */
- memcpy((void *)0, &_stext, 0x100);
- flush_icache_range(0, 0x100);
- /* look for cpus */
- *(unsigned long *)(0x0) = 0;
- asm volatile("dcbf 0,%0": : "r" (0) : "memory");
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom("getprop", 4, 1, node, "device_type",
- type, sizeof(type));
- if (strcmp(type, "cpu") != 0)
- continue;
- path = (char *) mem;
- memset(path, 0, 256);
- if ((int) call_prom("package-to-path", 3, 1,
- node, path, 255) < 0)
- continue;
- reg = -1;
- call_prom("getprop", 4, 1, node, "reg", ®, sizeof(reg));
- cpu = smp_chrp_cpu_nr++;
- #ifdef CONFIG_SMP
- smp_hw_index[cpu] = reg;
- #endif /* CONFIG_SMP */
- /* XXX: hack - don't start cpu 0, this cpu -- Cort */
- if (cpu == 0)
- continue;
- prom_print("starting cpu ");
- prom_print(path);
- *(ulong *)(0x4) = 0;
- call_prom("start-cpu", 3, 0, node,
- (char *)__secondary_hold - &_stext, cpu);
- prom_print("...");
- for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
- ;
- if (*(ulong *)(0x4) == cpu)
- prom_print("okn");
- else {
- prom_print("failed: ");
- prom_print_hex(*(ulong *)0x4);
- prom_print("n");
- }
- }
- }
- static void __init
- prom_instantiate_rtas(void)
- {
- ihandle prom_rtas;
- unsigned int i;
- struct prom_args prom_args;
- prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
- if (prom_rtas == (void *) -1)
- return;
- rtas_size = 0;
- call_prom("getprop", 4, 1, prom_rtas,
- "rtas-size", &rtas_size, sizeof(rtas_size));
- prom_print("instantiating rtas");
- if (rtas_size == 0) {
- rtas_data = 0;
- } else {
- /*
- * Ask OF for some space for RTAS.
- * Actually OF has bugs so we just arbitrarily
- * use memory at the 6MB point.
- */
- rtas_data = 6 << 20;
- prom_print(" at ");
- prom_print_hex(rtas_data);
- }
- prom_rtas = call_prom("open", 1, 1, "/rtas");
- prom_print("...");
- prom_args.service = "call-method";
- prom_args.nargs = 3;
- prom_args.nret = 2;
- prom_args.args[0] = "instantiate-rtas";
- prom_args.args[1] = prom_rtas;
- prom_args.args[2] = (void *) rtas_data;
- prom(&prom_args);
- i = 0;
- if (prom_args.args[3] == 0)
- i = (unsigned int)prom_args.args[4];
- rtas_entry = i;
- if ((rtas_entry == -1) || (rtas_entry == 0))
- prom_print(" failedn");
- else
- prom_print(" donen");
- }
- /*
- * We enter here early on, when the Open Firmware prom is still
- * handling exceptions and the MMU hash table for us.
- */
- unsigned long __init
- prom_init(int r3, int r4, prom_entry pp)
- {
- unsigned long mem;
- ihandle prom_mmu;
- unsigned long offset = reloc_offset();
- int i, l;
- char *p, *d;
- unsigned long phys;
- void *result[3];
- /* Default */
- phys = (unsigned long) &_stext;
- /* First get a handle for the stdout device */
- prom = pp;
- prom_chosen = call_prom("finddevice", 1, 1,
- "/chosen");
- if (prom_chosen == (void *)-1)
- prom_exit();
- if ((int) call_prom("getprop", 4, 1, prom_chosen,
- "stdout", &prom_stdout,
- sizeof(prom_stdout)) <= 0)
- prom_exit();
- /* Get the full OF pathname of the stdout device */
- mem = (unsigned long) klimit + offset;
- p = (char *) mem;
- memset(p, 0, 256);
- call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
- of_stdout_device = p;
- mem += strlen(p) + 1;
- /* Get the boot device and translate it to a full OF pathname. */
- p = (char *) mem;
- l = (int) call_prom("getprop", 4, 1, prom_chosen,
- "bootpath", p, 1<<20);
- if (l > 0) {
- p[l] = 0; /* should already be null-terminated */
- bootpath = PTRUNRELOC(p);
- mem += l + 1;
- d = (char *) mem;
- *d = 0;
- call_prom("canon", 3, 1, p, d, 1<<20);
- bootdevice = PTRUNRELOC(d);
- mem = ALIGN(mem + strlen(d) + 1);
- }
- prom_instantiate_rtas();
- mem = check_display(mem);
- prom_print("copying OF device tree...");
- mem = copy_device_tree(mem, mem + (1<<20));
- prom_print("donen");
- prom_hold_cpus(mem);
- klimit = (char *) (mem - offset);
- /* If we are already running at 0xc0000000, we assume we were
- * loaded by an OF bootloader which did set a BAT for us.
- * This breaks OF translate so we force phys to be 0.
- */
- if (offset == 0)
- phys = 0;
- else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
- &prom_mmu, sizeof(prom_mmu)) <= 0) {
- prom_print(" no MMU foundn");
- } else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
- prom_mmu, &_stext, 1) != 0) {
- prom_print(" (translate failed)n");
- } else {
- /* We assume the phys. address size is 3 cells */
- phys = (unsigned long)result[2];
- }
- if (prom_disp_node != 0)
- setup_disp_fake_bi(prom_disp_node);
- /* Use quiesce call to get OF to shut down any devices it's using */
- prom_print("Calling quiesce ...n");
- call_prom("quiesce", 0, 0);
- /* Relocate various pointers which will be used once the
- kernel is running at the address it was linked at. */
- for (i = 0; i < prom_num_displays; ++i)
- prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
- prom_print("returning 0x");
- prom_print_hex(phys);
- prom_print("from prom_initn");
- prom_stdout = 0;
- return phys;
- }
- /*
- * early_get_property is used to access the device tree image prepared
- * by BootX very early on, before the pointers in it have been relocated.
- */
- static void * __init
- early_get_property(unsigned long base, unsigned long node, char *prop)
- {
- struct device_node *np = (struct device_node *)(base + node);
- struct property *pp;
- for (pp = np->properties; pp != 0; pp = pp->next) {
- pp = (struct property *) (base + (unsigned long)pp);
- if (strcmp((char *)((unsigned long)pp->name + base),
- prop) == 0) {
- return (void *)((unsigned long)pp->value + base);
- }
- }
- return 0;
- }
- /* Is boot-info compatible ? */
- #define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION)
- #define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2)
- #define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4)
- void __init
- bootx_init(unsigned long r4, unsigned long phys)
- {
- boot_infos_t *bi = (boot_infos_t *) r4;
- unsigned long space;
- unsigned long ptr, x;
- char *model;
- boot_infos = PTRUNRELOC(bi);
- if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
- bi->logicalDisplayBase = 0;
- #ifdef CONFIG_BOOTX_TEXT
- btext_init(bi);
- /*
- * Test if boot-info is compatible. Done only in config
- * CONFIG_BOOTX_TEXT since there is nothing much we can do
- * with an incompatible version, except display a message
- * and eventually hang the processor...
- *
- * I'll try to keep enough of boot-info compatible in the
- * future to always allow display of this message;
- */
- if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
- btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!nnn");
- btext_flushscreen();
- }
- #endif /* CONFIG_BOOTX_TEXT */
- /* New BootX enters kernel with MMU off, i/os are not allowed
- here. This hack will have been done by the boostrap anyway.
- */
- if (bi->version < 4) {
- /*
- * XXX If this is an iMac, turn off the USB controller.
- */
- model = (char *) early_get_property
- (r4 + bi->deviceTreeOffset, 4, "model");
- if (model
- && (strcmp(model, "iMac,1") == 0
- || strcmp(model, "PowerMac1,1") == 0)) {
- out_le32((unsigned *)0x80880008, 1); /* XXX */
- }
- }
- /* Move klimit to enclose device tree, args, ramdisk, etc... */
- if (bi->version < 5) {
- space = bi->deviceTreeOffset + bi->deviceTreeSize;
- if (bi->ramDisk)
- space = bi->ramDisk + bi->ramDiskSize;
- } else
- space = bi->totalParamsSize;
- klimit = PTRUNRELOC((char *) bi + space);
- /* New BootX will have flushed all TLBs and enters kernel with
- MMU switched OFF, so this should not be useful anymore.
- */
- if (bi->version < 4) {
- /*
- * Touch each page to make sure the PTEs for them
- * are in the hash table - the aim is to try to avoid
- * getting DSI exceptions while copying the kernel image.
- */
- for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
- ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
- x = *(volatile unsigned long *)ptr;
- }
- #ifdef CONFIG_BOOTX_TEXT
- /*
- * Note that after we call btext_prepare_BAT, we can't do
- * prom_draw*, flushscreen or clearscreen until we turn the MMU
- * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
- * to a virtual address.
- */
- btext_prepare_BAT();
- #endif
- }