Ritesh Harjani (IBM)powerpc: Add Power12 architected mode287df873 months agoHistory
3460 lines · 88.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * 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  */ #undef DEBUG_PROM /* we cannot use FORTIFY as it brings in new symbols */#define __NO_FORTIFY #include <linux/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/delay.h>#include <linux/initrd.h>#include <linux/bitops.h>#include <linux/pgtable.h>#include <linux/printk.h>#include <linux/of.h>#include <linux/of_fdt.h>#include <asm/prom.h>#include <asm/rtas.h>#include <asm/page.h>#include <asm/processor.h>#include <asm/interrupt.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/mmu.h>#include <asm/iommu.h>#include <asm/btext.h>#include <asm/sections.h>#include <asm/setup.h>#include <asm/asm-prototypes.h>#include <asm/ultravisor-api.h> #include <linux/linux_logo.h> /* All of prom_init bss lives here */#define __prombss __section(".bss.prominit") /* * 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. * ppc64 objects are always relocatable, we just need to relocate the * TOC. * * 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). */#define ADDR(x)		(u32)(unsigned long)(x) /* * Current Power system firmware caps the PVR list array size at 16 entries * during CAS (Client Architecture Support) negotiation. */#define CAS_MAX_PVR_ENTRIES	16 #ifdef CONFIG_PPC64#define OF_WORKAROUNDS	0#else#define OF_WORKAROUNDS	of_workaroundsstatic int of_workarounds __prombss;#endif #define OF_WA_CLAIM	1	/* do phys/virt claim separately, then map */#define OF_WA_LONGTRAIL	2	/* work around longtrail bugs */ #ifdef DEBUG_PROM#define prom_debug(x...)	prom_printf(x)#else#define prom_debug(x...)	do { } while (0)#endif  typedef u32 prom_arg_t; struct prom_args {        __be32 service;        __be32 nargs;        __be32 nret;        __be32 args[10];}; struct prom_t {	ihandle root;	phandle chosen;	int cpu;	ihandle stdout;	ihandle mmumap;	ihandle memory;}; struct mem_map_entry {	__be64	base;	__be64	size;}; typedef __be32 cell_t; extern void __start(unsigned long r3, unsigned long r4, unsigned long r5,		    unsigned long r6, unsigned long r7, unsigned long r8,		    unsigned long r9); #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);}#endif extern void copy_and_flush(unsigned long dest, unsigned long src,			   unsigned long size, unsigned long offset); /* prom structure */static struct prom_t __prombss prom; static unsigned long __prombss prom_entry; static char __prombss of_stdout_device[256];static char __prombss prom_scratch[256]; static unsigned long __prombss dt_header_start;static unsigned long __prombss dt_struct_start, dt_struct_end;static unsigned long __prombss dt_string_start, dt_string_end; static unsigned long __prombss prom_initrd_start, prom_initrd_end; #ifdef CONFIG_PPC64static int __prombss prom_iommu_force_on;static int __prombss prom_iommu_off;static unsigned long __prombss prom_tce_alloc_start;static unsigned long __prombss prom_tce_alloc_end;#endif #ifdef CONFIG_PPC_PSERIESstatic bool __prombss prom_radix_disable;static bool __prombss prom_radix_gtse_disable;static bool __prombss prom_xive_disable;#endif #ifdef CONFIG_PPC_SVMstatic bool __prombss prom_svm_enable;#endif struct platform_support {	bool hash_mmu;	bool radix_mmu;	bool radix_gtse;	bool xive;}; /* 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	0x0500 static int __prombss of_platform; static char __prombss prom_cmd_line[COMMAND_LINE_SIZE]; static unsigned long __prombss prom_memory_limit; static unsigned long __prombss alloc_top;static unsigned long __prombss alloc_top_high;static unsigned long __prombss alloc_bottom;static unsigned long __prombss rmo_top;static unsigned long __prombss ram_top; static struct mem_map_entry __prombss mem_reserve_map[MEM_RESERVE_MAP_SIZE];static int __prombss mem_reserve_cnt; static cell_t __prombss regbuf[1024]; static bool  __prombss rtas_has_query_cpu_stopped;  /* * 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) /* Copied from lib/string.c and lib/kstrtox.c */ static int __init prom_strcmp(const char *cs, const char *ct){	unsigned char c1, c2; 	while (1) {		c1 = *cs++;		c2 = *ct++;		if (c1 != c2)			return c1 < c2 ? -1 : 1;		if (!c1)			break;	}	return 0;} static ssize_t __init prom_strscpy_pad(char *dest, const char *src, size_t n){	ssize_t rc;	size_t i; 	if (n == 0 || n > INT_MAX)		return -E2BIG; 	// Copy up to n bytes	for (i = 0; i < n && src[i] != '\0'; i++)		dest[i] = src[i]; 	rc = i; 	// If we copied all n then we have run out of space for the nul	if (rc == n) {		// Rewind by one character to ensure nul termination		i--;		rc = -E2BIG;	} 	for (; i < n; i++)		dest[i] = '\0'; 	return rc;} static int __init prom_strncmp(const char *cs, const char *ct, size_t count){	unsigned char c1, c2; 	while (count) {		c1 = *cs++;		c2 = *ct++;		if (c1 != c2)			return c1 < c2 ? -1 : 1;		if (!c1)			break;		count--;	}	return 0;} static size_t __init prom_strlen(const char *s){	const char *sc; 	for (sc = s; *sc != '\0'; ++sc)		/* nothing */;	return sc - s;} static int __init prom_memcmp(const void *cs, const void *ct, size_t count){	const unsigned char *su1, *su2;	int res = 0; 	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)		if ((res = *su1 - *su2) != 0)			break;	return res;} static char __init *prom_strstr(const char *s1, const char *s2){	size_t l1, l2; 	l2 = prom_strlen(s2);	if (!l2)		return (char *)s1;	l1 = prom_strlen(s1);	while (l1 >= l2) {		l1--;		if (!prom_memcmp(s1, s2, l2))			return (char *)s1;		s1++;	}	return NULL;} static size_t __init prom_strlcat(char *dest, const char *src, size_t count){	size_t dsize = prom_strlen(dest);	size_t len = prom_strlen(src);	size_t res = dsize + len; 	/* This would be a bug */	if (dsize >= count)		return count; 	dest += dsize;	count -= dsize;	if (len >= count)		len = count-1;	memcpy(dest, src, len);	dest[len] = 0;	return res; } #ifdef CONFIG_PPC_PSERIESstatic int __init prom_strtobool(const char *s, bool *res){	if (!s)		return -EINVAL; 	switch (s[0]) {	case 'y':	case 'Y':	case '1':		*res = true;		return 0;	case 'n':	case 'N':	case '0':		*res = false;		return 0;	case 'o':	case 'O':		switch (s[1]) {		case 'n':		case 'N':			*res = true;			return 0;		case 'f':		case 'F':			*res = false;			return 0;		default:			break;		}		break;	default:		break;	} 	return -EINVAL;}#endif /* 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 = cpu_to_be32(ADDR(service));	args.nargs = cpu_to_be32(nargs);	args.nret = cpu_to_be32(nret); 	va_start(list, nret);	for (i = 0; i < nargs; i++)		args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));	va_end(list); 	for (i = 0; i < nret; i++)		args.args[nargs+i] = 0; 	if (enter_prom(&args, prom_entry) < 0)		return PROM_ERROR; 	return (nret > 0) ? be32_to_cpu(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 = cpu_to_be32(ADDR(service));	args.nargs = cpu_to_be32(nargs);	args.nret = cpu_to_be32(nret); 	va_start(list, rets);	for (i = 0; i < nargs; i++)		args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));	va_end(list); 	for (i = 0; i < nret; i++)		args.args[nargs+i] = 0; 	if (enter_prom(&args, prom_entry) < 0)		return PROM_ERROR; 	if (rets != NULL)		for (i = 1; i < nret; ++i)			rets[i-1] = be32_to_cpu(args.args[nargs+i]); 	return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;}  static void __init prom_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)			break;		++q;		call_prom("write", 3, 1, prom.stdout, ADDR("\r\n"), 2);	}}  /* * Both prom_print_hex & prom_print_dec takes an unsigned long as input so that * we do not need __udivdi3 or __umoddi3 on 32bits. */static void __init prom_print_hex(unsigned long val){	int i, nibbles = sizeof(val)*2;	char buf[sizeof(val)*2+1]; 	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);} /* max number of decimal digits in an unsigned long */#define UL_DIGITS 21static void __init prom_print_dec(unsigned long val){	int i, size;	char buf[UL_DIGITS+1]; 	for (i = UL_DIGITS-1; i >= 0;  i--) {		buf[i] = (val % 10) + '0';		val = val/10;		if (val == 0)			break;	}	/* shift stuff down */	size = UL_DIGITS - i;

Lines 1–500 of 3460.