19703d9d7SCatalin Marinas /* 29703d9d7SCatalin Marinas * Based on arch/arm/kernel/setup.c 39703d9d7SCatalin Marinas * 49703d9d7SCatalin Marinas * Copyright (C) 1995-2001 Russell King 59703d9d7SCatalin Marinas * Copyright (C) 2012 ARM Ltd. 69703d9d7SCatalin Marinas * 79703d9d7SCatalin Marinas * This program is free software; you can redistribute it and/or modify 89703d9d7SCatalin Marinas * it under the terms of the GNU General Public License version 2 as 99703d9d7SCatalin Marinas * published by the Free Software Foundation. 109703d9d7SCatalin Marinas * 119703d9d7SCatalin Marinas * This program is distributed in the hope that it will be useful, 129703d9d7SCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of 139703d9d7SCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149703d9d7SCatalin Marinas * GNU General Public License for more details. 159703d9d7SCatalin Marinas * 169703d9d7SCatalin Marinas * You should have received a copy of the GNU General Public License 179703d9d7SCatalin Marinas * along with this program. If not, see <http://www.gnu.org/licenses/>. 189703d9d7SCatalin Marinas */ 199703d9d7SCatalin Marinas 2037655163SAl Stone #include <linux/acpi.h> 219703d9d7SCatalin Marinas #include <linux/export.h> 229703d9d7SCatalin Marinas #include <linux/kernel.h> 239703d9d7SCatalin Marinas #include <linux/stddef.h> 249703d9d7SCatalin Marinas #include <linux/ioport.h> 259703d9d7SCatalin Marinas #include <linux/delay.h> 269703d9d7SCatalin Marinas #include <linux/utsname.h> 279703d9d7SCatalin Marinas #include <linux/initrd.h> 289703d9d7SCatalin Marinas #include <linux/console.h> 29a41dc0e8SCatalin Marinas #include <linux/cache.h> 309703d9d7SCatalin Marinas #include <linux/bootmem.h> 319703d9d7SCatalin Marinas #include <linux/screen_info.h> 329703d9d7SCatalin Marinas #include <linux/init.h> 339703d9d7SCatalin Marinas #include <linux/kexec.h> 349703d9d7SCatalin Marinas #include <linux/root_dev.h> 359703d9d7SCatalin Marinas #include <linux/cpu.h> 369703d9d7SCatalin Marinas #include <linux/interrupt.h> 379703d9d7SCatalin Marinas #include <linux/smp.h> 389703d9d7SCatalin Marinas #include <linux/fs.h> 399703d9d7SCatalin Marinas #include <linux/proc_fs.h> 409703d9d7SCatalin Marinas #include <linux/memblock.h> 419703d9d7SCatalin Marinas #include <linux/of_fdt.h> 42f84d0275SMark Salter #include <linux/efi.h> 43bff60792SMark Rutland #include <linux/psci.h> 449164bb4aSIngo Molnar #include <linux/sched/task.h> 452077be67SLaura Abbott #include <linux/mm.h> 469703d9d7SCatalin Marinas 4737655163SAl Stone #include <asm/acpi.h> 48bf4b558eSMark Salter #include <asm/fixmap.h> 49df857416SMark Rutland #include <asm/cpu.h> 509703d9d7SCatalin Marinas #include <asm/cputype.h> 519703d9d7SCatalin Marinas #include <asm/elf.h> 52930da09fSAndre Przywara #include <asm/cpufeature.h> 53e8765b26SMark Rutland #include <asm/cpu_ops.h> 5439d114ddSAndrey Ryabinin #include <asm/kasan.h> 551a2db300SGanapatrao Kulkarni #include <asm/numa.h> 569703d9d7SCatalin Marinas #include <asm/sections.h> 579703d9d7SCatalin Marinas #include <asm/setup.h> 584c7aa002SJavi Merino #include <asm/smp_plat.h> 599703d9d7SCatalin Marinas #include <asm/cacheflush.h> 609703d9d7SCatalin Marinas #include <asm/tlbflush.h> 619703d9d7SCatalin Marinas #include <asm/traps.h> 629703d9d7SCatalin Marinas #include <asm/memblock.h> 63f84d0275SMark Salter #include <asm/efi.h> 645882bfefSStefano Stabellini #include <asm/xen/hypervisor.h> 659e8e865bSMark Rutland #include <asm/mmu_context.h> 669703d9d7SCatalin Marinas 679703d9d7SCatalin Marinas phys_addr_t __fdt_pointer __initdata; 689703d9d7SCatalin Marinas 699703d9d7SCatalin Marinas /* 709703d9d7SCatalin Marinas * Standard memory resources 719703d9d7SCatalin Marinas */ 729703d9d7SCatalin Marinas static struct resource mem_res[] = { 739703d9d7SCatalin Marinas { 749703d9d7SCatalin Marinas .name = "Kernel code", 759703d9d7SCatalin Marinas .start = 0, 769703d9d7SCatalin Marinas .end = 0, 7735d98e93SToshi Kani .flags = IORESOURCE_SYSTEM_RAM 789703d9d7SCatalin Marinas }, 799703d9d7SCatalin Marinas { 809703d9d7SCatalin Marinas .name = "Kernel data", 819703d9d7SCatalin Marinas .start = 0, 829703d9d7SCatalin Marinas .end = 0, 8335d98e93SToshi Kani .flags = IORESOURCE_SYSTEM_RAM 849703d9d7SCatalin Marinas } 859703d9d7SCatalin Marinas }; 869703d9d7SCatalin Marinas 879703d9d7SCatalin Marinas #define kernel_code mem_res[0] 889703d9d7SCatalin Marinas #define kernel_data mem_res[1] 899703d9d7SCatalin Marinas 90da9c177dSArd Biesheuvel /* 91da9c177dSArd Biesheuvel * The recorded values of x0 .. x3 upon kernel entry. 92da9c177dSArd Biesheuvel */ 93da9c177dSArd Biesheuvel u64 __cacheline_aligned boot_args[4]; 94da9c177dSArd Biesheuvel 9571586276SWill Deacon void __init smp_setup_processor_id(void) 9671586276SWill Deacon { 9780708677SMark Rutland u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; 9880708677SMark Rutland cpu_logical_map(0) = mpidr; 9980708677SMark Rutland 10071586276SWill Deacon /* 10171586276SWill Deacon * clear __my_cpu_offset on boot CPU to avoid hang caused by 10271586276SWill Deacon * using percpu variable early, for example, lockdep will 10371586276SWill Deacon * access percpu variable inside lock_release 10471586276SWill Deacon */ 10571586276SWill Deacon set_my_cpu_offset(0); 10680708677SMark Rutland pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr); 10771586276SWill Deacon } 10871586276SWill Deacon 1096e15d0e0SSudeep KarkadaNagesha bool arch_match_cpu_phys_id(int cpu, u64 phys_id) 1106e15d0e0SSudeep KarkadaNagesha { 1116e15d0e0SSudeep KarkadaNagesha return phys_id == cpu_logical_map(cpu); 1126e15d0e0SSudeep KarkadaNagesha } 1136e15d0e0SSudeep KarkadaNagesha 114976d7d3fSLorenzo Pieralisi struct mpidr_hash mpidr_hash; 115976d7d3fSLorenzo Pieralisi /** 116976d7d3fSLorenzo Pieralisi * smp_build_mpidr_hash - Pre-compute shifts required at each affinity 117976d7d3fSLorenzo Pieralisi * level in order to build a linear index from an 118976d7d3fSLorenzo Pieralisi * MPIDR value. Resulting algorithm is a collision 119976d7d3fSLorenzo Pieralisi * free hash carried out through shifting and ORing 120976d7d3fSLorenzo Pieralisi */ 121976d7d3fSLorenzo Pieralisi static void __init smp_build_mpidr_hash(void) 122976d7d3fSLorenzo Pieralisi { 123976d7d3fSLorenzo Pieralisi u32 i, affinity, fs[4], bits[4], ls; 124976d7d3fSLorenzo Pieralisi u64 mask = 0; 125976d7d3fSLorenzo Pieralisi /* 126976d7d3fSLorenzo Pieralisi * Pre-scan the list of MPIDRS and filter out bits that do 127976d7d3fSLorenzo Pieralisi * not contribute to affinity levels, ie they never toggle. 128976d7d3fSLorenzo Pieralisi */ 129976d7d3fSLorenzo Pieralisi for_each_possible_cpu(i) 130976d7d3fSLorenzo Pieralisi mask |= (cpu_logical_map(i) ^ cpu_logical_map(0)); 131976d7d3fSLorenzo Pieralisi pr_debug("mask of set bits %#llx\n", mask); 132976d7d3fSLorenzo Pieralisi /* 133976d7d3fSLorenzo Pieralisi * Find and stash the last and first bit set at all affinity levels to 134976d7d3fSLorenzo Pieralisi * check how many bits are required to represent them. 135976d7d3fSLorenzo Pieralisi */ 136976d7d3fSLorenzo Pieralisi for (i = 0; i < 4; i++) { 137976d7d3fSLorenzo Pieralisi affinity = MPIDR_AFFINITY_LEVEL(mask, i); 138976d7d3fSLorenzo Pieralisi /* 139976d7d3fSLorenzo Pieralisi * Find the MSB bit and LSB bits position 140976d7d3fSLorenzo Pieralisi * to determine how many bits are required 141976d7d3fSLorenzo Pieralisi * to express the affinity level. 142976d7d3fSLorenzo Pieralisi */ 143976d7d3fSLorenzo Pieralisi ls = fls(affinity); 144976d7d3fSLorenzo Pieralisi fs[i] = affinity ? ffs(affinity) - 1 : 0; 145976d7d3fSLorenzo Pieralisi bits[i] = ls - fs[i]; 146976d7d3fSLorenzo Pieralisi } 147976d7d3fSLorenzo Pieralisi /* 148976d7d3fSLorenzo Pieralisi * An index can be created from the MPIDR_EL1 by isolating the 149976d7d3fSLorenzo Pieralisi * significant bits at each affinity level and by shifting 150976d7d3fSLorenzo Pieralisi * them in order to compress the 32 bits values space to a 151976d7d3fSLorenzo Pieralisi * compressed set of values. This is equivalent to hashing 152976d7d3fSLorenzo Pieralisi * the MPIDR_EL1 through shifting and ORing. It is a collision free 153976d7d3fSLorenzo Pieralisi * hash though not minimal since some levels might contain a number 154976d7d3fSLorenzo Pieralisi * of CPUs that is not an exact power of 2 and their bit 155976d7d3fSLorenzo Pieralisi * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}. 156976d7d3fSLorenzo Pieralisi */ 157976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0]; 158976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0]; 159976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] - 160976d7d3fSLorenzo Pieralisi (bits[1] + bits[0]); 161976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) + 162976d7d3fSLorenzo Pieralisi fs[3] - (bits[2] + bits[1] + bits[0]); 163976d7d3fSLorenzo Pieralisi mpidr_hash.mask = mask; 164976d7d3fSLorenzo Pieralisi mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0]; 165976d7d3fSLorenzo Pieralisi pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n", 166976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[0], 167976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[1], 168976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[2], 169976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[3], 170976d7d3fSLorenzo Pieralisi mpidr_hash.mask, 171976d7d3fSLorenzo Pieralisi mpidr_hash.bits); 172976d7d3fSLorenzo Pieralisi /* 173976d7d3fSLorenzo Pieralisi * 4x is an arbitrary value used to warn on a hash table much bigger 174976d7d3fSLorenzo Pieralisi * than expected on most systems. 175976d7d3fSLorenzo Pieralisi */ 176976d7d3fSLorenzo Pieralisi if (mpidr_hash_size() > 4 * num_possible_cpus()) 177976d7d3fSLorenzo Pieralisi pr_warn("Large number of MPIDR hash buckets detected\n"); 178976d7d3fSLorenzo Pieralisi } 179137650aaSMark Rutland 1809703d9d7SCatalin Marinas static void __init setup_machine_fdt(phys_addr_t dt_phys) 1819703d9d7SCatalin Marinas { 18261bd93ceSArd Biesheuvel void *dt_virt = fixmap_remap_fdt(dt_phys); 1832f9a0becSGeert Uytterhoeven const char *name; 18461bd93ceSArd Biesheuvel 18561bd93ceSArd Biesheuvel if (!dt_virt || !early_init_dt_scan(dt_virt)) { 18661bd93ceSArd Biesheuvel pr_crit("\n" 18761bd93ceSArd Biesheuvel "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n" 18861bd93ceSArd Biesheuvel "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" 18961bd93ceSArd Biesheuvel "\nPlease check your bootloader.", 19061bd93ceSArd Biesheuvel &dt_phys, dt_virt); 1919703d9d7SCatalin Marinas 1929703d9d7SCatalin Marinas while (true) 1939703d9d7SCatalin Marinas cpu_relax(); 1949703d9d7SCatalin Marinas } 1955e39977eSWill Deacon 1962f9a0becSGeert Uytterhoeven name = of_flat_dt_get_machine_name(); 1972f9a0becSGeert Uytterhoeven pr_info("Machine model: %s\n", name); 1982f9a0becSGeert Uytterhoeven dump_stack_set_arch_desc("%s (DT)", name); 1999703d9d7SCatalin Marinas } 2009703d9d7SCatalin Marinas 2019703d9d7SCatalin Marinas static void __init request_standard_resources(void) 2029703d9d7SCatalin Marinas { 2039703d9d7SCatalin Marinas struct memblock_region *region; 2049703d9d7SCatalin Marinas struct resource *res; 2059703d9d7SCatalin Marinas 2062077be67SLaura Abbott kernel_code.start = __pa_symbol(_text); 2072077be67SLaura Abbott kernel_code.end = __pa_symbol(__init_begin - 1); 2082077be67SLaura Abbott kernel_data.start = __pa_symbol(_sdata); 2092077be67SLaura Abbott kernel_data.end = __pa_symbol(_end - 1); 2109703d9d7SCatalin Marinas 2119703d9d7SCatalin Marinas for_each_memblock(memory, region) { 2129703d9d7SCatalin Marinas res = alloc_bootmem_low(sizeof(*res)); 213e7cd1903SAKASHI Takahiro if (memblock_is_nomap(region)) { 214e7cd1903SAKASHI Takahiro res->name = "reserved"; 21579ba11d2SArd Biesheuvel res->flags = IORESOURCE_MEM; 216e7cd1903SAKASHI Takahiro } else { 2179703d9d7SCatalin Marinas res->name = "System RAM"; 218e7cd1903SAKASHI Takahiro res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 219e7cd1903SAKASHI Takahiro } 2209703d9d7SCatalin Marinas res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 2219703d9d7SCatalin Marinas res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 2229703d9d7SCatalin Marinas 2239703d9d7SCatalin Marinas request_resource(&iomem_resource, res); 2249703d9d7SCatalin Marinas 2259703d9d7SCatalin Marinas if (kernel_code.start >= res->start && 2269703d9d7SCatalin Marinas kernel_code.end <= res->end) 2279703d9d7SCatalin Marinas request_resource(res, &kernel_code); 2289703d9d7SCatalin Marinas if (kernel_data.start >= res->start && 2299703d9d7SCatalin Marinas kernel_data.end <= res->end) 2309703d9d7SCatalin Marinas request_resource(res, &kernel_data); 231764b51eaSAKASHI Takahiro #ifdef CONFIG_KEXEC_CORE 232764b51eaSAKASHI Takahiro /* Userspace will find "Crash kernel" region in /proc/iomem. */ 233764b51eaSAKASHI Takahiro if (crashk_res.end && crashk_res.start >= res->start && 234764b51eaSAKASHI Takahiro crashk_res.end <= res->end) 235764b51eaSAKASHI Takahiro request_resource(res, &crashk_res); 236764b51eaSAKASHI Takahiro #endif 2379703d9d7SCatalin Marinas } 2389703d9d7SCatalin Marinas } 2399703d9d7SCatalin Marinas 2404c7aa002SJavi Merino u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID }; 2414c7aa002SJavi Merino 2429703d9d7SCatalin Marinas void __init setup_arch(char **cmdline_p) 2439703d9d7SCatalin Marinas { 2444b998ff1SSuzuki K. Poulose pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id()); 2459703d9d7SCatalin Marinas 246cfa88c79SMichal Marek sprintf(init_utsname()->machine, UTS_MACHINE); 2479703d9d7SCatalin Marinas init_mm.start_code = (unsigned long) _text; 2489703d9d7SCatalin Marinas init_mm.end_code = (unsigned long) _etext; 2499703d9d7SCatalin Marinas init_mm.end_data = (unsigned long) _edata; 2509703d9d7SCatalin Marinas init_mm.brk = (unsigned long) _end; 2519703d9d7SCatalin Marinas 2529703d9d7SCatalin Marinas *cmdline_p = boot_command_line; 2539703d9d7SCatalin Marinas 254af86e597SLaura Abbott early_fixmap_init(); 255bf4b558eSMark Salter early_ioremap_init(); 2560bf757c7SMark Salter 25761bd93ceSArd Biesheuvel setup_machine_fdt(__fdt_pointer); 25861bd93ceSArd Biesheuvel 2599703d9d7SCatalin Marinas parse_early_param(); 2609703d9d7SCatalin Marinas 2617a9c43beSJon Masters /* 2627a9c43beSJon Masters * Unmask asynchronous aborts after bringing up possible earlycon. 2637a9c43beSJon Masters * (Report possible System Errors once we can report this occurred) 2647a9c43beSJon Masters */ 2657a9c43beSJon Masters local_async_enable(); 2667a9c43beSJon Masters 26786ccce89SMark Rutland /* 26886ccce89SMark Rutland * TTBR0 is only used for the identity mapping at this stage. Make it 26986ccce89SMark Rutland * point to zero page to avoid speculatively fetching new entries. 27086ccce89SMark Rutland */ 27186ccce89SMark Rutland cpu_uninstall_idmap(); 27286ccce89SMark Rutland 2739b08aaa3SShannon Zhao xen_early_init(); 274f84d0275SMark Salter efi_init(); 2759703d9d7SCatalin Marinas arm64_memblock_init(); 2769703d9d7SCatalin Marinas 27738b04a74SJon Masters paging_init(); 27838b04a74SJon Masters 27938b04a74SJon Masters acpi_table_upgrade(); 28038b04a74SJon Masters 28137655163SAl Stone /* Parse the ACPI tables for possible boot-time configuration */ 28237655163SAl Stone acpi_boot_table_init(); 28337655163SAl Stone 2843194ac6eSDavid Daney if (acpi_disabled) 2853194ac6eSDavid Daney unflatten_device_tree(); 2863194ac6eSDavid Daney 2873194ac6eSDavid Daney bootmem_init(); 2883194ac6eSDavid Daney 28939d114ddSAndrey Ryabinin kasan_init(); 29039d114ddSAndrey Ryabinin 2919703d9d7SCatalin Marinas request_standard_resources(); 2929703d9d7SCatalin Marinas 2930e63ea48SArd Biesheuvel early_ioremap_reset(); 294f84d0275SMark Salter 2953194ac6eSDavid Daney if (acpi_disabled) 2967c59a3dfSGraeme Gregory psci_dt_init(); 2973194ac6eSDavid Daney else 298fccb9a81SHanjun Guo psci_acpi_init(); 2993194ac6eSDavid Daney 3000f078336SLorenzo Pieralisi cpu_read_bootcpu_ops(); 3010f078336SLorenzo Pieralisi smp_init_cpus(); 302976d7d3fSLorenzo Pieralisi smp_build_mpidr_hash(); 3039703d9d7SCatalin Marinas 30439bc88e5SCatalin Marinas #ifdef CONFIG_ARM64_SW_TTBR0_PAN 30539bc88e5SCatalin Marinas /* 30639bc88e5SCatalin Marinas * Make sure init_thread_info.ttbr0 always generates translation 30739bc88e5SCatalin Marinas * faults in case uaccess_enable() is inadvertently called by the init 30839bc88e5SCatalin Marinas * thread. 30939bc88e5SCatalin Marinas */ 310cbb999ddSGeert Uytterhoeven init_task.thread_info.ttbr0 = __pa_symbol(empty_zero_page); 31139bc88e5SCatalin Marinas #endif 31239bc88e5SCatalin Marinas 3139703d9d7SCatalin Marinas #ifdef CONFIG_VT 3149703d9d7SCatalin Marinas #if defined(CONFIG_VGA_CONSOLE) 3159703d9d7SCatalin Marinas conswitchp = &vga_con; 3169703d9d7SCatalin Marinas #elif defined(CONFIG_DUMMY_CONSOLE) 3179703d9d7SCatalin Marinas conswitchp = &dummy_con; 3189703d9d7SCatalin Marinas #endif 3199703d9d7SCatalin Marinas #endif 320da9c177dSArd Biesheuvel if (boot_args[1] || boot_args[2] || boot_args[3]) { 321da9c177dSArd Biesheuvel pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n" 322da9c177dSArd Biesheuvel "\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n" 323da9c177dSArd Biesheuvel "This indicates a broken bootloader or old kernel\n", 324da9c177dSArd Biesheuvel boot_args[1], boot_args[2], boot_args[3]); 325da9c177dSArd Biesheuvel } 3269703d9d7SCatalin Marinas } 3279703d9d7SCatalin Marinas 3289703d9d7SCatalin Marinas static int __init topology_init(void) 3299703d9d7SCatalin Marinas { 3309703d9d7SCatalin Marinas int i; 3319703d9d7SCatalin Marinas 3321a2db300SGanapatrao Kulkarni for_each_online_node(i) 3331a2db300SGanapatrao Kulkarni register_one_node(i); 3341a2db300SGanapatrao Kulkarni 3359703d9d7SCatalin Marinas for_each_possible_cpu(i) { 336df857416SMark Rutland struct cpu *cpu = &per_cpu(cpu_data.cpu, i); 3379703d9d7SCatalin Marinas cpu->hotpluggable = 1; 3389703d9d7SCatalin Marinas register_cpu(cpu, i); 3399703d9d7SCatalin Marinas } 3409703d9d7SCatalin Marinas 3419703d9d7SCatalin Marinas return 0; 3429703d9d7SCatalin Marinas } 3439703d9d7SCatalin Marinas subsys_initcall(topology_init); 344f80fb3a3SArd Biesheuvel 345f80fb3a3SArd Biesheuvel /* 346f80fb3a3SArd Biesheuvel * Dump out kernel offset information on panic. 347f80fb3a3SArd Biesheuvel */ 348f80fb3a3SArd Biesheuvel static int dump_kernel_offset(struct notifier_block *self, unsigned long v, 349f80fb3a3SArd Biesheuvel void *p) 350f80fb3a3SArd Biesheuvel { 3517ede8665SAlexander Popov const unsigned long offset = kaslr_offset(); 352f80fb3a3SArd Biesheuvel 3537ede8665SAlexander Popov if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && offset > 0) { 3547ede8665SAlexander Popov pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n", 3557ede8665SAlexander Popov offset, KIMAGE_VADDR); 356f80fb3a3SArd Biesheuvel } else { 357f80fb3a3SArd Biesheuvel pr_emerg("Kernel Offset: disabled\n"); 358f80fb3a3SArd Biesheuvel } 359f80fb3a3SArd Biesheuvel return 0; 360f80fb3a3SArd Biesheuvel } 361f80fb3a3SArd Biesheuvel 362f80fb3a3SArd Biesheuvel static struct notifier_block kernel_offset_notifier = { 363f80fb3a3SArd Biesheuvel .notifier_call = dump_kernel_offset 364f80fb3a3SArd Biesheuvel }; 365f80fb3a3SArd Biesheuvel 366f80fb3a3SArd Biesheuvel static int __init register_kernel_offset_dumper(void) 367f80fb3a3SArd Biesheuvel { 368f80fb3a3SArd Biesheuvel atomic_notifier_chain_register(&panic_notifier_list, 369f80fb3a3SArd Biesheuvel &kernel_offset_notifier); 370f80fb3a3SArd Biesheuvel return 0; 371f80fb3a3SArd Biesheuvel } 372f80fb3a3SArd Biesheuvel __initcall(register_kernel_offset_dumper); 373