// 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. Load more
// 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_workarounds static 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_PPC64 extern int enter_prom(struct prom_args *args, unsigned long entry); #else static 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_PPC64 static 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_PSERIES static bool __prombss prom_radix_disable; static bool __prombss prom_radix_gtse_disable; static bool __prombss prom_xive_disable; #endif #ifdef CONFIG_PPC_SVM static 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_PSERIES static 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 21 static 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;