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

📄 prom_init.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
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;}/* * Early parsing of the command line passed to the kernel, used for * "mem=x" and the options that affect the iommu */static void __init early_cmdline_parse(void){	struct prom_t *_prom = &RELOC(prom);#ifdef CONFIG_PPC64	const char *opt;#endif	char *p;	int l = 0;	RELOC(prom_cmd_line[0]) = 0;	p = RELOC(prom_cmd_line);	if ((long)_prom->chosen > 0)		l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);#ifdef CONFIG_CMDLINE	if (l <= 0 || p[0] == '\0') /* dbl check */		strlcpy(RELOC(prom_cmd_line),			RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));#endif /* CONFIG_CMDLINE */	prom_printf("command line: %s\n", RELOC(prom_cmd_line));#ifdef CONFIG_PPC64	opt = strstr(RELOC(prom_cmd_line), RELOC("iommu="));	if (opt) {		prom_printf("iommu opt is: %s\n", opt);		opt += 6;		while (*opt && *opt == ' ')			opt++;		if (!strncmp(opt, RELOC("off"), 3))			RELOC(prom_iommu_off) = 1;		else if (!strncmp(opt, RELOC("force"), 5))			RELOC(prom_iommu_force_on) = 1;	}#endif}#ifdef CONFIG_PPC_PSERIES/* * There are two methods for telling firmware what our capabilities are. * Newer machines have an "ibm,client-architecture-support" method on the * root node.  For older machines, we have to call the "process-elf-header" * method in the /packages/elf-loader node, passing it a fake 32-bit * ELF header containing a couple of PT_NOTE sections that contain * structures that contain various information. *//* * New method - extensible architecture description vector. * * Because the description vector contains a mix of byte and word * values, we declare it as an unsigned char array, and use this * macro to put word values in. */#define W(x)	((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \		((x) >> 8) & 0xff, (x) & 0xff/* Option vector bits - generic bits in byte 1 */#define OV_IGNORE		0x80	/* ignore this vector */#define OV_CESSATION_POLICY	0x40	/* halt if unsupported option present*//* Option vector 1: processor architectures supported */#define OV1_PPC_2_00		0x80	/* set if we support PowerPC 2.00 */#define OV1_PPC_2_01		0x40	/* set if we support PowerPC 2.01 */#define OV1_PPC_2_02		0x20	/* set if we support PowerPC 2.02 */#define OV1_PPC_2_03		0x10	/* set if we support PowerPC 2.03 */#define OV1_PPC_2_04		0x08	/* set if we support PowerPC 2.04 */#define OV1_PPC_2_05		0x04	/* set if we support PowerPC 2.05 *//* Option vector 2: Open Firmware options supported */#define OV2_REAL_MODE		0x20	/* set if we want OF in real mode *//* Option vector 3: processor options supported */#define OV3_FP			0x80	/* floating point */#define OV3_VMX			0x40	/* VMX/Altivec */#define OV3_DFP			0x20	/* decimal FP *//* Option vector 5: PAPR/OF options supported */#define OV5_LPAR		0x80	/* logical partitioning supported */#define OV5_SPLPAR		0x40	/* shared-processor LPAR supported *//* ibm,dynamic-reconfiguration-memory property supported */#define OV5_DRCONF_MEMORY	0x20#define OV5_LARGE_PAGES		0x10	/* large pages supported */#define OV5_DONATE_DEDICATE_CPU 0x02	/* donate dedicated CPU support *//* PCIe/MSI support.  Without MSI full PCIe is not supported */#ifdef CONFIG_PCI_MSI#define OV5_MSI			0x01	/* PCIe/MSI support */#else#define OV5_MSI			0x00#endif /* CONFIG_PCI_MSI *//* * The architecture vector has an array of PVR mask/value pairs, * followed by # option vectors - 1, followed by the option vectors. */static unsigned char ibm_architecture_vec[] = {	W(0xfffe0000), W(0x003a0000),	/* POWER5/POWER5+ */	W(0xffff0000), W(0x003e0000),	/* POWER6 */	W(0xffffffff), W(0x0f000002),	/* all 2.05-compliant */	W(0xfffffffe), W(0x0f000001),	/* all 2.04-compliant and earlier */	5 - 1,				/* 5 option vectors */	/* option vector 1: processor architectures supported */	3 - 2,				/* length */	0,				/* don't ignore, don't halt */	OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |	OV1_PPC_2_04 | OV1_PPC_2_05,	/* option vector 2: Open Firmware options supported */	34 - 2,				/* length */	OV2_REAL_MODE,	0, 0,	W(0xffffffff),			/* real_base */	W(0xffffffff),			/* real_size */	W(0xffffffff),			/* virt_base */	W(0xffffffff),			/* virt_size */	W(0xffffffff),			/* load_base */	W(64),				/* 128MB min RMA */	W(0xffffffff),			/* full client load */	0,				/* min RMA percentage of total RAM */	48,				/* max log_2(hash table size) */	/* option vector 3: processor options supported */	3 - 2,				/* length */	0,				/* don't ignore, don't halt */	OV3_FP | OV3_VMX | OV3_DFP,	/* option vector 4: IBM PAPR implementation */	2 - 2,				/* length */	0,				/* don't halt */	/* option vector 5: PAPR/OF options */	3 - 2,				/* length */	0,				/* don't ignore, don't halt */	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |	OV5_DONATE_DEDICATE_CPU | OV5_MSI,};/* Old method - ELF header with PT_NOTE sections */static struct fake_elf {	Elf32_Ehdr	elfhdr;	Elf32_Phdr	phdr[2];	struct chrpnote {		u32	namesz;		u32	descsz;		u32	type;		char	name[8];	/* "PowerPC" */		struct chrpdesc {			u32	real_mode;			u32	real_base;			u32	real_size;			u32	virt_base;			u32	virt_size;			u32	load_base;		} chrpdesc;	} chrpnote;	struct rpanote {		u32	namesz;		u32	descsz;		u32	type;		char	name[24];	/* "IBM,RPA-Client-Config" */		struct rpadesc {			u32	lpar_affinity;			u32	min_rmo_size;			u32	min_rmo_percent;			u32	max_pft_size;			u32	splpar;			u32	min_load;			u32	new_mem_def;			u32	ignore_me;		} rpadesc;	} rpanote;} fake_elf = {	.elfhdr = {		.e_ident = { 0x7f, 'E', 'L', 'F',			     ELFCLASS32, ELFDATA2MSB, EV_CURRENT },		.e_type = ET_EXEC,	/* yeah right */		.e_machine = EM_PPC,		.e_version = EV_CURRENT,		.e_phoff = offsetof(struct fake_elf, phdr),		.e_phentsize = sizeof(Elf32_Phdr),		.e_phnum = 2	},	.phdr = {		[0] = {			.p_type = PT_NOTE,			.p_offset = offsetof(struct fake_elf, chrpnote),			.p_filesz = sizeof(struct chrpnote)		}, [1] = {			.p_type = PT_NOTE,			.p_offset = offsetof(struct fake_elf, rpanote),			.p_filesz = sizeof(struct rpanote)		}	},	.chrpnote = {		.namesz = sizeof("PowerPC"),		.descsz = sizeof(struct chrpdesc),		.type = 0x1275,		.name = "PowerPC",		.chrpdesc = {			.real_mode = ~0U,	/* ~0 means "don't care" */			.real_base = ~0U,			.real_size = ~0U,			.virt_base = ~0U,			.virt_size = ~0U,			.load_base = ~0U		},	},	.rpanote = {		.namesz = sizeof("IBM,RPA-Client-Config"),		.descsz = sizeof(struct rpadesc),		.type = 0x12759999,		.name = "IBM,RPA-Client-Config",		.rpadesc = {			.lpar_affinity = 0,			.min_rmo_size = 64,	/* in megabytes */			.min_rmo_percent = 0,			.max_pft_size = 48,	/* 2^48 bytes max PFT size */			.splpar = 1,			.min_load = ~0U,			.new_mem_def = 0		}	}};static void __init prom_send_capabilities(void){	ihandle elfloader, root;	prom_arg_t ret;	root = call_prom("open", 1, 1, ADDR("/"));	if (root != 0) {		/* try calling the ibm,client-architecture-support method */		if (call_prom_ret("call-method", 3, 2, &ret,				  ADDR("ibm,client-architecture-support"),				  root,				  ADDR(ibm_architecture_vec)) == 0) {			/* the call exists... */			if (ret)				prom_printf("WARNING: ibm,client-architecture"					    "-support call FAILED!\n");			call_prom("close", 1, 0, root);			return;		}		call_prom("close", 1, 0, root);	}	/* no ibm,client-architecture-support call, try the old way */	elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));	if (elfloader == 0) {		prom_printf("couldn't open /packages/elf-loader\n");		return;	}	call_prom("call-method", 3, 1, ADDR("process-elf-header"),			elfloader, ADDR(&fake_elf));	call_prom("close", 1, 0, elfloader);}#endif/* * Memory allocation strategy... our layout is normally: * *  at 14Mb or more we have vmlinux, then a gap and initrd.  In some *  rare cases, initrd might end up being before the kernel though. *  We assume this won't override the final kernel at 0, we have no *  provision to handle that in this version, but it should hopefully *  never happen. * *  alloc_top is set to the top of RMO, eventually shrink down if the *  TCEs overlap * *  alloc_bottom is set to the top of kernel/initrd * *  from there, allocations are done this way : rtas is allocated *  topmost, and the device-tree is allocated from the bottom. We try *  to grow the device-tree allocation as we progress. If we can't, *  then we fail, we don't currently have a facility to restart *  elsewhere, but that shouldn't be necessary. * *  Note that calls to reserve_mem have to be done explicitly, memory *  allocated with either alloc_up or alloc_down isn't automatically *  reserved. *//* * Allocates memory in the RMO upward from the kernel/initrd * * When align is 0, this is a special case, it means to allocate in place * at the current location of alloc_bottom or fail (that is basically * extending the previous allocation). Used for the device-tree flattening */static unsigned long __init alloc_up(unsigned long size, unsigned long align){	unsigned long base = RELOC(alloc_bottom);	unsigned long addr = 0;	if (align)		base = _ALIGN_UP(base, align);	prom_debug("alloc_up(%x, %x)\n", size, align);	if (RELOC(ram_top) == 0)		prom_panic("alloc_up() called with mem not initialized\n");	if (align)		base = _ALIGN_UP(RELOC(alloc_bottom), align);	else		base = RELOC(alloc_bottom);	for(; (base + size) <= RELOC(alloc_top); 	    base = _ALIGN_UP(base + 0x100000, align)) {		prom_debug("    trying: 0x%x\n\r", base);		addr = (unsigned long)prom_claim(base, size, 0);		if (addr != PROM_ERROR && addr != 0)			break;		addr = 0;		if (align == 0)			break;	}	if (addr == 0)		return 0;	RELOC(alloc_bottom) = addr;	prom_debug(" -> %x\n", addr);	prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));	prom_debug("  alloc_top    : %x\n", RELOC(alloc_top));	prom_debug("  alloc_top_hi : %x\n", RELOC(alloc_top_high));	prom_debug("  rmo_top      : %x\n", RELOC(rmo_top));	prom_debug("  ram_top      : %x\n", RELOC(ram_top));	return addr;}/* * Allocates memory downward, either from top of RMO, or if highmem * is set, from the top of RAM.  Note that this one doesn't handle * failures.  It does claim memory if highmem is not set. */static unsigned long __init alloc_down(unsigned long size, unsigned long align,				       int highmem){	unsigned long base, addr = 0;	prom_debug("alloc_down(%x, %x, %s)\n", size, align,		   highmem ? RELOC("(high)") : RELOC("(low)"));	if (RELOC(ram_top) == 0)		prom_panic("alloc_down() called with mem not initialized\n");	if (highmem) {		/* Carve out storage for the TCE table. */		addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align);		if (addr <= RELOC(alloc_bottom))			return 0;		/* Will we bump into the RMO ? If yes, check out that we		 * didn't overlap existing allocations there, if we did,		 * we are dead, we must be the first in town !		 */		if (addr < RELOC(rmo_top)) {			/* Good, we are first */			if (RELOC(alloc_top) == RELOC(rmo_top))				RELOC(alloc_top) = RELOC(rmo_top) = addr;			else				return 0;		}		RELOC(alloc_top_high) = addr;		goto bail;	}	base = _ALIGN_DOWN(RELOC(alloc_top) - size, align);	for (; base > RELOC(alloc_bottom);	     base = _ALIGN_DOWN(base - 0x100000, align))  {		prom_debug("    trying: 0x%x\n\r", base);		addr = (unsigned long)prom_claim(base, size, 0);		if (addr != PROM_ERROR && addr != 0)			break;		addr = 0;	}	if (addr == 0)		return 0;	RELOC(alloc_top) = addr; bail:	prom_debug(" -> %x\n", addr);	prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));	prom_debug("  alloc_top    : %x\n", RELOC(alloc_top));

⌨️ 快捷键说明

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