Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Code to handle transition of Linux booting another kernel.
0004  *
0005  * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
0006  * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
0007  * Copyright (C) 2005 IBM Corporation.
0008  */
0009 
0010 #include <linux/kexec.h>
0011 #include <linux/reboot.h>
0012 #include <linux/threads.h>
0013 #include <linux/memblock.h>
0014 #include <linux/of.h>
0015 #include <linux/irq.h>
0016 #include <linux/ftrace.h>
0017 
0018 #include <asm/kdump.h>
0019 #include <asm/machdep.h>
0020 #include <asm/pgalloc.h>
0021 #include <asm/sections.h>
0022 #include <asm/setup.h>
0023 #include <asm/firmware.h>
0024 
0025 void machine_kexec_mask_interrupts(void) {
0026     unsigned int i;
0027     struct irq_desc *desc;
0028 
0029     for_each_irq_desc(i, desc) {
0030         struct irq_chip *chip;
0031 
0032         chip = irq_desc_get_chip(desc);
0033         if (!chip)
0034             continue;
0035 
0036         if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data))
0037             chip->irq_eoi(&desc->irq_data);
0038 
0039         if (chip->irq_mask)
0040             chip->irq_mask(&desc->irq_data);
0041 
0042         if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data))
0043             chip->irq_disable(&desc->irq_data);
0044     }
0045 }
0046 
0047 void machine_crash_shutdown(struct pt_regs *regs)
0048 {
0049     default_machine_crash_shutdown(regs);
0050 }
0051 
0052 void machine_kexec_cleanup(struct kimage *image)
0053 {
0054 }
0055 
0056 void arch_crash_save_vmcoreinfo(void)
0057 {
0058 
0059 #ifdef CONFIG_NUMA
0060     VMCOREINFO_SYMBOL(node_data);
0061     VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
0062 #endif
0063 #ifndef CONFIG_NUMA
0064     VMCOREINFO_SYMBOL(contig_page_data);
0065 #endif
0066 #if defined(CONFIG_PPC64) && defined(CONFIG_SPARSEMEM_VMEMMAP)
0067     VMCOREINFO_SYMBOL(vmemmap_list);
0068     VMCOREINFO_SYMBOL(mmu_vmemmap_psize);
0069     VMCOREINFO_SYMBOL(mmu_psize_defs);
0070     VMCOREINFO_STRUCT_SIZE(vmemmap_backing);
0071     VMCOREINFO_OFFSET(vmemmap_backing, list);
0072     VMCOREINFO_OFFSET(vmemmap_backing, phys);
0073     VMCOREINFO_OFFSET(vmemmap_backing, virt_addr);
0074     VMCOREINFO_STRUCT_SIZE(mmu_psize_def);
0075     VMCOREINFO_OFFSET(mmu_psize_def, shift);
0076 #endif
0077     vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
0078 }
0079 
0080 /*
0081  * Do not allocate memory (or fail in any way) in machine_kexec().
0082  * We are past the point of no return, committed to rebooting now.
0083  */
0084 void machine_kexec(struct kimage *image)
0085 {
0086     int save_ftrace_enabled;
0087 
0088     save_ftrace_enabled = __ftrace_enabled_save();
0089     this_cpu_disable_ftrace();
0090 
0091     if (ppc_md.machine_kexec)
0092         ppc_md.machine_kexec(image);
0093     else
0094         default_machine_kexec(image);
0095 
0096     this_cpu_enable_ftrace();
0097     __ftrace_enabled_restore(save_ftrace_enabled);
0098 
0099     /* Fall back to normal restart if we're still alive. */
0100     machine_restart(NULL);
0101     for(;;);
0102 }
0103 
0104 void __init reserve_crashkernel(void)
0105 {
0106     unsigned long long crash_size, crash_base, total_mem_sz;
0107     int ret;
0108 
0109     total_mem_sz = memory_limit ? memory_limit : memblock_phys_mem_size();
0110     /* use common parsing */
0111     ret = parse_crashkernel(boot_command_line, total_mem_sz,
0112             &crash_size, &crash_base);
0113     if (ret == 0 && crash_size > 0) {
0114         crashk_res.start = crash_base;
0115         crashk_res.end = crash_base + crash_size - 1;
0116     }
0117 
0118     if (crashk_res.end == crashk_res.start) {
0119         crashk_res.start = crashk_res.end = 0;
0120         return;
0121     }
0122 
0123     /* We might have got these values via the command line or the
0124      * device tree, either way sanitise them now. */
0125 
0126     crash_size = resource_size(&crashk_res);
0127 
0128 #ifndef CONFIG_NONSTATIC_KERNEL
0129     if (crashk_res.start != KDUMP_KERNELBASE)
0130         printk("Crash kernel location must be 0x%x\n",
0131                 KDUMP_KERNELBASE);
0132 
0133     crashk_res.start = KDUMP_KERNELBASE;
0134 #else
0135     if (!crashk_res.start) {
0136 #ifdef CONFIG_PPC64
0137         /*
0138          * On the LPAR platform place the crash kernel to mid of
0139          * RMA size (512MB or more) to ensure the crash kernel
0140          * gets enough space to place itself and some stack to be
0141          * in the first segment. At the same time normal kernel
0142          * also get enough space to allocate memory for essential
0143          * system resource in the first segment. Keep the crash
0144          * kernel starts at 128MB offset on other platforms.
0145          */
0146         if (firmware_has_feature(FW_FEATURE_LPAR))
0147             crashk_res.start = ppc64_rma_size / 2;
0148         else
0149             crashk_res.start = min(0x8000000ULL, (ppc64_rma_size / 2));
0150 #else
0151         crashk_res.start = KDUMP_KERNELBASE;
0152 #endif
0153     }
0154 
0155     crash_base = PAGE_ALIGN(crashk_res.start);
0156     if (crash_base != crashk_res.start) {
0157         printk("Crash kernel base must be aligned to 0x%lx\n",
0158                 PAGE_SIZE);
0159         crashk_res.start = crash_base;
0160     }
0161 
0162 #endif
0163     crash_size = PAGE_ALIGN(crash_size);
0164     crashk_res.end = crashk_res.start + crash_size - 1;
0165 
0166     /* The crash region must not overlap the current kernel */
0167     if (overlaps_crashkernel(__pa(_stext), _end - _stext)) {
0168         printk(KERN_WARNING
0169             "Crash kernel can not overlap current kernel\n");
0170         crashk_res.start = crashk_res.end = 0;
0171         return;
0172     }
0173 
0174     /* Crash kernel trumps memory limit */
0175     if (memory_limit && memory_limit <= crashk_res.end) {
0176         memory_limit = crashk_res.end + 1;
0177         total_mem_sz = memory_limit;
0178         printk("Adjusted memory limit for crashkernel, now 0x%llx\n",
0179                memory_limit);
0180     }
0181 
0182     printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
0183             "for crashkernel (System RAM: %ldMB)\n",
0184             (unsigned long)(crash_size >> 20),
0185             (unsigned long)(crashk_res.start >> 20),
0186             (unsigned long)(total_mem_sz >> 20));
0187 
0188     if (!memblock_is_region_memory(crashk_res.start, crash_size) ||
0189         memblock_reserve(crashk_res.start, crash_size)) {
0190         pr_err("Failed to reserve memory for crashkernel!\n");
0191         crashk_res.start = crashk_res.end = 0;
0192         return;
0193     }
0194 }
0195 
0196 int __init overlaps_crashkernel(unsigned long start, unsigned long size)
0197 {
0198     return (start + size) > crashk_res.start && start <= crashk_res.end;
0199 }
0200 
0201 /* Values we need to export to the second kernel via the device tree. */
0202 static phys_addr_t kernel_end;
0203 static phys_addr_t crashk_base;
0204 static phys_addr_t crashk_size;
0205 static unsigned long long mem_limit;
0206 
0207 static struct property kernel_end_prop = {
0208     .name = "linux,kernel-end",
0209     .length = sizeof(phys_addr_t),
0210     .value = &kernel_end,
0211 };
0212 
0213 static struct property crashk_base_prop = {
0214     .name = "linux,crashkernel-base",
0215     .length = sizeof(phys_addr_t),
0216     .value = &crashk_base
0217 };
0218 
0219 static struct property crashk_size_prop = {
0220     .name = "linux,crashkernel-size",
0221     .length = sizeof(phys_addr_t),
0222     .value = &crashk_size,
0223 };
0224 
0225 static struct property memory_limit_prop = {
0226     .name = "linux,memory-limit",
0227     .length = sizeof(unsigned long long),
0228     .value = &mem_limit,
0229 };
0230 
0231 #define cpu_to_be_ulong __PASTE(cpu_to_be, BITS_PER_LONG)
0232 
0233 static void __init export_crashk_values(struct device_node *node)
0234 {
0235     /* There might be existing crash kernel properties, but we can't
0236      * be sure what's in them, so remove them. */
0237     of_remove_property(node, of_find_property(node,
0238                 "linux,crashkernel-base", NULL));
0239     of_remove_property(node, of_find_property(node,
0240                 "linux,crashkernel-size", NULL));
0241 
0242     if (crashk_res.start != 0) {
0243         crashk_base = cpu_to_be_ulong(crashk_res.start),
0244         of_add_property(node, &crashk_base_prop);
0245         crashk_size = cpu_to_be_ulong(resource_size(&crashk_res));
0246         of_add_property(node, &crashk_size_prop);
0247     }
0248 
0249     /*
0250      * memory_limit is required by the kexec-tools to limit the
0251      * crash regions to the actual memory used.
0252      */
0253     mem_limit = cpu_to_be_ulong(memory_limit);
0254     of_update_property(node, &memory_limit_prop);
0255 }
0256 
0257 static int __init kexec_setup(void)
0258 {
0259     struct device_node *node;
0260 
0261     node = of_find_node_by_path("/chosen");
0262     if (!node)
0263         return -ENOENT;
0264 
0265     /* remove any stale properties so ours can be found */
0266     of_remove_property(node, of_find_property(node, kernel_end_prop.name, NULL));
0267 
0268     /* information needed by userspace when using default_machine_kexec */
0269     kernel_end = cpu_to_be_ulong(__pa(_end));
0270     of_add_property(node, &kernel_end_prop);
0271 
0272     export_crashk_values(node);
0273 
0274     of_node_put(node);
0275     return 0;
0276 }
0277 late_initcall(kexec_setup);