// SPDX-License-Identifier: GPL-2.0-only/* * linux/arch/arm/kernel/setup.c * * Copyright (C) 1995-2001 Russell King */#include <linux/efi.h>#include <linux/export.h>#include <linux/kernel.h>#include <linux/stddef.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/utsname.h>#include <linux/initrd.h>#include <linux/console.h>#include <linux/seq_file.h>#include <linux/screen_info.h>#include <linux/of_platform.h>#include <linux/init.h>#include <linux/kexec.h>#include <linux/libfdt.h>#include <linux/of_fdt.h>#include <linux/cpu.h>#include <linux/interrupt.h>#include <linux/smp.h>#include <linux/proc_fs.h>#include <linux/memblock.h>#include <linux/bug.h>#include <linux/compiler.h>#include <linux/sort.h>#include <linux/psci.h> #include <asm/unified.h>#include <asm/cp15.h>#include <asm/cpu.h>#include <asm/cputype.h>#include <asm/efi.h>#include <asm/elf.h>#include <asm/early_ioremap.h>#include <asm/fixmap.h>#include <asm/procinfo.h>#include <asm/psci.h>#include <asm/sections.h>#include <asm/setup.h>#include <asm/smp_plat.h>#include <asm/mach-types.h>#include <asm/cacheflush.h>#include <asm/cachetype.h>#include <asm/tlbflush.h>#include <asm/xen/hypervisor.h> #include <asm/prom.h>#include <asm/mach/arch.h>#include <asm/mach/irq.h>#include <asm/mach/time.h>#include <asm/system_info.h>#include <asm/system_misc.h>#include <asm/traps.h>#include <asm/unwind.h>#include <asm/memblock.h>#include <asm/virt.h>#include <asm/kasan.h> #include "atags.h" #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)char fpe_type[8]; static int __init fpe_setup(char *line){ memcpy(fpe_type, line, 8); return 1;} __setup("fpe=", fpe_setup);#endif extern void init_default_cache_policy(unsigned long);extern void paging_init(const struct machine_desc *desc);extern void early_mm_init(const struct machine_desc *);extern void adjust_lowmem_bounds(void);extern enum reboot_mode reboot_mode;extern void setup_dma_zone(const struct machine_desc *desc); unsigned int processor_id;EXPORT_SYMBOL(processor_id);unsigned int __machine_arch_type __read_mostly;EXPORT_SYMBOL(__machine_arch_type);unsigned int cacheid __read_mostly;EXPORT_SYMBOL(cacheid); unsigned int __atags_pointer __initdata; unsigned int system_rev;EXPORT_SYMBOL(system_rev); const char *system_serial;EXPORT_SYMBOL(system_serial); unsigned int system_serial_low;EXPORT_SYMBOL(system_serial_low); unsigned int system_serial_high;EXPORT_SYMBOL(system_serial_high); unsigned int elf_hwcap __read_mostly;EXPORT_SYMBOL(elf_hwcap); unsigned int elf_hwcap2 __read_mostly;EXPORT_SYMBOL(elf_hwcap2); #ifdef MULTI_CPUstruct processor processor __ro_after_init;#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)struct processor *cpu_vtable[NR_CPUS] = { [0] = &processor,};#endif#endif#ifdef MULTI_TLBstruct cpu_tlb_fns cpu_tlb __ro_after_init;#endif#ifdef MULTI_USERstruct cpu_user_fns cpu_user __ro_after_init;#endif#ifdef MULTI_CACHEstruct cpu_cache_fns cpu_cache __ro_after_init;#endif#ifdef CONFIG_OUTER_CACHEstruct outer_cache_fns outer_cache __ro_after_init;EXPORT_SYMBOL(outer_cache);#endif /* * Cached cpu_architecture() result for use by assembler code. * C code should use the cpu_architecture() function instead of accessing this * variable directly. */int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; struct stack { u32 irq[4]; u32 abt[4]; u32 und[4]; u32 fiq[4];} ____cacheline_aligned; #ifndef CONFIG_CPU_V7Mstatic struct stack stacks[NR_CPUS];#endif char elf_platform[ELF_PLATFORM_SIZE];EXPORT_SYMBOL(elf_platform); static const char *cpu_name;static const char *machine_name;static char __initdata cmd_line[COMMAND_LINE_SIZE];const struct machine_desc *machine_desc __initdata; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };#define ENDIANNESS ((char)endian_test.l) DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); /* * Standard memory resources */static struct resource mem_res[] = { { .name = "Video RAM", .start = 0, .end = 0, .flags = IORESOURCE_MEM }, { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_SYSTEM_RAM }, { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_SYSTEM_RAM }}; #define video_ram mem_res[0]#define kernel_code mem_res[1]#define kernel_data mem_res[2] static struct resource io_res[] = { { .name = "reserved", .start = 0x3bc, .end = 0x3be, .flags = IORESOURCE_IO | IORESOURCE_BUSY }, { .name = "reserved", .start = 0x378, .end = 0x37f, .flags = IORESOURCE_IO | IORESOURCE_BUSY }, { .name = "reserved", .start = 0x278, .end = 0x27f, .flags = IORESOURCE_IO | IORESOURCE_BUSY }}; #define lp0 io_res[0]#define lp1 io_res[1]#define lp2 io_res[2] static const char *proc_arch[] = { "undefined/unknown", "3", "4", "4T", "5", "5T", "5TE", "5TEJ", "6TEJ", "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)",}; #ifdef CONFIG_CPU_V7Mstatic int __get_cpu_architecture(void){ return CPU_ARCH_ARMv7M;}#elsestatic int __get_cpu_architecture(void){ int cpu_arch; if ((read_cpuid_id() & 0x0008f000) == 0) { cpu_arch = CPU_ARCH_UNKNOWN; } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { cpu_arch = (read_cpuid_id() >> 16) & 7; if (cpu_arch) cpu_arch += CPU_ARCH_ARMv3; } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { /* Revised CPUID format. Read the Memory Model Feature * Register 0 and check for VMSAv7 or PMSAv7 */ unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0); if ((mmfr0 & 0x0000000f) >= 0x00000003 || (mmfr0 & 0x000000f0) >= 0x00000030) cpu_arch = CPU_ARCH_ARMv7; else if ((mmfr0 & 0x0000000f) == 0x00000002 || (mmfr0 & 0x000000f0) == 0x00000020) cpu_arch = CPU_ARCH_ARMv6; else cpu_arch = CPU_ARCH_UNKNOWN; } else cpu_arch = CPU_ARCH_UNKNOWN; return cpu_arch;}#endif int __pure cpu_architecture(void){ BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN); return __cpu_architecture;} static int cpu_has_aliasing_icache(unsigned int arch){ int aliasing_icache; unsigned int id_reg, num_sets, line_size; /* PIPT caches never alias. */ if (icache_is_pipt()) return 0; /* arch specifies the register format */ switch (arch) { case CPU_ARCH_ARMv7: set_csselr(CSSELR_ICACHE | CSSELR_L1); isb(); id_reg = read_ccsidr(); line_size = 4 << ((id_reg & 0x7) + 2); num_sets = ((id_reg >> 13) & 0x7fff) + 1; aliasing_icache = (line_size * num_sets) > PAGE_SIZE; break; case CPU_ARCH_ARMv6: aliasing_icache = read_cpuid_cachetype() & (1 << 11); break; default: /* I-cache aliases will be handled by D-cache aliasing code */ aliasing_icache = 0; } return aliasing_icache;} static void __init cacheid_init(void){ unsigned int arch = cpu_architecture(); if (arch >= CPU_ARCH_ARMv6) { unsigned int cachetype = read_cpuid_cachetype(); if ((arch == CPU_ARCH_ARMv7M) && !(cachetype & 0xf000f)) { cacheid = 0; } else if ((cachetype & (7 << 29)) == 4 << 29) { /* ARMv7 register format */ arch = CPU_ARCH_ARMv7; cacheid = CACHEID_VIPT_NONALIASING; switch (cachetype & (3 << 14)) { case (1 << 14): cacheid |= CACHEID_ASID_TAGGED; break; case (3 << 14): cacheid |= CACHEID_PIPT; break; } } else { arch = CPU_ARCH_ARMv6; if (cachetype & (1 << 23)) cacheid = CACHEID_VIPT_ALIASING; else cacheid = CACHEID_VIPT_NONALIASING; } if (cpu_has_aliasing_icache(arch)) cacheid |= CACHEID_VIPT_I_ALIASING; } else { cacheid = CACHEID_VIVT; } pr_info("CPU: %s data cache, %s instruction cache\n", cache_is_vivt() ? "VIVT" : cache_is_vipt_aliasing() ? "VIPT aliasing" : cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown", cache_is_vivt() ? "VIVT" : icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : icache_is_vipt_aliasing() ? "VIPT aliasing" : icache_is_pipt() ? "PIPT" : cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");} /* * These functions re-use the assembly code in head.S, which * already provide the required functionality. */extern struct proc_info_list *lookup_processor_type(unsigned int); void __init early_print(const char *str, ...){ extern void printascii(const char *); char buf[256]; va_list ap; va_start(ap, str); vsnprintf(buf, sizeof(buf), str, ap); va_end(ap); #ifdef CONFIG_DEBUG_LL printascii(buf);#endif printk("%s", buf);} #ifdef CONFIG_ARM_PATCH_IDIV static inline u32 __attribute_const__ sdiv_instruction(void){ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { /* "sdiv r0, r0, r1" */ u32 insn = __opcode_thumb32_compose(0xfb90, 0xf0f1); return __opcode_to_mem_thumb32(insn); } /* "sdiv r0, r0, r1" */ return __opcode_to_mem_arm(0xe710f110);} static inline u32 __attribute_const__ udiv_instruction(void){ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { /* "udiv r0, r0, r1" */ u32 insn = __opcode_thumb32_compose(0xfbb0, 0xf0f1); return __opcode_to_mem_thumb32(insn); } /* "udiv r0, r0, r1" */ return __opcode_to_mem_arm(0xe730f110);} static inline u32 __attribute_const__ bx_lr_instruction(void){ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { /* "bx lr; nop" */ u32 insn = __opcode_thumb32_compose(0x4770, 0x46c0); return __opcode_to_mem_thumb32(insn); } /* "bx lr" */ return __opcode_to_mem_arm(0xe12fff1e);} static void __init patch_aeabi_idiv(void){ extern void __aeabi_uidiv(void); extern void __aeabi_idiv(void); uintptr_t fn_addr; unsigned int mask; mask = IS_ENABLED(CONFIG_THUMB2_KERNEL) ? HWCAP_IDIVT : HWCAP_IDIVA; if (!(elf_hwcap & mask)) return; pr_info("CPU: div instructions available: patching division code\n"); fn_addr = ((uintptr_t)&__aeabi_uidiv) & ~1; asm ("" : "+g" (fn_addr)); ((u32 *)fn_addr)[0] = udiv_instruction(); ((u32 *)fn_addr)[1] = bx_lr_instruction(); flush_icache_range(fn_addr, fn_addr + 8); fn_addr = ((uintptr_t)&__aeabi_idiv) & ~1; asm ("" : "+g" (fn_addr)); ((u32 *)fn_addr)[0] = sdiv_instruction(); ((u32 *)fn_addr)[1] = bx_lr_instruction(); flush_icache_range(fn_addr, fn_addr + 8);} #elsestatic inline void patch_aeabi_idiv(void) { }#endif static void __init cpuid_init_hwcaps(void){ int block; u32 isar5; u32 isar6; u32 pfr2; if (cpu_architecture() < CPU_ARCH_ARMv7) return; block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24); if (block >= 2) elf_hwcap |= HWCAP_IDIVA; if (block >= 1) elf_hwcap |= HWCAP_IDIVT; /* LPAE implies atomic ldrd/strd instructions */ block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0); if (block >= 5) elf_hwcap |= HWCAP_LPAE; /* check for supported v8 Crypto instructions */ isar5 = read_cpuid_ext(CPUID_EXT_ISAR5); block = cpuid_feature_extract_field(isar5, 4); if (block >= 2) elf_hwcap2 |= HWCAP2_PMULL; if (block >= 1) elf_hwcap2 |= HWCAP2_AES; block = cpuid_feature_extract_field(isar5, 8); if (block >= 1) elf_hwcap2 |= HWCAP2_SHA1; block = cpuid_feature_extract_field(isar5, 12); if (block >= 1) elf_hwcap2 |= HWCAP2_SHA2; block = cpuid_feature_extract_field(isar5, 16); if (block >= 1) elf_hwcap2 |= HWCAP2_CRC32; /* Check for Speculation barrier instruction */ isar6 = read_cpuid_ext(CPUID_EXT_ISAR6); block = cpuid_feature_extract_field(isar6, 12); if (block >= 1) elf_hwcap2 |= HWCAP2_SB; /* Check for Speculative Store Bypassing control */ pfr2 = read_cpuid_ext(CPUID_EXT_PFR2); block = cpuid_feature_extract_field(pfr2, 4); if (block >= 1)Lines 1–500 of 1372. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/kernel/setup.c * * Copyright (C) 1995-2001 Russell King */ #include <linux/efi.h> #include <linux/export.h> #include <linux/kernel.h> #include <linux/stddef.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/utsname.h> #include <linux/initrd.h> #include <linux/console.h> #include <linux/seq_file.h> #include <linux/screen_info.h> #include <linux/of_platform.h> #include <linux/init.h> #include <linux/kexec.h> #include <linux/libfdt.h> #include <linux/of_fdt.h> #include <linux/cpu.h> #include <linux/interrupt.h> #include <linux/smp.h> #include <linux/proc_fs.h> #include <linux/memblock.h> #include <linux/bug.h> #include <linux/compiler.h> #include <linux/sort.h> #include <linux/psci.h> #include <asm/unified.h> #include <asm/cp15.h> #include <asm/cpu.h> #include <asm/cputype.h> #include <asm/efi.h> #include <asm/elf.h> #include <asm/early_ioremap.h> #include <asm/fixmap.h> #include <asm/procinfo.h> #include <asm/psci.h> #include <asm/sections.h> #include <asm/setup.h> #include <asm/smp_plat.h> #include <asm/mach-types.h> #include <asm/cacheflush.h> #include <asm/cachetype.h> #include <asm/tlbflush.h> #include <asm/xen/hypervisor.h> #include <asm/prom.h> #include <asm/mach/arch.h> #include <asm/mach/irq.h> #include <asm/mach/time.h> #include <asm/system_info.h> #include <asm/system_misc.h> #include <asm/traps.h> #include <asm/unwind.h> #include <asm/memblock.h> #include <asm/virt.h> #include <asm/kasan.h> #include "atags.h" #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) char fpe_type[8]; static int __init fpe_setup(char *line) { memcpy(fpe_type, line, 8); return 1; } __setup("fpe=", fpe_setup); #endif extern void init_default_cache_policy(unsigned long); extern void paging_init(const struct machine_desc *desc); extern void early_mm_init(const struct machine_desc *); extern void adjust_lowmem_bounds(void); extern enum reboot_mode reboot_mode; extern void setup_dma_zone(const struct machine_desc *desc); unsigned int processor_id; EXPORT_SYMBOL(processor_id); unsigned int __machine_arch_type __read_mostly; EXPORT_SYMBOL(__machine_arch_type); unsigned int cacheid __read_mostly; EXPORT_SYMBOL(cacheid); unsigned int __atags_pointer __initdata; unsigned int system_rev; EXPORT_SYMBOL(system_rev); const char *system_serial; EXPORT_SYMBOL(system_serial); unsigned int system_serial_low; EXPORT_SYMBOL(system_serial_low); unsigned int system_serial_high; EXPORT_SYMBOL(system_serial_high); unsigned int elf_hwcap __read_mostly; EXPORT_SYMBOL(elf_hwcap); unsigned int elf_hwcap2 __read_mostly; EXPORT_SYMBOL(elf_hwcap2); #ifdef MULTI_CPU struct processor processor __ro_after_init; #if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) struct processor *cpu_vtable[NR_CPUS] = { [0] = &processor, }; #endif #endif #ifdef MULTI_TLB struct cpu_tlb_fns cpu_tlb __ro_after_init; #endif #ifdef MULTI_USER struct cpu_user_fns cpu_user __ro_after_init; #endif #ifdef MULTI_CACHE struct cpu_cache_fns cpu_cache __ro_after_init; #endif #ifdef CONFIG_OUTER_CACHE struct outer_cache_fns outer_cache __ro_after_init; EXPORT_SYMBOL(outer_cache); #endif /* * Cached cpu_architecture() result for use by assembler code. * C code should use the cpu_architecture() function instead of accessing this * variable directly. */ int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; struct stack { u32 irq[4]; u32 abt[4]; u32 und[4]; u32 fiq[4]; } ____cacheline_aligned; #ifndef CONFIG_CPU_V7M static struct stack stacks[NR_CPUS]; #endif char elf_platform[ELF_PLATFORM_SIZE]; EXPORT_SYMBOL(elf_platform); static const char *cpu_name; static const char *machine_name; static char __initdata cmd_line[COMMAND_LINE_SIZE]; const struct machine_desc *machine_desc __initdata; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; #define ENDIANNESS ((char)endian_test.l) DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); /* * Standard memory resources */ static struct resource mem_res[] = { { .name = "Video RAM", .start = 0, .end = 0, .flags = IORESOURCE_MEM }, { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_SYSTEM_RAM }, { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_SYSTEM_RAM } }; #define video_ram mem_res[0] #define kernel_code mem_res[1] #define kernel_data mem_res[2] static struct resource io_res[] = { { .name = "reserved", .start = 0x3bc, .end = 0x3be, .flags = IORESOURCE_IO | IORESOURCE_BUSY }, { .name = "reserved", .start = 0x378, .end = 0x37f, .flags = IORESOURCE_IO | IORESOURCE_BUSY }, { .name = "reserved", .start = 0x278, .end = 0x27f, .flags = IORESOURCE_IO | IORESOURCE_BUSY } }; #define lp0 io_res[0] #define lp1 io_res[1] #define lp2 io_res[2] static const char *proc_arch[] = { "undefined/unknown", "3", "4", "4T", "5", "5T", "5TE", "5TEJ", "6TEJ", "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)", }; #ifdef CONFIG_CPU_V7M static int __get_cpu_architecture(void) { return CPU_ARCH_ARMv7M; } #else static int __get_cpu_architecture(void) { int cpu_arch; if ((read_cpuid_id() & 0x0008f000) == 0) { cpu_arch = CPU_ARCH_UNKNOWN; } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { cpu_arch = (read_cpuid_id() >> 16) & 7; if (cpu_arch) cpu_arch += CPU_ARCH_ARMv3; } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { /* Revised CPUID format. Read the Memory Model Feature * Register 0 and check for VMSAv7 or PMSAv7 */ unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0); if ((mmfr0 & 0x0000000f) >= 0x00000003 || (mmfr0 & 0x000000f0) >= 0x00000030) cpu_arch = CPU_ARCH_ARMv7; else if ((mmfr0 & 0x0000000f) == 0x00000002 || (mmfr0 & 0x000000f0) == 0x00000020) cpu_arch = CPU_ARCH_ARMv6; else cpu_arch = CPU_ARCH_UNKNOWN; } else cpu_arch = CPU_ARCH_UNKNOWN; return cpu_arch; } #endif int __pure cpu_architecture(void) { BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN); return __cpu_architecture; } static int cpu_has_aliasing_icache(unsigned int arch) { int aliasing_icache; unsigned int id_reg, num_sets, line_size; /* PIPT caches never alias. */ if (icache_is_pipt()) return 0; /* arch specifies the register format */ switch (arch) { case CPU_ARCH_ARMv7: set_csselr(CSSELR_ICACHE | CSSELR_L1); isb(); id_reg = read_ccsidr(); line_size = 4 << ((id_reg & 0x7) + 2); num_sets = ((id_reg >> 13) & 0x7fff) + 1; aliasing_icache = (line_size * num_sets) > PAGE_SIZE; break; case CPU_ARCH_ARMv6: aliasing_icache = read_cpuid_cachetype() & (1 << 11); break; default: /* I-cache aliases will be handled by D-cache aliasing code */ aliasing_icache = 0; } return aliasing_icache; } static void __init cacheid_init(void) { unsigned int arch = cpu_architecture(); if (arch >= CPU_ARCH_ARMv6) { unsigned int cachetype = read_cpuid_cachetype(); if ((arch == CPU_ARCH_ARMv7M) && !(cachetype & 0xf000f)) { cacheid = 0; } else if ((cachetype & (7 << 29)) == 4 << 29) { /* ARMv7 register format */ arch = CPU_ARCH_ARMv7; cacheid = CACHEID_VIPT_NONALIASING; switch (cachetype & (3 << 14)) { case (1 << 14): cacheid |= CACHEID_ASID_TAGGED; break; case (3 << 14): cacheid |= CACHEID_PIPT; break; } } else { arch = CPU_ARCH_ARMv6; if (cachetype & (1 << 23)) cacheid = CACHEID_VIPT_ALIASING; else cacheid = CACHEID_VIPT_NONALIASING; } if (cpu_has_aliasing_icache(arch)) cacheid |= CACHEID_VIPT_I_ALIASING; } else { cacheid = CACHEID_VIVT; } pr_info("CPU: %s data cache, %s instruction cache\n", cache_is_vivt() ? "VIVT" : cache_is_vipt_aliasing() ? "VIPT aliasing" : cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown", cache_is_vivt() ? "VIVT" : icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : icache_is_vipt_aliasing() ? "VIPT aliasing" : icache_is_pipt() ? "PIPT" : cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); } /* * These functions re-use the assembly code in head.S, which * already provide the required functionality. */ extern struct proc_info_list *lookup_processor_type(unsigned int); void __init early_print(const char *str, ...) { extern void printascii(const char *); char buf[256]; va_list ap; va_start(ap, str); vsnprintf(buf, sizeof(buf), str, ap); va_end(ap); #ifdef CONFIG_DEBUG_LL printascii(buf); #endif printk("%s", buf); } #ifdef CONFIG_ARM_PATCH_IDIV static inline u32 __attribute_const__ sdiv_instruction(void) { if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { /* "sdiv r0, r0, r1" */ u32 insn = __opcode_thumb32_compose(0xfb90, 0xf0f1); return __opcode_to_mem_thumb32(insn); } /* "sdiv r0, r0, r1" */ return __opcode_to_mem_arm(0xe710f110); } static inline u32 __attribute_const__ udiv_instruction(void) { if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { /* "udiv r0, r0, r1" */ u32 insn = __opcode_thumb32_compose(0xfbb0, 0xf0f1); return __opcode_to_mem_thumb32(insn); } /* "udiv r0, r0, r1" */ return __opcode_to_mem_arm(0xe730f110); } static inline u32 __attribute_const__ bx_lr_instruction(void) { if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { /* "bx lr; nop" */ u32 insn = __opcode_thumb32_compose(0x4770, 0x46c0); return __opcode_to_mem_thumb32(insn); } /* "bx lr" */ return __opcode_to_mem_arm(0xe12fff1e); } static void __init patch_aeabi_idiv(void) { extern void __aeabi_uidiv(void); extern void __aeabi_idiv(void); uintptr_t fn_addr; unsigned int mask; mask = IS_ENABLED(CONFIG_THUMB2_KERNEL) ? HWCAP_IDIVT : HWCAP_IDIVA; if (!(elf_hwcap & mask)) return; pr_info("CPU: div instructions available: patching division code\n"); fn_addr = ((uintptr_t)&__aeabi_uidiv) & ~1; asm ("" : "+g" (fn_addr)); ((u32 *)fn_addr)[0] = udiv_instruction(); ((u32 *)fn_addr)[1] = bx_lr_instruction(); flush_icache_range(fn_addr, fn_addr + 8); fn_addr = ((uintptr_t)&__aeabi_idiv) & ~1; asm ("" : "+g" (fn_addr)); ((u32 *)fn_addr)[0] = sdiv_instruction(); ((u32 *)fn_addr)[1] = bx_lr_instruction(); flush_icache_range(fn_addr, fn_addr + 8); } #else static inline void patch_aeabi_idiv(void) { } #endif static void __init cpuid_init_hwcaps(void) { int block; u32 isar5; u32 isar6; u32 pfr2; if (cpu_architecture() < CPU_ARCH_ARMv7) return; block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24); if (block >= 2) elf_hwcap |= HWCAP_IDIVA; if (block >= 1) elf_hwcap |= HWCAP_IDIVT; /* LPAE implies atomic ldrd/strd instructions */ block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0); if (block >= 5) elf_hwcap |= HWCAP_LPAE; /* check for supported v8 Crypto instructions */ isar5 = read_cpuid_ext(CPUID_EXT_ISAR5); block = cpuid_feature_extract_field(isar5, 4); if (block >= 2) elf_hwcap2 |= HWCAP2_PMULL; if (block >= 1) elf_hwcap2 |= HWCAP2_AES; block = cpuid_feature_extract_field(isar5, 8); if (block >= 1) elf_hwcap2 |= HWCAP2_SHA1; block = cpuid_feature_extract_field(isar5, 12); if (block >= 1) elf_hwcap2 |= HWCAP2_SHA2; block = cpuid_feature_extract_field(isar5, 16); if (block >= 1) elf_hwcap2 |= HWCAP2_CRC32; /* Check for Speculation barrier instruction */ isar6 = read_cpuid_ext(CPUID_EXT_ISAR6); block = cpuid_feature_extract_field(isar6, 12); if (block >= 1) elf_hwcap2 |= HWCAP2_SB; /* Check for Speculative Store Bypassing control */ pfr2 = read_cpuid_ext(CPUID_EXT_PFR2); block = cpuid_feature_extract_field(pfr2, 4); if (block >= 1)