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

📄 prom_init.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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/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 {	u64	base;	u64	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 prom_iommu_force_on;static int __initdata prom_iommu_off;static unsigned long __initdata prom_tce_alloc_start;static unsigned long __initdata prom_tce_alloc_end;#endif/* Platforms codes are now obsolete in the kernel. Now only used within this * file and ultimately gone too. Feel free to change them if you need, they * are not shared with anything outside of this file anymore */#define PLATFORM_PSERIES	0x0100#define PLATFORM_PSERIES_LPAR	0x0101#define PLATFORM_LPAR		0x0001#define PLATFORM_POWERMAC	0x0400#define PLATFORM_GENERIC	0x0500static int __initdata of_platform;static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];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/* * 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);	/* Do not call exit because it clears the screen on pmac	 * it also causes some sort of double-fault on early pmacs */	if (RELOC(of_platform) == PLATFORM_POWERMAC)		asm("trap\n");	/* 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];}

⌨️ 快捷键说明

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