/*
* 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/string.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/threads.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <asm/sections.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/bootx.h>
#include <asm/system.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
#include <asm/bootinfo.h>
#include <asm/btext.h>
#include <asm/pci-bridge.h>
#include <asm/open_pic.h>
#include <asm/cacheflush.h>
#ifdef CONFIG_LOGO_LINUX_CLUT224
#include <linux/linux_logo.h>
extern const struct linux_logo logo_linux_clut224;
#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 ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
typedef u32 prom_arg_t;
struct prom_args {
const char *service;
int nargs;
int nret;
prom_arg_t 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 int call_prom(const char *service, int nargs, int nret, ...);
static int call_prom_ret(const char *service, int nargs, int nret,
prom_arg_t *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;
ihandle prom_chosen __initdata;
ihandle prom_stdout __initdata;
static char *prom_display_paths[FB_MAX] __initdata;
static phandle prom_display_nodes[FB_MAX] __initdata;
static unsigned int prom_num_displays __initdata;
static ihandle prom_disp_node __initdata;
char *of_stdout_device __initdata;
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;
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 int __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<