欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

prom.c

优龙2410linux2.6.8内核源代码
C
第 1 页 / 共 5 页
字号:
/* *  * * Procedures for interfacing to Open Firmware. * * Paul Mackerras	August 1996. * Copyright (C) 1996 Paul Mackerras. *  *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. *    {engebret|bergner}@us.ibm.com  * *      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. */#undef DEBUG_PROM#include <stdarg.h>#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/types.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/stringify.h>#include <linux/delay.h>#include <linux/initrd.h>#include <asm/prom.h>#include <asm/rtas.h>#include <asm/lmb.h>#include <asm/abs_addr.h>#include <asm/page.h>#include <asm/processor.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/system.h>#include <asm/mmu.h>#include <asm/pgtable.h>#include <asm/bitops.h>#include <asm/naca.h>#include <asm/pci.h>#include <asm/iommu.h>#include <asm/bootinfo.h>#include <asm/ppcdebug.h>#include <asm/btext.h>#include <asm/sections.h>#include <asm/machdep.h>#include "open_pic.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 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	(1UL * 1024 * 1024)/* * prom_init() is called very early on, before the kernel text * and data have been mapped to KERNELBASE.  At this point the code * is running at whatever address it has been loaded at, so * references to extern and static variables must be relocated * explicitly.  The procedure reloc_offset() returns the address * we're currently running at minus the address we were linked at. * (Note that strings count as static variables.) * * Because OF may have mapped I/O devices into the area starting at * KERNELBASE, particularly on CHRP machines, we can't safely call * OF once the kernel has been mapped to KERNELBASE.  Therefore all * OF calls should be done within prom_init(), and prom_init() * and all routines called within it must be careful to relocate * references as necessary. * * Note that the bss is cleared *after* prom_init runs, so we have * to make sure that any static or extern variables it accesses * are put in the data segment. */#define PROM_BUG() do {						\        prom_printf("kernel BUG at %s line 0x%x!\n",		\		    RELOC(__FILE__), __LINE__);			\        __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR);	\} while (0)#ifdef DEBUG_PROM#define prom_debug(x...)	prom_printf(x)#else#define prom_debug(x...)#endifstruct pci_reg_property {	struct pci_address addr;	u32 size_hi;	u32 size_lo;};struct isa_reg_property {	u32 space;	u32 address;	u32 size;};struct pci_intr_map {	struct pci_address addr;	u32 dunno;	phandle int_ctrler;	u32 intr;};typedef unsigned long interpret_func(struct device_node *, unsigned long,				     int, int, int);#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */#define FB_MAX	8#endif/* prom structure */struct prom_t prom;char *prom_display_paths[FB_MAX] __initdata = { NULL, };phandle prom_display_nodes[FB_MAX] __initdata;unsigned int prom_num_displays = 0;char *of_stdout_device = NULL;static int iommu_force_on;int ppc64_iommu_off;extern struct rtas_t rtas;extern unsigned long klimit;extern struct lmb lmb;#define MAX_PHB (32 * 6)  /* 32 drawers * 6 PHBs/drawer */struct of_tce_table of_tce_table[MAX_PHB + 1];char *bootpath = NULL;char *bootdevice = NULL;int boot_cpuid = 0;#define MAX_CPU_THREADS 2struct device_node *allnodes = NULL;/* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. */static rwlock_t devtree_lock = RW_LOCK_UNLOCKED;extern unsigned long reloc_offset(void);extern void enter_prom(struct prom_args *args);extern void copy_and_flush(unsigned long dest, unsigned long src,			   unsigned long size, unsigned long offset);unsigned long dev_tree_size;unsigned long _get_PIR(void);#ifdef CONFIG_HMTstruct {	unsigned int pir;	unsigned int threadid;} hmt_thread_data[NR_CPUS];#endif /* CONFIG_HMT */char testString[] = "LINUX\n"; /* * This are used in calls to call_prom.  The 4th and following * arguments to call_prom should be 32-bit values.  64 bit values * are truncated to 32 bits (and fortunately don't get interpreted * as two arguments). */#define ADDR(x)		(u32) ((unsigned long)(x) - offset)/* This is the one and *ONLY* place where we actually call open * firmware from, since we need to make sure we're running in 32b * mode when we do.  We switch back to 64b mode upon return. */#define PROM_ERROR	(-1)static int __init call_prom(const char *service, int nargs, int nret, ...){	int i;	unsigned long offset = reloc_offset();	struct prom_t *_prom = PTRRELOC(&prom);	va_list list;	_prom->args.service = ADDR(service);	_prom->args.nargs = nargs;	_prom->args.nret = nret;	_prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]);	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.rets[i] = 0;	enter_prom(&_prom->args);	return (nret > 0)? _prom->args.rets[0]: 0;}static void __init prom_print(const char *msg){	const char *p, *q;	unsigned long offset = reloc_offset();	struct prom_t *_prom = PTRRELOC(&prom);	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)			break;		++q;		call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2);	}}static void __init prom_print_hex(unsigned long val){	unsigned long offset = reloc_offset();	int i, nibbles = sizeof(val)*2;	char buf[sizeof(val)*2+1];	struct prom_t *_prom = PTRRELOC(&prom);	for (i = nibbles-1;  i >= 0;  i--) {		buf[i] = (val & 0xf) + '0';		if (buf[i] > '9')			buf[i] += ('a'-'0'-10);		val >>= 4;	}	buf[nibbles] = '\0';	call_prom("write", 3, 1, _prom->stdout, buf, nibbles);}static void __init prom_printf(const char *format, ...){	unsigned long offset = reloc_offset();	const char *p, *q, *s;	va_list args;	unsigned long v;	struct prom_t *_prom = PTRRELOC(&prom);	va_start(args, format);	for (p = PTRRELOC(format); *p != 0; p = q) {		for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)			;		if (q > p)			call_prom("write", 3, 1, _prom->stdout, p, q - p);		if (*q == 0)			break;		if (*q == '\n') {			++q;			call_prom("write", 3, 1, _prom->stdout,				  ADDR("\r\n"), 2);			continue;		}		++q;		if (*q == 0)			break;		switch (*q) {		case 's':			++q;			s = va_arg(args, const char *);			prom_print(s);			break;		case 'x':			++q;			v = va_arg(args, unsigned long);			prom_print_hex(v);			break;		}	}}static void __init __attribute__((noreturn)) prom_panic(const char *reason){	unsigned long offset = reloc_offset();	prom_print(PTRRELOC(reason));	/* ToDo: should put up an SRC here */	call_prom("exit", 0, 0);	for (;;)			/* should never get here */		;}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;	}}static int __init prom_getprop(phandle node, const char *pname,			       void *value, size_t valuelen){	unsigned long offset = reloc_offset();	return call_prom("getprop", 4, 1, node, ADDR(pname),			 (u32)(unsigned long) value, (u32) valuelen);}static void __init prom_initialize_naca(void){	phandle node;	char type[64];	unsigned long num_cpus = 0;	unsigned long offset = reloc_offset();	struct prom_t *_prom = PTRRELOC(&prom);	struct naca_struct *_naca = RELOC(naca);	struct systemcfg *_systemcfg = RELOC(systemcfg);	/* NOTE: _naca->debug_switch is already initialized. */	prom_debug("prom_initialize_naca: start...\n");	_naca->pftSize = 0;	/* ilog2 of htab size.  computed below. */	for (node = 0; prom_next_node(&node); ) {		type[0] = 0;		prom_getprop(node, "device_type", type, sizeof(type));		if (!strcmp(type, RELOC("cpu"))) {			num_cpus += 1;			/* We're assuming *all* of the CPUs have the same			 * d-cache and i-cache sizes... -Peter			 */			if ( num_cpus == 1 ) {				u32 size, lsize;				const char *dc, *ic;				if (_systemcfg->platform == PLATFORM_POWERMAC){					dc = "d-cache-block-size";					ic = "i-cache-block-size";				} else {					dc = "d-cache-line-size";					ic = "i-cache-line-size";				}				prom_getprop(node, "d-cache-size",					     &size, sizeof(size));				prom_getprop(node, dc, &lsize, sizeof(lsize));				_systemcfg->dCacheL1Size = size;				_systemcfg->dCacheL1LineSize = lsize;				_naca->dCacheL1LogLineSize = __ilog2(lsize);				_naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;				prom_getprop(node, "i-cache-size",					     &size, sizeof(size));				prom_getprop(node, ic, &lsize, sizeof(lsize));				_systemcfg->iCacheL1Size = size;				_systemcfg->iCacheL1LineSize = lsize;				_naca->iCacheL1LogLineSize = __ilog2(lsize);				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;				if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {					u32 pft_size[2];					prom_getprop(node, "ibm,pft-size",						&pft_size, sizeof(pft_size));				/* pft_size[0] is the NUMA CEC cookie */					_naca->pftSize = pft_size[1];				}			}		} else if (!strcmp(type, RELOC("serial"))) {			phandle isa, pci;			struct isa_reg_property reg;			union pci_range ranges;			if (_systemcfg->platform == PLATFORM_POWERMAC)				continue;			type[0] = 0;			prom_getprop(node, "ibm,aix-loc", type, sizeof(type));			if (strcmp(type, RELOC("S1")))				continue;			prom_getprop(node, "reg", &reg, sizeof(reg));			isa = call_prom("parent", 1, 1, node);			if (!isa)				PROM_BUG();			pci = call_prom("parent", 1, 1, isa);			if (!pci)				PROM_BUG();			prom_getprop(pci, "ranges", &ranges, sizeof(ranges));			if ( _prom->encode_phys_size == 32 )				_naca->serialPortAddr = ranges.pci32.phys+reg.address;			else {				_naca->serialPortAddr = 					((((unsigned long)ranges.pci64.phys_hi) << 32) |					 (ranges.pci64.phys_lo)) + reg.address;			}		}	}	if (_systemcfg->platform == PLATFORM_POWERMAC)		_naca->interrupt_controller = IC_OPEN_PIC;	else {		_naca->interrupt_controller = IC_INVALID;		for (node = 0; prom_next_node(&node); ) {			type[0] = 0;			prom_getprop(node, "name", type, sizeof(type));			if (strcmp(type, RELOC("interrupt-controller")))				continue;			prom_getprop(node, "compatible", type, sizeof(type));			if (strstr(type, RELOC("open-pic")))				_naca->interrupt_controller = IC_OPEN_PIC;			else if (strstr(type, RELOC("ppc-xicp")))				_naca->interrupt_controller = IC_PPC_XIC;			else				prom_printf("prom: failed to recognize"					    " interrupt-controller\n");			break;		}	}	if (_naca->interrupt_controller == IC_INVALID) {		prom_printf("prom: failed to find interrupt-controller\n");		PROM_BUG();	}	/* We gotta have at least 1 cpu... */	if ( (_systemcfg->processorCount = num_cpus) < 1 )		PROM_BUG();	_systemcfg->physicalMemorySize = lmb_phys_mem_size();	if (_systemcfg->platform == PLATFORM_PSERIES ||	    _systemcfg->platform == PLATFORM_POWERMAC) {		unsigned long rnd_mem_size, pteg_count;		/* round mem_size up to next power of 2 */		rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);		if (rnd_mem_size < _systemcfg->physicalMemorySize)			rnd_mem_size <<= 1;		/* # pages / 2 */

⌨️ 快捷键说明

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