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/crash_dump.h> 359703d9d7SCatalin Marinas #include <linux/root_dev.h> 369703d9d7SCatalin Marinas #include <linux/cpu.h> 379703d9d7SCatalin Marinas #include <linux/interrupt.h> 389703d9d7SCatalin Marinas #include <linux/smp.h> 399703d9d7SCatalin Marinas #include <linux/fs.h> 409703d9d7SCatalin Marinas #include <linux/proc_fs.h> 419703d9d7SCatalin Marinas #include <linux/memblock.h> 4278d51e0bSRobin Murphy #include <linux/of_iommu.h> 439703d9d7SCatalin Marinas #include <linux/of_fdt.h> 44d6bafb9bSCatalin Marinas #include <linux/of_platform.h> 45f84d0275SMark Salter #include <linux/efi.h> 46bff60792SMark Rutland #include <linux/psci.h> 479703d9d7SCatalin Marinas 4837655163SAl Stone #include <asm/acpi.h> 49bf4b558eSMark Salter #include <asm/fixmap.h> 50df857416SMark Rutland #include <asm/cpu.h> 519703d9d7SCatalin Marinas #include <asm/cputype.h> 529703d9d7SCatalin Marinas #include <asm/elf.h> 53930da09fSAndre Przywara #include <asm/cpufeature.h> 54e8765b26SMark Rutland #include <asm/cpu_ops.h> 5539d114ddSAndrey Ryabinin #include <asm/kasan.h> 561a2db300SGanapatrao Kulkarni #include <asm/numa.h> 579703d9d7SCatalin Marinas #include <asm/sections.h> 589703d9d7SCatalin Marinas #include <asm/setup.h> 594c7aa002SJavi Merino #include <asm/smp_plat.h> 609703d9d7SCatalin Marinas #include <asm/cacheflush.h> 619703d9d7SCatalin Marinas #include <asm/tlbflush.h> 629703d9d7SCatalin Marinas #include <asm/traps.h> 639703d9d7SCatalin Marinas #include <asm/memblock.h> 64f84d0275SMark Salter #include <asm/efi.h> 655882bfefSStefano Stabellini #include <asm/xen/hypervisor.h> 669e8e865bSMark Rutland #include <asm/mmu_context.h> 679703d9d7SCatalin Marinas 689703d9d7SCatalin Marinas phys_addr_t __fdt_pointer __initdata; 699703d9d7SCatalin Marinas 709703d9d7SCatalin Marinas /* 719703d9d7SCatalin Marinas * Standard memory resources 729703d9d7SCatalin Marinas */ 739703d9d7SCatalin Marinas static struct resource mem_res[] = { 749703d9d7SCatalin Marinas { 759703d9d7SCatalin Marinas .name = "Kernel code", 769703d9d7SCatalin Marinas .start = 0, 779703d9d7SCatalin Marinas .end = 0, 7835d98e93SToshi Kani .flags = IORESOURCE_SYSTEM_RAM 799703d9d7SCatalin Marinas }, 809703d9d7SCatalin Marinas { 819703d9d7SCatalin Marinas .name = "Kernel data", 829703d9d7SCatalin Marinas .start = 0, 839703d9d7SCatalin Marinas .end = 0, 8435d98e93SToshi Kani .flags = IORESOURCE_SYSTEM_RAM 859703d9d7SCatalin Marinas } 869703d9d7SCatalin Marinas }; 879703d9d7SCatalin Marinas 889703d9d7SCatalin Marinas #define kernel_code mem_res[0] 899703d9d7SCatalin Marinas #define kernel_data mem_res[1] 909703d9d7SCatalin Marinas 91da9c177dSArd Biesheuvel /* 92da9c177dSArd Biesheuvel * The recorded values of x0 .. x3 upon kernel entry. 93da9c177dSArd Biesheuvel */ 94da9c177dSArd Biesheuvel u64 __cacheline_aligned boot_args[4]; 95da9c177dSArd Biesheuvel 9671586276SWill Deacon void __init smp_setup_processor_id(void) 9771586276SWill Deacon { 9880708677SMark Rutland u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; 9980708677SMark Rutland cpu_logical_map(0) = mpidr; 10080708677SMark Rutland 10171586276SWill Deacon /* 10271586276SWill Deacon * clear __my_cpu_offset on boot CPU to avoid hang caused by 10371586276SWill Deacon * using percpu variable early, for example, lockdep will 10471586276SWill Deacon * access percpu variable inside lock_release 10571586276SWill Deacon */ 10671586276SWill Deacon set_my_cpu_offset(0); 10780708677SMark Rutland pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr); 10871586276SWill Deacon } 10971586276SWill Deacon 1106e15d0e0SSudeep KarkadaNagesha bool arch_match_cpu_phys_id(int cpu, u64 phys_id) 1116e15d0e0SSudeep KarkadaNagesha { 1126e15d0e0SSudeep KarkadaNagesha return phys_id == cpu_logical_map(cpu); 1136e15d0e0SSudeep KarkadaNagesha } 1146e15d0e0SSudeep KarkadaNagesha 115976d7d3fSLorenzo Pieralisi struct mpidr_hash mpidr_hash; 116976d7d3fSLorenzo Pieralisi /** 117976d7d3fSLorenzo Pieralisi * smp_build_mpidr_hash - Pre-compute shifts required at each affinity 118976d7d3fSLorenzo Pieralisi * level in order to build a linear index from an 119976d7d3fSLorenzo Pieralisi * MPIDR value. Resulting algorithm is a collision 120976d7d3fSLorenzo Pieralisi * free hash carried out through shifting and ORing 121976d7d3fSLorenzo Pieralisi */ 122976d7d3fSLorenzo Pieralisi static void __init smp_build_mpidr_hash(void) 123976d7d3fSLorenzo Pieralisi { 124976d7d3fSLorenzo Pieralisi u32 i, affinity, fs[4], bits[4], ls; 125976d7d3fSLorenzo Pieralisi u64 mask = 0; 126976d7d3fSLorenzo Pieralisi /* 127976d7d3fSLorenzo Pieralisi * Pre-scan the list of MPIDRS and filter out bits that do 128976d7d3fSLorenzo Pieralisi * not contribute to affinity levels, ie they never toggle. 129976d7d3fSLorenzo Pieralisi */ 130976d7d3fSLorenzo Pieralisi for_each_possible_cpu(i) 131976d7d3fSLorenzo Pieralisi mask |= (cpu_logical_map(i) ^ cpu_logical_map(0)); 132976d7d3fSLorenzo Pieralisi pr_debug("mask of set bits %#llx\n", mask); 133976d7d3fSLorenzo Pieralisi /* 134976d7d3fSLorenzo Pieralisi * Find and stash the last and first bit set at all affinity levels to 135976d7d3fSLorenzo Pieralisi * check how many bits are required to represent them. 136976d7d3fSLorenzo Pieralisi */ 137976d7d3fSLorenzo Pieralisi for (i = 0; i < 4; i++) { 138976d7d3fSLorenzo Pieralisi affinity = MPIDR_AFFINITY_LEVEL(mask, i); 139976d7d3fSLorenzo Pieralisi /* 140976d7d3fSLorenzo Pieralisi * Find the MSB bit and LSB bits position 141976d7d3fSLorenzo Pieralisi * to determine how many bits are required 142976d7d3fSLorenzo Pieralisi * to express the affinity level. 143976d7d3fSLorenzo Pieralisi */ 144976d7d3fSLorenzo Pieralisi ls = fls(affinity); 145976d7d3fSLorenzo Pieralisi fs[i] = affinity ? ffs(affinity) - 1 : 0; 146976d7d3fSLorenzo Pieralisi bits[i] = ls - fs[i]; 147976d7d3fSLorenzo Pieralisi } 148976d7d3fSLorenzo Pieralisi /* 149976d7d3fSLorenzo Pieralisi * An index can be created from the MPIDR_EL1 by isolating the 150976d7d3fSLorenzo Pieralisi * significant bits at each affinity level and by shifting 151976d7d3fSLorenzo Pieralisi * them in order to compress the 32 bits values space to a 152976d7d3fSLorenzo Pieralisi * compressed set of values. This is equivalent to hashing 153976d7d3fSLorenzo Pieralisi * the MPIDR_EL1 through shifting and ORing. It is a collision free 154976d7d3fSLorenzo Pieralisi * hash though not minimal since some levels might contain a number 155976d7d3fSLorenzo Pieralisi * of CPUs that is not an exact power of 2 and their bit 156976d7d3fSLorenzo Pieralisi * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}. 157976d7d3fSLorenzo Pieralisi */ 158976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0]; 159976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0]; 160976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] - 161976d7d3fSLorenzo Pieralisi (bits[1] + bits[0]); 162976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) + 163976d7d3fSLorenzo Pieralisi fs[3] - (bits[2] + bits[1] + bits[0]); 164976d7d3fSLorenzo Pieralisi mpidr_hash.mask = mask; 165976d7d3fSLorenzo Pieralisi mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0]; 166976d7d3fSLorenzo Pieralisi pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n", 167976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[0], 168976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[1], 169976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[2], 170976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[3], 171976d7d3fSLorenzo Pieralisi mpidr_hash.mask, 172976d7d3fSLorenzo Pieralisi mpidr_hash.bits); 173976d7d3fSLorenzo Pieralisi /* 174976d7d3fSLorenzo Pieralisi * 4x is an arbitrary value used to warn on a hash table much bigger 175976d7d3fSLorenzo Pieralisi * than expected on most systems. 176976d7d3fSLorenzo Pieralisi */ 177976d7d3fSLorenzo Pieralisi if (mpidr_hash_size() > 4 * num_possible_cpus()) 178976d7d3fSLorenzo Pieralisi pr_warn("Large number of MPIDR hash buckets detected\n"); 179976d7d3fSLorenzo Pieralisi } 180137650aaSMark Rutland 1819703d9d7SCatalin Marinas static void __init setup_machine_fdt(phys_addr_t dt_phys) 1829703d9d7SCatalin Marinas { 18361bd93ceSArd Biesheuvel void *dt_virt = fixmap_remap_fdt(dt_phys); 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 19644b82b77SMark Rutland dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name()); 1979703d9d7SCatalin Marinas } 1989703d9d7SCatalin Marinas 1999703d9d7SCatalin Marinas static void __init request_standard_resources(void) 2009703d9d7SCatalin Marinas { 2019703d9d7SCatalin Marinas struct memblock_region *region; 2029703d9d7SCatalin Marinas struct resource *res; 2039703d9d7SCatalin Marinas 2049703d9d7SCatalin Marinas kernel_code.start = virt_to_phys(_text); 2059fdc14c5SArd Biesheuvel kernel_code.end = virt_to_phys(__init_begin - 1); 2069703d9d7SCatalin Marinas kernel_data.start = virt_to_phys(_sdata); 2079703d9d7SCatalin Marinas kernel_data.end = virt_to_phys(_end - 1); 2089703d9d7SCatalin Marinas 2099703d9d7SCatalin Marinas for_each_memblock(memory, region) { 2109703d9d7SCatalin Marinas res = alloc_bootmem_low(sizeof(*res)); 2119703d9d7SCatalin Marinas res->name = "System RAM"; 2129703d9d7SCatalin Marinas res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 2139703d9d7SCatalin Marinas res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 21435d98e93SToshi Kani res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 2159703d9d7SCatalin Marinas 2169703d9d7SCatalin Marinas request_resource(&iomem_resource, res); 2179703d9d7SCatalin Marinas 2189703d9d7SCatalin Marinas if (kernel_code.start >= res->start && 2199703d9d7SCatalin Marinas kernel_code.end <= res->end) 2209703d9d7SCatalin Marinas request_resource(res, &kernel_code); 2219703d9d7SCatalin Marinas if (kernel_data.start >= res->start && 2229703d9d7SCatalin Marinas kernel_data.end <= res->end) 2239703d9d7SCatalin Marinas request_resource(res, &kernel_data); 2249703d9d7SCatalin Marinas } 2259703d9d7SCatalin Marinas } 2269703d9d7SCatalin Marinas 2274c7aa002SJavi Merino u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID }; 2284c7aa002SJavi Merino 2299703d9d7SCatalin Marinas void __init setup_arch(char **cmdline_p) 2309703d9d7SCatalin Marinas { 2314b998ff1SSuzuki K. Poulose pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id()); 2329703d9d7SCatalin Marinas 2334b998ff1SSuzuki K. Poulose sprintf(init_utsname()->machine, ELF_PLATFORM); 2349703d9d7SCatalin Marinas init_mm.start_code = (unsigned long) _text; 2359703d9d7SCatalin Marinas init_mm.end_code = (unsigned long) _etext; 2369703d9d7SCatalin Marinas init_mm.end_data = (unsigned long) _edata; 2379703d9d7SCatalin Marinas init_mm.brk = (unsigned long) _end; 2389703d9d7SCatalin Marinas 2399703d9d7SCatalin Marinas *cmdline_p = boot_command_line; 2409703d9d7SCatalin Marinas 241af86e597SLaura Abbott early_fixmap_init(); 242bf4b558eSMark Salter early_ioremap_init(); 2430bf757c7SMark Salter 24461bd93ceSArd Biesheuvel setup_machine_fdt(__fdt_pointer); 24561bd93ceSArd Biesheuvel 2469703d9d7SCatalin Marinas parse_early_param(); 2479703d9d7SCatalin Marinas 2487a9c43beSJon Masters /* 2497a9c43beSJon Masters * Unmask asynchronous aborts after bringing up possible earlycon. 2507a9c43beSJon Masters * (Report possible System Errors once we can report this occurred) 2517a9c43beSJon Masters */ 2527a9c43beSJon Masters local_async_enable(); 2537a9c43beSJon Masters 25486ccce89SMark Rutland /* 25586ccce89SMark Rutland * TTBR0 is only used for the identity mapping at this stage. Make it 25686ccce89SMark Rutland * point to zero page to avoid speculatively fetching new entries. 25786ccce89SMark Rutland */ 25886ccce89SMark Rutland cpu_uninstall_idmap(); 25986ccce89SMark Rutland 260f84d0275SMark Salter efi_init(); 2619703d9d7SCatalin Marinas arm64_memblock_init(); 2629703d9d7SCatalin Marinas 26337655163SAl Stone /* Parse the ACPI tables for possible boot-time configuration */ 26437655163SAl Stone acpi_boot_table_init(); 26537655163SAl Stone 2669703d9d7SCatalin Marinas paging_init(); 26739d114ddSAndrey Ryabinin 2683194ac6eSDavid Daney if (acpi_disabled) 2693194ac6eSDavid Daney unflatten_device_tree(); 2703194ac6eSDavid Daney 2713194ac6eSDavid Daney bootmem_init(); 2723194ac6eSDavid Daney 27339d114ddSAndrey Ryabinin kasan_init(); 27439d114ddSAndrey Ryabinin 2759703d9d7SCatalin Marinas request_standard_resources(); 2769703d9d7SCatalin Marinas 2770e63ea48SArd Biesheuvel early_ioremap_reset(); 278f84d0275SMark Salter 2793194ac6eSDavid Daney if (acpi_disabled) 2807c59a3dfSGraeme Gregory psci_dt_init(); 2813194ac6eSDavid Daney else 282fccb9a81SHanjun Guo psci_acpi_init(); 2833194ac6eSDavid Daney 2845882bfefSStefano Stabellini xen_early_init(); 285fccb9a81SHanjun Guo 2860f078336SLorenzo Pieralisi cpu_read_bootcpu_ops(); 2870f078336SLorenzo Pieralisi smp_init_cpus(); 288976d7d3fSLorenzo Pieralisi smp_build_mpidr_hash(); 2899703d9d7SCatalin Marinas 2909703d9d7SCatalin Marinas #ifdef CONFIG_VT 2919703d9d7SCatalin Marinas #if defined(CONFIG_VGA_CONSOLE) 2929703d9d7SCatalin Marinas conswitchp = &vga_con; 2939703d9d7SCatalin Marinas #elif defined(CONFIG_DUMMY_CONSOLE) 2949703d9d7SCatalin Marinas conswitchp = &dummy_con; 2959703d9d7SCatalin Marinas #endif 2969703d9d7SCatalin Marinas #endif 297da9c177dSArd Biesheuvel if (boot_args[1] || boot_args[2] || boot_args[3]) { 298da9c177dSArd Biesheuvel pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n" 299da9c177dSArd Biesheuvel "\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n" 300da9c177dSArd Biesheuvel "This indicates a broken bootloader or old kernel\n", 301da9c177dSArd Biesheuvel boot_args[1], boot_args[2], boot_args[3]); 302da9c177dSArd Biesheuvel } 3039703d9d7SCatalin Marinas } 3049703d9d7SCatalin Marinas 305c560ecfeSCatalin Marinas static int __init arm64_device_init(void) 306de79a64dSCatalin Marinas { 307e094d445SSudeep Holla if (of_have_populated_dt()) { 30878d51e0bSRobin Murphy of_iommu_init(); 309e094d445SSudeep Holla of_platform_populate(NULL, of_default_bus_match_table, 310e094d445SSudeep Holla NULL, NULL); 311e094d445SSudeep Holla } else if (acpi_disabled) { 312e094d445SSudeep Holla pr_crit("Device tree not populated\n"); 313e094d445SSudeep Holla } 314de79a64dSCatalin Marinas return 0; 315de79a64dSCatalin Marinas } 3166ecba8ebSCatalin Marinas arch_initcall_sync(arm64_device_init); 317de79a64dSCatalin Marinas 3189703d9d7SCatalin Marinas static int __init topology_init(void) 3199703d9d7SCatalin Marinas { 3209703d9d7SCatalin Marinas int i; 3219703d9d7SCatalin Marinas 3221a2db300SGanapatrao Kulkarni for_each_online_node(i) 3231a2db300SGanapatrao Kulkarni register_one_node(i); 3241a2db300SGanapatrao Kulkarni 3259703d9d7SCatalin Marinas for_each_possible_cpu(i) { 326df857416SMark Rutland struct cpu *cpu = &per_cpu(cpu_data.cpu, i); 3279703d9d7SCatalin Marinas cpu->hotpluggable = 1; 3289703d9d7SCatalin Marinas register_cpu(cpu, i); 3299703d9d7SCatalin Marinas } 3309703d9d7SCatalin Marinas 3319703d9d7SCatalin Marinas return 0; 3329703d9d7SCatalin Marinas } 3339703d9d7SCatalin Marinas subsys_initcall(topology_init); 334f80fb3a3SArd Biesheuvel 335f80fb3a3SArd Biesheuvel /* 336f80fb3a3SArd Biesheuvel * Dump out kernel offset information on panic. 337f80fb3a3SArd Biesheuvel */ 338f80fb3a3SArd Biesheuvel static int dump_kernel_offset(struct notifier_block *self, unsigned long v, 339f80fb3a3SArd Biesheuvel void *p) 340f80fb3a3SArd Biesheuvel { 341f80fb3a3SArd Biesheuvel u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR; 342f80fb3a3SArd Biesheuvel 343f80fb3a3SArd Biesheuvel if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) { 344f80fb3a3SArd Biesheuvel pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n", 345f80fb3a3SArd Biesheuvel kaslr_offset, KIMAGE_VADDR); 346f80fb3a3SArd Biesheuvel } else { 347f80fb3a3SArd Biesheuvel pr_emerg("Kernel Offset: disabled\n"); 348f80fb3a3SArd Biesheuvel } 349f80fb3a3SArd Biesheuvel return 0; 350f80fb3a3SArd Biesheuvel } 351f80fb3a3SArd Biesheuvel 352f80fb3a3SArd Biesheuvel static struct notifier_block kernel_offset_notifier = { 353f80fb3a3SArd Biesheuvel .notifier_call = dump_kernel_offset 354f80fb3a3SArd Biesheuvel }; 355f80fb3a3SArd Biesheuvel 356f80fb3a3SArd Biesheuvel static int __init register_kernel_offset_dumper(void) 357f80fb3a3SArd Biesheuvel { 358f80fb3a3SArd Biesheuvel atomic_notifier_chain_register(&panic_notifier_list, 359f80fb3a3SArd Biesheuvel &kernel_offset_notifier); 360f80fb3a3SArd Biesheuvel return 0; 361f80fb3a3SArd Biesheuvel } 362f80fb3a3SArd Biesheuvel __initcall(register_kernel_offset_dumper); 363