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

📄 prom_init.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Procedures for interfacing to Open Firmware. * * Paul Mackerras	August 1996. * Copyright (C) 1996-2005 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/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 <linux/bitops.h>#include <asm/prom.h>#include <asm/rtas.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/pci.h>#include <asm/iommu.h>#include <asm/btext.h>#include <asm/sections.h>#include <asm/machdep.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)/* * Eventually bump that one up */#define DEVTREE_CHUNK_SIZE	0x100000/* * This is the size of the local memory reserve map that gets copied * into the boot params passed to the kernel. That size is totally * flexible as the kernel just reads the list until it encounters an * entry with size 0, so it can be changed without breaking binary * compatibility */#define MEM_RESERVE_MAP_SIZE	8/* * 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. * On ppc32 we compile with -mrelocatable, which means that references * to extern and static variables get relocated automatically. * On ppc64 we have to relocate the references explicitly with * RELOC.  (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 must be done within prom_init(). * * ADDR is used in calls to call_prom.  The 4th and following * arguments to call_prom should be 32-bit values. * On ppc64, 64 bit values are truncated to 32 bits (and * fortunately don't get interpreted as two arguments). */#ifdef CONFIG_PPC64#define RELOC(x)        (*PTRRELOC(&(x)))#define ADDR(x)		(u32) add_reloc_offset((unsigned long)(x))#define OF_WORKAROUNDS	0#else#define RELOC(x)	(x)#define ADDR(x)		(u32) (x)#define OF_WORKAROUNDS	of_workaroundsint of_workarounds;#endif#define OF_WA_CLAIM	1	/* do phys/virt claim separately, then map */#define OF_WA_LONGTRAIL	2	/* work around longtrail bugs */#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...)#endiftypedef u32 prom_arg_t;struct prom_args {        u32 service;        u32 nargs;        u32 nret;        prom_arg_t args[10];};struct prom_t {	ihandle root;	phandle chosen;	int cpu;	ihandle stdout;	ihandle mmumap;	ihandle memory;};struct mem_map_entry {	unsigned long	base;	unsigned long	size;};typedef u32 cell_t;extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);#ifdef CONFIG_PPC64extern int enter_prom(struct prom_args *args, unsigned long entry);#elsestatic inline int enter_prom(struct prom_args *args, unsigned long entry){	return ((int (*)(struct prom_args *))entry)(args);}#endifextern void copy_and_flush(unsigned long dest, unsigned long src,			   unsigned long size, unsigned long offset);/* prom structure */static struct prom_t __initdata prom;static unsigned long prom_entry __initdata;#define PROM_SCRATCH_SIZE 256static char __initdata of_stdout_device[256];static char __initdata prom_scratch[PROM_SCRATCH_SIZE];static unsigned long __initdata dt_header_start;static unsigned long __initdata dt_struct_start, dt_struct_end;static unsigned long __initdata dt_string_start, dt_string_end;static unsigned long __initdata prom_initrd_start, prom_initrd_end;#ifdef CONFIG_PPC64static int __initdata iommu_force_on;static int __initdata ppc64_iommu_off;static unsigned long __initdata prom_tce_alloc_start;static unsigned long __initdata prom_tce_alloc_end;#endifstatic int __initdata of_platform;static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];static unsigned long __initdata prom_memory_limit;static unsigned long __initdata alloc_top;static unsigned long __initdata alloc_top_high;static unsigned long __initdata alloc_bottom;static unsigned long __initdata rmo_top;static unsigned long __initdata ram_top;static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];static int __initdata mem_reserve_cnt;static cell_t __initdata regbuf[1024];#define MAX_CPU_THREADS 2/* TO GO */#ifdef CONFIG_HMTstruct {	unsigned int pir;	unsigned int threadid;} hmt_thread_data[NR_CPUS];#endif /* CONFIG_HMT *//* * Error results ... some OF calls will return "-1" on error, some * will return 0, some will return either. To simplify, here are * macros to use with any ihandle or phandle return value to check if * it is valid */#define PROM_ERROR		(-1u)#define PHANDLE_VALID(p)	((p) != 0 && (p) != PROM_ERROR)#define IHANDLE_VALID(i)	((i) != 0 && (i) != PROM_ERROR)/* This is the one and *ONLY* place where we actually call open * firmware. */static int __init call_prom(const char *service, int nargs, int nret, ...){	int i;	struct prom_args args;	va_list list;	args.service = ADDR(service);	args.nargs = nargs;	args.nret = nret;	va_start(list, nret);	for (i = 0; i < nargs; i++)		args.args[i] = va_arg(list, prom_arg_t);	va_end(list);	for (i = 0; i < nret; i++)		args.args[nargs+i] = 0;	if (enter_prom(&args, RELOC(prom_entry)) < 0)		return PROM_ERROR;	return (nret > 0) ? args.args[nargs] : 0;}static int __init call_prom_ret(const char *service, int nargs, int nret,				prom_arg_t *rets, ...){	int i;	struct prom_args args;	va_list list;	args.service = ADDR(service);	args.nargs = nargs;	args.nret = nret;	va_start(list, rets);	for (i = 0; i < nargs; i++)		args.args[i] = va_arg(list, prom_arg_t);	va_end(list);	for (i = 0; i < nret; i++)		args.args[nargs+i] = 0;	if (enter_prom(&args, RELOC(prom_entry)) < 0)		return PROM_ERROR;	if (rets != NULL)		for (i = 1; i < nret; ++i)			rets[i-1] = args.args[nargs+i];	return (nret > 0) ? args.args[nargs] : 0;}static void __init prom_print(const char *msg){	const char *p, *q;	struct prom_t *_prom = &RELOC(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){	int i, nibbles = sizeof(val)*2;	char buf[sizeof(val)*2+1];	struct prom_t *_prom = &RELOC(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, ...){	const char *p, *q, *s;	va_list args;	unsigned long v;	struct prom_t *_prom = &RELOC(prom);	va_start(args, format);#ifdef CONFIG_PPC64	format = PTRRELOC(format);#endif	for (p = 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 unsigned int __init prom_claim(unsigned long virt, unsigned long size,				unsigned long align){	struct prom_t *_prom = &RELOC(prom);	if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) {		/*		 * Old OF requires we claim physical and virtual separately		 * and then map explicitly (assuming virtual mode)		 */		int ret;		prom_arg_t result;		ret = call_prom_ret("call-method", 5, 2, &result,				    ADDR("claim"), _prom->memory,				    align, size, virt);		if (ret != 0 || result == -1)			return -1;		ret = call_prom_ret("call-method", 5, 2, &result,				    ADDR("claim"), _prom->mmumap,				    align, size, virt);		if (ret != 0) {			call_prom("call-method", 4, 1, ADDR("release"),				  _prom->memory, size, virt);			return -1;		}		/* the 0x12 is M (coherence) + PP == read/write */		call_prom("call-method", 6, 1,			  ADDR("map"), _prom->mmumap, 0x12, size, virt, virt);		return virt;	}	return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,			 (prom_arg_t)align);}static void __init __attribute__((noreturn)) prom_panic(const char *reason){#ifdef CONFIG_PPC64	reason = PTRRELOC(reason);#endif	prom_print(reason);	/* ToDo: should put up an SRC here on p/iSeries */	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 inline prom_getprop(phandle node, const char *pname,			       void *value, size_t valuelen){	return call_prom("getprop", 4, 1, node, ADDR(pname),			 (u32)(unsigned long) value, (u32) valuelen);}static int inline prom_getproplen(phandle node, const char *pname){	return call_prom("getproplen", 2, 1, node, ADDR(pname));}static void add_string(char **str, const char *q){	char *p = *str;	while (*q)		*p++ = *q++;	*p++ = ' ';	*str = p;}static char *tohex(unsigned int x){	static char digits[] = "0123456789abcdef";	static char result[9];	int i;	result[8] = 0;	i = 8;	do {		--i;		result[i] = digits[x & 0xf];		x >>= 4;	} while (x != 0 && i > 0);	return &result[i];}static int __init prom_setprop(phandle node, const char *nodename,			       const char *pname, void *value, size_t valuelen){	char cmd[256], *p;	if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL))		return call_prom("setprop", 4, 1, node, ADDR(pname),				 (u32)(unsigned long) value, (u32) valuelen);	/* gah... setprop doesn't work on longtrail, have to use interpret */	p = cmd;	add_string(&p, "dev");	add_string(&p, nodename);	add_string(&p, tohex((u32)(unsigned long) value));	add_string(&p, tohex(valuelen));	add_string(&p, tohex(ADDR(pname)));	add_string(&p, tohex(strlen(RELOC(pname))));	add_string(&p, "property");	*p = 0;	return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);}/* We can't use the standard versions because of RELOC headaches. */#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \			 || ('a' <= (c) && (c) <= 'f') \			 || ('A' <= (c) && (c) <= 'F'))#define isdigit(c)	('0' <= (c) && (c) <= '9')#define islower(c)	('a' <= (c) && (c) <= 'z')#define toupper(c)	(islower(c) ? ((c) - 'a' + 'A') : (c))unsigned long prom_strtoul(const char *cp, const char **endp){	unsigned long result = 0, base = 10, value;	if (*cp == '0') {		base = 8;		cp++;		if (toupper(*cp) == 'X') {			cp++;			base = 16;		}	}	while (isxdigit(*cp) &&	       (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {		result = result * base + value;		cp++;	}	if (endp)		*endp = cp;	return result;}unsigned long prom_memparse(const char *ptr, const char **retptr){	unsigned long ret = prom_strtoul(ptr, retptr);	int shift = 0;	/*	 * We can't use a switch here because GCC *may* generate a	 * jump table which won't work, because we're not running at	 * the address we're linked at.	 */	if ('G' == **retptr || 'g' == **retptr)		shift = 30;	if ('M' == **retptr || 'm' == **retptr)		shift = 20;	if ('K' == **retptr || 'k' == **retptr)		shift = 10;	if (shift) {		ret <<= shift;		(*retptr)++;	}	return ret;}/*

⌨️ 快捷键说明

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