⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prom_init.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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/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 __initprom_exit(void){	struct prom_args args;	args.service = "exit";	args.nargs = 0;	args.nret = 0;	prom(&args);	for (;;)			/* should never get here */		;}static int __initcall_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, prom_arg_t);	va_end(list);	for (i = 0; i < nret; ++i)		prom_args.args[i + nargs] = 0;	prom(&prom_args);	return prom_args.args[nargs];}static int __initcall_prom_ret(const char *service, int nargs, int nret, prom_arg_t *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, int);	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 __initprom_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, "\r\n", 2);		}	}}static void __initprom_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 __initprom_set_color(ihandle ih, int i, int r, int g, int b){	return call_prom("call-method", 6, 1, "color!", ih, i, b, g, r);}static int __initprom_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;	}}#ifdef CONFIG_POWER4/* * Set up a hash table with a set of entries in it to map the * first 64MB of RAM.  This is used on 64-bit machines since * some of them don't have BATs. */static inline void make_pte(unsigned long htab, unsigned int hsize,			    unsigned int va, unsigned int pa, int mode){	unsigned int *pteg;	unsigned int hash, i, vsid;	vsid = ((va >> 28) * 0x111) << 12;	hash = ((va ^ vsid) >> 5) & 0x7fff80;	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));	for (i = 0; i < 8; ++i, pteg += 4) {		if ((pteg[1] & 1) == 0) {			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;			pteg[3] = pa | mode;			break;		}	}}extern unsigned long _SDR1;extern PTE *Hash;extern unsigned long Hash_size;static void __initprom_alloc_htab(void){	unsigned int hsize;	unsigned long htab;	unsigned int addr;	/*	 * Because of OF bugs we can't use the "claim" client	 * interface to allocate memory for the hash table.	 * This code is only used on 64-bit PPCs, and the only	 * 64-bit PPCs at the moment are RS/6000s, and their	 * OF is based at 0xc00000 (the 12M point), so we just	 * arbitrarily use the 0x800000 - 0xc00000 region for the	 * hash table.	 *  -- paulus.	 */	hsize = 4 << 20;	/* POWER4 has no BATs */	htab = (8 << 20);	call_prom("claim", 3, 1, htab, hsize, 0);	Hash = (void *)(htab + KERNELBASE);	Hash_size = hsize;	_SDR1 = htab + __ilog2(hsize) - 18;	/*	 * Put in PTEs for the first 64MB of RAM	 */	memset((void *)htab, 0, hsize);	for (addr = 0; addr < 0x4000000; addr += 0x1000)		make_pte(htab, hsize, addr + KERNELBASE, addr,			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);#if 0 /* DEBUG stuff mapping the SCC */	make_pte(htab, hsize, 0x80013000, 0x80013000,		 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);#endif}#endif /* CONFIG_POWER4 *//* * 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 __initcheck_display(unsigned long mem){	phandle node;	ihandle ih;	int i, j;	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	};	const unsigned char *clut;	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 (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;	}	for (j=0; j<prom_num_displays; j++) {		path = prom_display_paths[j];		node = prom_display_nodes[j];		prom_print("opening display ");		prom_print(path);		ih = call_prom("open", 1, 1, path);		if (ih == 0 || ih == (ihandle) -1) {			prom_print("... failed\n");			for (i=j+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[j];				j--;			} else				prom_disp_node = 0;			continue;		} else {			prom_print("... ok\n");			call_prom("setprop", 4, 1, node, "linux,opened", 0, 0);			/*			 * Setup a usable color table when the appropriate			 * method is available.			 * Should update this to use set-colors.			 */			clut = default_colors;			for (i = 0; i < 32; i++, clut += 3)				if (prom_set_color(ih, i, clut[0], clut[1],						   clut[2]) != 0)					break;#ifdef CONFIG_LOGO_LINUX_CLUT224			clut = PTRRELOC(logo_linux_clut224.clut);			for (i = 0; i < logo_linux_clut224.clutsize;			     i++, clut += 3)				if (prom_set_color(ih, i + 32, clut[0],						   clut[1], clut[2]) != 0)					break;#endif /* CONFIG_LOGO_LINUX_CLUT224 */		}	}		if (prom_stdout) {		phandle p;		p = call_prom("instance-to-package", 1, 1, prom_stdout);		if (p && p != -1) {			type[0] = 0;			call_prom("getprop", 4, 1, p, "device_type",				  type, sizeof(type));			if (strcmp(type, "display") == 0)				call_prom("setprop", 4, 1, p, "linux,boot-display",					  0, 0);		}	}	return ALIGNUL(mem);}/* This function will enable the early boot text when doing OF booting. This * way, xmon output should work too */static void __initsetup_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 = 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 address\n");			return;		}	}	/* kludge for valkyrie */	if (strcmp(name, "valkyrie") == 0)		address += 0x1000;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -