Skip to content

Instantly share code, notes, and snippets.

@alvinhochun
Created December 13, 2013 14:53
Show Gist options
  • Save alvinhochun/7945428 to your computer and use it in GitHub Desktop.
Save alvinhochun/7945428 to your computer and use it in GitHub Desktop.

Revisions

  1. alvinhochun created this gist Dec 13, 2013.
    608 changes: 608 additions & 0 deletions kexec-hardboot.patch
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,608 @@
    From 2e818d81f21f6a627bc629e477052045426b0663 Mon Sep 17 00:00:00 2001
    From: Alvin Wong <[email protected]>
    Date: Fri, 13 Dec 2013 22:19:52 +0800
    Subject: [PATCH] Implement kexec-hardboot

    This allows performing kexec with a full hardware reboot so that the "guest"
    kernel does not have to worry about reinitializing hardware states.

    I've ported the patch to this Xperia M stock kernel. The hardboot page is
    located at 0x88000000, which is exactly 1MiB below the ram_console.

    I've tested kexec hardboot with the following parameters:
    --mem-min=0x85000000 --mem-max=0x87ffffff

    Keep in mind that normally, the bootloader will append parameters (e.g. IMEI)
    to the cmdline, but doing kexec will require manually appending them.

    Here is a sample script that uses `sed` to do the work:

    - https://gist.github.com/alvinhochun/7945270

    Please refer to the following links for more information:

    - https://gist.github.com/Tasssadar/6766757
    - http://forum.xda-developers.com/showthread.php?p=46223952

    Original author: Mike Kasick <[email protected]>

    Vojtech Bocek <[email protected]>:
    I've ported it to mako and flo, it is based of my grouper port, which is
    based of Asus TF201 patche ported by Jens Andersen <[email protected]>

    I've moved atags copying from guest to the host kernel, which means there
    is no need to patch the guest kernel, assuming the --mem-min in kexec call
    is within the first 256MB of System RAM, otherwise it will take a long time
    to load. I've also fixed /proc/atags entry, which would give the kexec-tools
    userspace binary only the first 1024 bytes of atags,
    see arch/arm/kernel/atags.c for more details.

    Other than that, memory-reservation code for the hardboot page and
    some assembler to do the watchdog reset on MSM chip are new for this device.

    ayysir <[email protected]>:
    kexec: use mem_text_write_kernel_word to set reboot_code_buffer args
    in order to avoid protection faults (writes to read-only
    kernel memory) when CONFIG_STRICT_MEMORY_RWX is enabled.
    ---
    arch/arm/Kconfig | 26 +++++++++
    arch/arm/boot/compressed/head.S | 96 +++++++++++++++++++++++++++++++
    arch/arm/include/asm/kexec.h | 8 +++
    arch/arm/kernel/atags.c | 51 ++++++++++------
    arch/arm/kernel/machine_kexec.c | 22 +++++--
    arch/arm/kernel/relocate_kernel.S | 47 +++++++++++++++
    arch/arm/mach-msm/board-8930.c | 11 ++++
    arch/arm/mach-msm/include/mach/memory.h | 8 +++
    arch/arm/mach-msm/restart.c | 16 ++++++
    include/linux/kexec.h | 19 +++++-
    kernel/crash_notes.c | 2 +-
    kernel/kexec.c | 4 ++
    12 files changed, 285 insertions(+), 25 deletions(-)

    diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
    index 8b31d48..731bc97 100644
    --- a/arch/arm/Kconfig
    +++ b/arch/arm/Kconfig
    @@ -2117,6 +2117,32 @@ config ATAGS_PROC
    Should the atags used to boot the kernel be exported in an "atags"
    file in procfs. Useful with kexec.

    +config KEXEC_HARDBOOT
    + bool "Support hard booting to a kexec kernel"
    + depends on KEXEC
    + help
    + Allows hard booting (i.e., with a full hardware reboot) to a kernel
    + previously loaded in memory by kexec. This works around the problem of
    + soft-booted kernel hangs due to improper device shutdown and/or
    + reinitialization. Support is comprised of two components:
    +
    + First, a "hardboot" flag is added to the kexec syscall to force a hard
    + reboot in relocate_new_kernel() (which requires machine-specific assembly
    + code). This also requires the kexec userspace tool to load the kexec'd
    + kernel in memory region left untouched by the bootloader (i.e., not
    + explicitly cleared and not overwritten by the boot kernel). Just prior
    + to reboot, the kexec kernel arguments are stashed in a machine-specific
    + memory page that must also be preserved. Note that this hardboot page
    + need not be reserved during regular kernel execution.
    +
    + Second, the zImage decompresor of the boot (bootloader-loaded) kernel is
    + modified to check the hardboot page for fresh kexec arguments, and if
    + present, attempts to jump to the kexec'd kernel preserved in memory.
    +
    + Note that hardboot support is only required in the boot kernel and any
    + kernel capable of performing a hardboot kexec. It is _not_ required by a
    + kexec'd kernel.
    +
    config CRASH_DUMP
    bool "Build kdump crash kernel (EXPERIMENTAL)"
    depends on EXPERIMENTAL
    diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
    index 64a6d6f..c7f1e64 100644
    --- a/arch/arm/boot/compressed/head.S
    +++ b/arch/arm/boot/compressed/head.S
    @@ -10,6 +10,11 @@
    */
    #include <linux/linkage.h>

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + #include <asm/kexec.h>
    + #include <asm/memory.h>
    +#endif
    +
    /*
    * Debugging stuff
    *
    @@ -135,6 +140,97 @@ start:
    1: mov r7, r1 @ save architecture ID
    mov r8, r2 @ save atags pointer

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + /* Check hardboot page for a kexec kernel. */
    + ldr r3, =KEXEC_HB_PAGE_ADDR
    + ldr r0, [r3]
    + ldr r1, =KEXEC_HB_PAGE_MAGIC
    + teq r0, r1
    + bne not_booting_other
    +
    + /* Clear hardboot page magic to avoid boot loop. */
    + mov r0, #0
    + str r0, [r3]
    +
    +/* Copy the kernel tagged list (atags):
    + *
    + * The kernel requires atags to be located in a direct-mapped region,
    + * usually below the kernel in the first 16 kB of RAM. If they're above
    + * (the start of) the kernel, they need to be copied to a suitable
    + * location, e.g., the machine-defined params_phys.
    + *
    + * The assumption is that the tags will only be "out of place" if the
    + * decompressor code is also, so copying is implemented only in the "won't
    + * overwrite" case (which should be fixed). Still need to make sure that
    + * the copied tags don't overwrite either the kernel or decompressor code
    + * (or rather, the remainder of it since everything up to here has already
    + * been executed).
    + *
    + * Vojtech Bocek <[email protected]>: I've moved atags copying from guest
    + * kernel to the host and rewrote it from C to assembler in order to remove
    + * the need for guest kernel to be patched. I don't know assembler very well,
    + * so it doesn't look very good and I have no idea if I didn't accidentally
    + * break something, causing problems down the road. It's worked every time
    + * and I didn't notice any problems so far though.
    + *
    + * r4: zreladdr (kernel start)
    + * r8: kexec_boot_atags
    + * r2: boot_atags */
    + ldr r8, [r3, #12] @ kexec_boot_atags (r2: boot_atags)
    + ldr r4, =zreladdr @ zreladdr
    +
    + /* No need to copy atags if they're already below kernel */
    + cmp r8, r4
    + blo no_atags_cpy
    +
    + /* r0: min(zreladdr, pc) */
    + mov r0, pc
    + cmp r4, r0
    + movlo r0, r4
    +
    + /* Compute max space for atags, if max <= 0 don't copy. */
    + subs r5, r0, r2 @ max = min(zreladdr, pc) - dest
    + bls no_atags_cpy
    +
    + /* Copy atags to params_phys. */
    + /* r8 src, r2 dest, r5 max */
    +
    + ldr r0, [r8] @ first tag size
    + cmp r0, #0
    + moveq r4, #8
    + beq catags_empty
    + mov r4, r8
    +
    +catags_foreach:
    + lsl r0, r0, #2 @ Multiply by 4
    + ldr r0, [r4, r0]! @ Load next tag size to r0 and address to r4
    + cmp r0, #0
    + bne catags_foreach
    +
    + rsb r4, r8, r4 @ r4 -= r8 (get only size)
    + add r4, r4, #8 @ add size of the last tag
    +catags_empty:
    + cmp r5, r4 @ if(max <= size)
    + bcc no_atags_cpy
    +
    + mov r5, #0 @ iterator
    +catags_cpy:
    + ldr r0, [r8, r5]
    + str r0, [r2, r5]
    + add r5, r5, #4
    + cmp r5, r4
    + blo catags_cpy
    +
    +no_atags_cpy:
    + /* Load boot arguments and jump to kexec kernel. */
    + ldr r1, [r3, #8] @ kexec_mach_type
    + ldr pc, [r3, #4] @ kexec_start_address
    +
    + .ltorg
    +
    +not_booting_other:
    +#endif
    +
    #ifndef __ARM_ARCH_2__
    /*
    * Booting from Angel - need to enter SVC mode and disable
    diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
    index c2b9b4b..564c55b 100644
    --- a/arch/arm/include/asm/kexec.h
    +++ b/arch/arm/include/asm/kexec.h
    @@ -17,6 +17,10 @@
    #define KEXEC_ARM_ATAGS_OFFSET 0x1000
    #define KEXEC_ARM_ZIMAGE_OFFSET 0x8000

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + #define KEXEC_HB_PAGE_MAGIC 0x4a5db007
    +#endif
    +
    #ifndef __ASSEMBLY__

    /**
    @@ -53,6 +57,10 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
    /* Function pointer to optional machine-specific reinitialization */
    extern void (*kexec_reinit)(void);

    +#ifdef CONFIG_KEXEC_HARDBOOT
    +extern void (*kexec_hardboot_hook)(void);
    +#endif
    +
    #endif /* __ASSEMBLY__ */

    #endif /* CONFIG_KEXEC */
    diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c
    index 42a1a14..0cfd7e4 100644
    --- a/arch/arm/kernel/atags.c
    +++ b/arch/arm/kernel/atags.c
    @@ -4,29 +4,45 @@
    #include <asm/types.h>
    #include <asm/page.h>

    +/*
    + * [PATCH] Backport arch/arm/kernel/atags.c from 3.10
    + *
    + * There is a bug in older kernels, causing kexec-tools binary to
    + * only read first 1024 bytes from /proc/atags. I guess the bug is
    + * somewhere in /fs/proc/, since I don't think the callback in atags.c
    + * does something wrong. It might affect all procfs files using that
    + * old read callback instead of fops. Doesn't matter though, since it
    + * was accidentally fixed when 3.10 removed it.
    + *
    + * This might have no particular effect on real devices, because the
    + * atags _might_ be organized "just right", but it might be very hard
    + * to track down on a device where it causes problems.
    + *
    + */
    +
    struct buffer {
    size_t size;
    char data[];
    };

    -static int
    -read_buffer(char* page, char** start, off_t off, int count,
    - int* eof, void* data)
    -{
    - struct buffer *buffer = (struct buffer *)data;
    -
    - if (off >= buffer->size) {
    - *eof = 1;
    - return 0;
    - }
    -
    - count = min((int) (buffer->size - off), count);
    +static struct buffer* atags_buffer = NULL;

    - memcpy(page, &buffer->data[off], count);
    -
    - return count;
    +static ssize_t atags_read(struct file *file, char __user *buf,
    + size_t count, loff_t *ppos)
    +{
    + // These are introduced in kernel 3.10. I don't want to backport
    + // the whole chunk, and other things (ram_console) use static
    + // variable to keep data too, so I guess it's okay.
    + //struct buffer *b = PDE_DATA(file_inode(file));
    + struct buffer *b = atags_buffer;
    + return simple_read_from_buffer(buf, count, ppos, b->data, b->size);
    }

    +static const struct file_operations atags_fops = {
    + .read = atags_read,
    + .llseek = default_llseek,
    +};
    +
    #define BOOT_PARAMS_SIZE 1536
    static char __initdata atags_copy[BOOT_PARAMS_SIZE];

    @@ -66,12 +82,13 @@ static int __init init_atags_procfs(void)
    b->size = size;
    memcpy(b->data, atags_copy, size);

    - tags_entry = create_proc_read_entry("atags", 0400,
    - NULL, read_buffer, b);
    + tags_entry = proc_create_data("atags", 0400, NULL, &atags_fops, b);

    if (!tags_entry)
    goto nomem;

    + atags_buffer = b;
    +
    return 0;

    nomem:
    diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
    index dfcdb9f..05a6f2a 100644
    --- a/arch/arm/kernel/machine_kexec.c
    +++ b/arch/arm/kernel/machine_kexec.c
    @@ -14,6 +14,7 @@
    #include <asm/cacheflush.h>
    #include <asm/mach-types.h>
    #include <asm/system_misc.h>
    +#include <asm/mmu_writeable.h>

    extern const unsigned char relocate_new_kernel[];
    extern const unsigned int relocate_new_kernel_size;
    @@ -22,6 +23,10 @@ extern unsigned long kexec_start_address;
    extern unsigned long kexec_indirection_page;
    extern unsigned long kexec_mach_type;
    extern unsigned long kexec_boot_atags;
    +#ifdef CONFIG_KEXEC_HARDBOOT
    +extern unsigned long kexec_hardboot;
    +void (*kexec_hardboot_hook)(void);
    +#endif

    static atomic_t waiting_for_crash_ipi;

    @@ -119,10 +124,13 @@ void machine_kexec(struct kimage *image)
    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;
    + mem_text_write_kernel_word(&kexec_start_address, image->start);
    + mem_text_write_kernel_word(&kexec_indirection_page, page_list);
    + mem_text_write_kernel_word(&kexec_mach_type, machine_arch_type);
    + mem_text_write_kernel_word(&kexec_boot_atags, image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET);
    +#ifdef CONFIG_KEXEC_HARDBOOT
    + mem_text_write_kernel_word(&kexec_hardboot, image->hardboot);
    +#endif

    /* copy our kernel relocation code to the control code page */
    memcpy(reboot_code_buffer,
    @@ -136,5 +144,11 @@ void machine_kexec(struct kimage *image)
    if (kexec_reinit)
    kexec_reinit();

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + /* Run any final machine-specific shutdown code. */
    + if (image->hardboot && kexec_hardboot_hook)
    + kexec_hardboot_hook();
    +#endif
    +
    soft_restart(reboot_code_buffer_phys);
    }
    diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
    index d0cdedf..f4469a1 100644
    --- a/arch/arm/kernel/relocate_kernel.S
    +++ b/arch/arm/kernel/relocate_kernel.S
    @@ -4,6 +4,13 @@

    #include <asm/kexec.h>

    +#ifdef CONFIG_KEXEC_HARDBOOT
    +#include <asm/memory.h>
    +#if defined(CONFIG_ARCH_MSM8930)
    + #include <mach/msm_iomap.h>
    +#endif
    +#endif
    +
    .globl relocate_new_kernel
    relocate_new_kernel:

    @@ -52,6 +59,12 @@ relocate_new_kernel:
    b 0b

    2:
    +#ifdef CONFIG_KEXEC_HARDBOOT
    + ldr r0, kexec_hardboot
    + teq r0, #0
    + bne hardboot
    +#endif
    +
    /* Jump to relocated kernel */
    mov lr,r1
    mov r0,#0
    @@ -60,6 +73,34 @@ relocate_new_kernel:
    ARM( mov pc, lr )
    THUMB( bx lr )

    +#ifdef CONFIG_KEXEC_HARDBOOT
    +hardboot:
    + /* Stash boot arguments in hardboot page:
    + * 0: KEXEC_HB_PAGE_MAGIC
    + * 4: kexec_start_address
    + * 8: kexec_mach_type
    + * 12: kexec_boot_atags */
    + ldr r0, =KEXEC_HB_PAGE_ADDR
    + str r1, [r0, #4]
    + ldr r1, kexec_mach_type
    + str r1, [r0, #8]
    + ldr r1, kexec_boot_atags
    + str r1, [r0, #12]
    + ldr r1, =KEXEC_HB_PAGE_MAGIC
    + str r1, [r0]
    +
    +#if defined(CONFIG_ARCH_MSM8930)
    + /* Restart using the PMIC chip, see mach-msm/restart.c */
    + ldr r0, =MSM8930_TLMM_PHYS
    + mov r1, #0
    + str r1, [r0, #0x820] @ PSHOLD_CTL_SU
    +loop: b loop
    +#else
    +#error "No reboot method defined for hardboot."
    +#endif
    +
    + .ltorg
    +#endif
    .align

    .globl kexec_start_address
    @@ -79,6 +120,12 @@ kexec_mach_type:
    kexec_boot_atags:
    .long 0x0

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + .globl kexec_hardboot
    +kexec_hardboot:
    + .long 0x0
    +#endif
    +
    relocate_new_kernel_end:

    .globl relocate_new_kernel_size
    diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
    index 4ecf2ad..65924cd 100644
    --- a/arch/arm/mach-msm/board-8930.c
    +++ b/arch/arm/mach-msm/board-8930.c
    @@ -1100,6 +1100,17 @@ early_param("ext_display", ext_display_setup);

    static void __init msm8930_reserve(void)
    {
    +#ifdef CONFIG_KEXEC_HARDBOOT
    + // Reserve space for hardboot page, just before the ram_console
    + //struct membank* bank = &meminfo.bank[0];
    + //phys_addr_t start = bank->start + bank->size - SZ_1M - 0x00300000;
    + phys_addr_t start = KEXEC_HB_PAGE_ADDR;
    + int ret = memblock_remove(start, SZ_1M);
    + if(!ret)
    + pr_info("Hardboot page reserved at 0x%X\n", start);
    + else
    + pr_err("Failed to reserve space for hardboot page at 0x%X!\n", start);
    +#endif
    msm8930_set_display_params(prim_panel_name, ext_panel_name);
    msm_reserve();
    if (msm8930_fmem_pdata.size) {
    diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
    index e8c9567..37ecfbc 100644
    --- a/arch/arm/mach-msm/include/mach/memory.h
    +++ b/arch/arm/mach-msm/include/mach/memory.h
    @@ -20,6 +20,14 @@
    /* physical offset of RAM */
    #define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET)

    +#if defined(CONFIG_KEXEC_HARDBOOT)
    +#if defined(CONFIG_FIH_MACH_S3A)
    +#define KEXEC_HB_PAGE_ADDR UL(0x88000000)
    +#else
    +#error "Adress for kexec hardboot page not defined"
    +#endif
    +#endif
    +
    #define MAX_PHYSMEM_BITS 32
    #define SECTION_SIZE_BITS 28

    diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
    index 5033f5e..6baa64d 100644
    --- a/arch/arm/mach-msm/restart.c
    +++ b/arch/arm/mach-msm/restart.c
    @@ -36,6 +36,10 @@
    #include "timer.h"
    #include <linux/fih_sw_info.h> //MTD-KERNEL-DL-POC-00

    +#ifdef CONFIG_KEXEC_HARDBOOT
    +#include <asm/kexec.h>
    +#endif
    +
    #define WDT0_RST 0x38
    #define WDT0_EN 0x40
    #define WDT0_BARK_TIME 0x4C
    @@ -303,6 +307,14 @@ static int __init msm_pmic_restart_init(void)

    late_initcall(msm_pmic_restart_init);

    +#ifdef CONFIG_KEXEC_HARDBOOT
    +static void msm_kexec_hardboot_hook(void)
    +{
    + // Set PMIC to restart-on-poweroff
    + pm8xxx_reset_pwr_off(1);
    +}
    +#endif
    +
    static int __init msm_restart_init(void)
    {
    #ifdef CONFIG_MSM_DLOAD_MODE
    @@ -314,6 +326,10 @@ static int __init msm_restart_init(void)
    restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
    pm_power_off = msm_power_off;

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + kexec_hardboot_hook = msm_kexec_hardboot_hook;
    +#endif
    +
    return 0;
    }
    early_initcall(msm_restart_init);
    diff --git a/include/linux/kexec.h b/include/linux/kexec.h
    index af84a25..a4509ad 100644
    --- a/include/linux/kexec.h
    +++ b/include/linux/kexec.h
    @@ -111,6 +111,10 @@ struct kimage {
    #define KEXEC_TYPE_CRASH 1
    unsigned int preserve_context : 1;

    +#ifdef CONFIG_KEXEC_HARDBOOT
    + unsigned int hardboot : 1;
    +#endif
    +
    #ifdef ARCH_HAS_KIMAGE_ARCH
    struct kimage_arch arch;
    #endif
    @@ -178,6 +182,11 @@ extern struct kimage *kexec_crash_image;

    #define KEXEC_ON_CRASH 0x00000001
    #define KEXEC_PRESERVE_CONTEXT 0x00000002
    +
    +#ifdef CONFIG_KEXEC_HARDBOOT
    +#define KEXEC_HARDBOOT 0x00000004
    +#endif
    +
    #define KEXEC_ARCH_MASK 0xffff0000

    /* These values match the ELF architecture values.
    @@ -196,10 +205,14 @@ extern struct kimage *kexec_crash_image;
    #define KEXEC_ARCH_MIPS ( 8 << 16)

    /* List of defined/legal kexec flags */
    -#ifndef CONFIG_KEXEC_JUMP
    -#define KEXEC_FLAGS KEXEC_ON_CRASH
    -#else
    +#if defined(CONFIG_KEXEC_JUMP) && defined(CONFIG_KEXEC_HARDBOOT)
    +#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT | KEXEC_HARDBOOT)
    +#elif defined(CONFIG_KEXEC_JUMP)
    #define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)
    +#elif defined(CONFIG_KEXEC_HARDBOOT)
    +#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_HARDBOOT)
    +#else
    +#define KEXEC_FLAGS (KEXEC_ON_CRASH)
    #endif

    #define VMCOREINFO_BYTES (4096)
    diff --git a/kernel/crash_notes.c b/kernel/crash_notes.c
    index 76bcf8d..73e2324 100644
    --- a/kernel/crash_notes.c
    +++ b/kernel/crash_notes.c
    @@ -57,7 +57,7 @@ struct crash_extras {

    typedef u32 note_buf_t[CRASH_NOTE_BYTES/4];

    -note_buf_t* crash_notes;
    +static note_buf_t* crash_notes;

    static inline void dump_regs(struct pt_regs *regs)
    {
    diff --git a/kernel/kexec.c b/kernel/kexec.c
    index 4e2e472..aef7893 100644
    --- a/kernel/kexec.c
    +++ b/kernel/kexec.c
    @@ -1004,6 +1004,10 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,

    if (flags & KEXEC_PRESERVE_CONTEXT)
    image->preserve_context = 1;
    +#ifdef CONFIG_KEXEC_HARDBOOT
    + if (flags & KEXEC_HARDBOOT)
    + image->hardboot = 1;
    +#endif
    result = machine_kexec_prepare(image);
    if (result)
    goto out;
    --
    1.7.9.5