mirror of
https://github.com/torvalds/linux.git
synced 2024-12-22 10:56:40 +00:00
abf015f046
This reverts commit 2b034922af
.
Will Deacon reports:
This is causing kexec to fail.
The symptoms are that the .init.text section is not loaded as part of the
new kernel image, so when we try to do the SMP/UP fixups we hit a whole sea
of poison left there by the previous kernel.
So my guess is that machine_kexec_prepare *is* too early for preparing the
reboot_code_buffer and, unless anybody has a good reason not to, I'd like to
revert the patch causing these problems.
Reported-by: Will Deacon <will.deacon@arm.com>
125 lines
3.2 KiB
C
125 lines
3.2 KiB
C
/*
|
|
* machine_kexec.c - handle transition of Linux booting another kernel
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/kexec.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/io.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/mmu_context.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/mach-types.h>
|
|
|
|
extern const unsigned char relocate_new_kernel[];
|
|
extern const unsigned int relocate_new_kernel_size;
|
|
|
|
extern void setup_mm_for_reboot(char mode);
|
|
|
|
extern unsigned long kexec_start_address;
|
|
extern unsigned long kexec_indirection_page;
|
|
extern unsigned long kexec_mach_type;
|
|
extern unsigned long kexec_boot_atags;
|
|
|
|
static atomic_t waiting_for_crash_ipi;
|
|
|
|
/*
|
|
* Provide a dummy crash_notes definition while crash dump arrives to arm.
|
|
* This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
|
|
*/
|
|
|
|
int machine_kexec_prepare(struct kimage *image)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void machine_kexec_cleanup(struct kimage *image)
|
|
{
|
|
}
|
|
|
|
void machine_crash_nonpanic_core(void *unused)
|
|
{
|
|
struct pt_regs regs;
|
|
|
|
crash_setup_regs(®s, NULL);
|
|
printk(KERN_DEBUG "CPU %u will stop doing anything useful since another CPU has crashed\n",
|
|
smp_processor_id());
|
|
crash_save_cpu(®s, smp_processor_id());
|
|
flush_cache_all();
|
|
|
|
atomic_dec(&waiting_for_crash_ipi);
|
|
while (1)
|
|
cpu_relax();
|
|
}
|
|
|
|
void machine_crash_shutdown(struct pt_regs *regs)
|
|
{
|
|
unsigned long msecs;
|
|
|
|
local_irq_disable();
|
|
|
|
atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
|
|
smp_call_function(machine_crash_nonpanic_core, NULL, false);
|
|
msecs = 1000; /* Wait at most a second for the other cpus to stop */
|
|
while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
|
|
mdelay(1);
|
|
msecs--;
|
|
}
|
|
if (atomic_read(&waiting_for_crash_ipi) > 0)
|
|
printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n");
|
|
|
|
crash_save_cpu(regs, smp_processor_id());
|
|
|
|
printk(KERN_INFO "Loading crashdump kernel...\n");
|
|
}
|
|
|
|
/*
|
|
* Function pointer to optional machine-specific reinitialization
|
|
*/
|
|
void (*kexec_reinit)(void);
|
|
|
|
void machine_kexec(struct kimage *image)
|
|
{
|
|
unsigned long page_list;
|
|
unsigned long reboot_code_buffer_phys;
|
|
void *reboot_code_buffer;
|
|
|
|
|
|
page_list = image->head & PAGE_MASK;
|
|
|
|
/* we need both effective and real address here */
|
|
reboot_code_buffer_phys =
|
|
page_to_pfn(image->control_code_page) << PAGE_SHIFT;
|
|
reboot_code_buffer = page_address(image->control_code_page);
|
|
|
|
/* Prepare parameters for reboot_code_buffer*/
|
|
kexec_start_address = image->start;
|
|
kexec_indirection_page = page_list;
|
|
kexec_mach_type = machine_arch_type;
|
|
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
|
|
|
|
/* copy our kernel relocation code to the control code page */
|
|
memcpy(reboot_code_buffer,
|
|
relocate_new_kernel, relocate_new_kernel_size);
|
|
|
|
|
|
flush_icache_range((unsigned long) reboot_code_buffer,
|
|
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
|
|
printk(KERN_INFO "Bye!\n");
|
|
|
|
if (kexec_reinit)
|
|
kexec_reinit();
|
|
local_irq_disable();
|
|
local_fiq_disable();
|
|
setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
|
|
flush_cache_all();
|
|
outer_flush_all();
|
|
outer_disable();
|
|
cpu_proc_fin();
|
|
outer_inv_all();
|
|
flush_cache_all();
|
|
cpu_reset(reboot_code_buffer_phys);
|
|
}
|