From: Chad Goodman Date: Mon, 10 Dec 2012 05:24:16 +0000 (-0800) Subject: KEXEC: add support for (and enable) KEXEC with RAM CONSOLE X-Git-Url: https://projects.ziggy471.com/git/gitweb.cgi?p=ziggy471-sgs3-jb.git;a=commitdiff;h=a477802f44e154772a8e00371882acdb78721956 KEXEC: add support for (and enable) KEXEC with RAM CONSOLE Signed-off-by: Ziggy --- --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2026,6 +2026,36 @@ 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 KEXEC_HB_PAGE_ADDR + hex "Kexec hardboot page address" + depends on KEXEC_HARDBOOT + config CRASH_DUMP bool "Build kdump crash kernel (EXPERIMENTAL)" depends on EXPERIMENTAL --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -5,6 +5,7 @@ # OBJS = +plus_sec := $(call as-instr,.arch_extension sec,+sec) # Ensure that mmcif loader code appears early in the image # to minimise that number of bocks that have to be read in @@ -15,14 +16,26 @@ OBJS += mmcif-sh7372.o endif endif -AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) -HEAD = head.o -OBJS += misc.o decompress.o +AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) +AFLAGS_head.o += -Wa,-march=armv7-a$(plus_sec) +HEAD = head.o + +AFLAGS_misc.o +=-Wa,-march=armv7-a$(plus_sec) +MISC = misc.o + +AFLAGS_decompress.o += -Wa,-march=armv7-a$(plus_sec) +DECOMPRESS = decompress.o + FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c +#AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) +#HEAD = head.o +#OBJS += misc.o decompress.o +#FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c + # string library code (-Os is enforced to keep it much smaller) OBJS += string.o -CFLAGS_string.o := -Os +CFLAGS_string.o := -O3 # # Architecture dependencies @@ -86,6 +99,7 @@ SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/ suffix_$(CONFIG_KERNEL_GZIP) = gzip suffix_$(CONFIG_KERNEL_LZO) = lzo suffix_$(CONFIG_KERNEL_LZMA) = lzma +suffix_$(CONFIG_KERNEL_XZ) = xzkern # Borrowed libfdt files for the ATAG compatibility mode @@ -106,10 +120,10 @@ endif targets := vmlinux vmlinux.lds \ piggy.$(suffix_y) piggy.$(suffix_y).o \ - lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS) + lib1funcs.o lib1funcs.S font.o font.c head.o misc.o decompress.o $(OBJS) # Make sure files are removed during clean -extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs) +extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern lib1funcs.S $(libfdt) $(libfdt_hdrs) ifeq ($(CONFIG_FUNCTION_TRACER),y) ORIG_CFLAGS := $(KBUILD_CFLAGS) @@ -117,7 +131,7 @@ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CF endif ccflags-y := -fpic -fno-builtin -I$(obj) -asflags-y := -Wa,-march=all +asflags-y := -Wa,-march=armv7-a$(plus_sec) # Supply kernel BSS size to the decompressor via a linker symbol. SIZEBIN := $(if $(shell which $(CROSS_COMPILE)size),$(CROSS_COMPILE)size,size) @@ -130,6 +144,9 @@ endif ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) LDFLAGS_vmlinux += --be8 endif +ifneq ($(PARAMS_PHYS),) +LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS) +endif # ? LDFLAGS_vmlinux += -p # Report unresolved symbol references @@ -140,6 +157,7 @@ LDFLAGS_vmlinux += -X LDFLAGS_vmlinux += -T # For __aeabi_uidivmod +AFLAGS_lib1funcs.o +=-Wa,-march=armv7-a$(plus_sec) lib1funcs = $(obj)/lib1funcs.o $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S @@ -157,12 +175,19 @@ bad_syms=$$($(CROSS_COMPILE)nm $@ | sed [ -z "$$bad_syms" ] || \ ( echo "following symbols must have non local/private scope:" >&2; \ echo "$$bad_syms" >&2; rm -f $@; false ) +# For __aeabi_llsl +AFLAGS_ashldi3.o +=-Wa,-march=armv7-a$(plus_sec) +ashldi3 = $(obj)/ashldi3.o + +$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S FORCE + $(call cmd,shipped) -$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ - $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE +$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/$(MISC) $(obj)/$(DECOMPRESS) $(obj)/piggy.$(suffix_y).o \ + $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE $(call if_changed,ld) @$(check_for_bad_syms) +AFLAGS_piggy.$(suffix_y).o += -Wa,-march=armv7-a$(plus_sec) $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE $(call if_changed,$(suffix_y)) @@ -175,3 +200,4 @@ $(obj)/font.c: $(FONTC) $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) @sed "$(SEDFLAGS)" < $< > $@ + --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -9,6 +9,11 @@ * published by the Free Software Foundation. */ #include +#include + +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif /* * Debugging stuff @@ -141,7 +146,31 @@ start: .word _edata @ zImage end address THUMB( .thumb ) 1: mov r7, r1 @ save architecture ID - mov r8, r2 @ save atags pointer + teq r0, #0 @ Check for kexec_boot_atags. + movne r8, r0 @ Save kexec_boot_tags. + moveq 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] + + /* Load boot arguments and jump to kexec kernel. */ + ldr r0, [r3, #12] @ kexec_boot_atags (r2: boot_atags) + ldr r1, [r3, #8] @ kexec_mach_type + ldr pc, [r3, #4] @ kexec_start_address + + .ltorg + +not_booting_other: +#endif #ifndef __ARM_ARCH_2__ /* @@ -463,6 +492,41 @@ not_relocated: mov r0, #0 add r2, sp, #0x10000 @ 64k max mov r3, r7 bl decompress_kernel + +/* 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. + * + * 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). + * + * r4: zreladdr (kernel start) + * r8: atags */ + + /* Don't need to copy atags if they're already below the kernel. */ + cmp r8, r4 + blo call_kernel + + /* r1: min(zreladdr, pc) */ + mov r1, pc + cmp r4, r1 + movlo r1, r4 + + /* Compute max space for atags, if max <= 0 don't copy. */ + ldr r0, =params_phys @ dest + subs r2, r1, r0 @ max = min(zreladdr, pc) - dest + bls call_kernel + + /* Copy atags to params_phys. */ + mov r1, r8 @ src + bl copy_atags + mov r8, r0 + +call_kernel: bl cache_clean_flush bl cache_off mov r0, #0 @ must be zero @@ -470,6 +534,8 @@ not_relocated: mov r0, #0 mov r2, r8 @ restore atags pointer mov pc, r4 @ call kernel + .ltorg + .align 2 .type LC0, #object LC0: .word LC0 @ r1 @@ -581,9 +647,14 @@ __setup_mmu: sub r3, r4, #16384 @ Page * bits for the RAM area only. */ mov r0, r3 +#if defined(PLAT_PHYS_OFFSET) && defined(END_MEM) + ldr r9, =PLAT_PHYS_OFFSET @ start of RAM + ldr r10, =END_MEM @ end of RAM +#else mov r9, r0, lsr #18 mov r9, r9, lsl #18 @ start of RAM add r10, r9, #0x10000000 @ a reasonable RAM size +#endif mov r1, #0x12 orr r1, r1, #3 << 10 add r2, r3, #16384 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -21,6 +21,8 @@ unsigned int __machine_arch_type; #include /* for inline */ #include #include +#include +#include static void putstr(const char *ptr); extern void error(char *x); @@ -152,3 +154,25 @@ decompress_kernel(unsigned long output_s else putstr(" done, booting the kernel.\n"); } + +const struct tag *copy_atags(struct tag *dest, const struct tag *src, + size_t max) +{ + struct tag *tag; + size_t size; + + /* Find the last tag (ATAG_NONE). */ + for_each_tag(tag, (struct tag *)src) + continue; + + /* Include the last tag in copy. */ + size = (char *)tag - (char *)src + sizeof(struct tag_header); + + /* If there's not enough room, just use original and hope it works. */ + if (size > max) + return src; + + memcpy(dest, src, size); + + return dest; +} --- a/arch/arm/include/asm/kexec.h +++ b/arch/arm/include/asm/kexec.h @@ -17,6 +17,11 @@ #define KEXEC_ARM_ATAGS_OFFSET 0x1000 #define KEXEC_ARM_ZIMAGE_OFFSET 0x8000 +#ifdef CONFIG_KEXEC_HARDBOOT +#define KEXEC_HB_PAGE_ADDR UL(CONFIG_KEXEC_HB_PAGE_ADDR) +#define KEXEC_HB_PAGE_MAGIC 0x4a5db007 +#endif + #ifndef __ASSEMBLY__ /** @@ -53,6 +58,10 @@ static inline void crash_setup_regs(stru /* 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 */ --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -12,6 +12,7 @@ #include #include #include +#include extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; @@ -23,6 +24,11 @@ extern unsigned long kexec_indirection_p 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; /* @@ -96,10 +102,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, @@ -115,6 +124,13 @@ void machine_kexec(struct kimage *image) local_irq_disable(); local_fiq_disable(); setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ + +#ifdef CONFIG_KEXEC_HARDBOOT + if (image->hardboot && kexec_hardboot_hook) + /* Run any final machine-specific shutdown code. */ + kexec_hardboot_hook(); +#endif + flush_cache_all(); outer_flush_all(); outer_disable(); --- a/arch/arm/kernel/machine_kexec.c.rej +++ /dev/null @@ -1,12 +0,0 @@ ---- arch/arm/kernel/machine_kexec.c -+++ arch/arm/kernel/machine_kexec.c -@@ -106,6 +111,9 @@ - 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, --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -4,6 +4,13 @@ #include +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#ifdef CONFIG_ARCH_MSM8960 +#include +#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 @@ -59,6 +72,35 @@ relocate_new_kernel: ldr r2,kexec_boot_atags mov pc,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] + +#ifdef CONFIG_ARCH_MSM8960 + /* Hard reset via PMIC, decompressor jumps to kernel. */ + ldr r0, =MSM8960_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 @@ -78,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 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -904,6 +904,13 @@ config PHYS_OFFSET default "0x40200000" if ARCH_MSM8X60 default "0x10000000" +config HAVE_END_MEM + bool "Specify highest physical RAM address at compile time" + +config END_MEM + hex "Highest physical address where system RAM resides" + depends on HAVE_END_MEM + config KERNEL_PMEM_EBI_REGION bool "Enable in-kernel PMEM region for EBI" default y if ARCH_MSM8X60 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -34,6 +34,7 @@ endif # MSM8960 zreladdr-$(CONFIG_ARCH_MSM8960) := 0x80208000 +params_phys-$(CONFIG_ARCH_MSM8960) := 0x80200100 # MSM8930 zreladdr-$(CONFIG_ARCH_MSM8930) := 0x80208000 --- a/arch/arm/mach-msm/board-m2_spr.c +++ b/arch/arm/mach-msm/board-m2_spr.c @@ -172,6 +172,9 @@ #include #endif +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif #ifdef CONFIG_TOUCHSCREEN_MMS144 struct tsp_callbacks *charger_callbacks; struct tsp_callbacks { @@ -1029,6 +1032,25 @@ static int __init ext_display_setup(char } early_param("ext_display", ext_display_setup); +/* Exclude the last 4 kB to preserve the kexec hardboot page. */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#define RAM_CONSOLE_START 0xfff00000 +#define RAM_CONSOLE_SIZE (SZ_1M-SZ_4K) + +static struct resource ram_console_resource[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ram_console_device = { + .name = "ram_console", + .id = -1, + .num_resources = ARRAY_SIZE(ram_console_resource), + .resource = ram_console_resource, +}; +#endif + unsigned int address = 0xea000000; unsigned int size = 0x100000; @@ -1054,6 +1076,17 @@ static void __init msm8960_reserve(void) ret = memblock_remove(address, size); BUG_ON(ret); } + +#ifdef CONFIG_ANDROID_RAM_CONSOLE + if (memblock_remove(RAM_CONSOLE_START, RAM_CONSOLE_SIZE) == 0) { + ram_console_resource[0].start = RAM_CONSOLE_START; + ram_console_resource[0].end = RAM_CONSOLE_START+RAM_CONSOLE_SIZE-1; + } +#endif + +#ifdef CONFIG_KEXEC_HARDBOOT + memblock_remove(KEXEC_HB_PAGE_ADDR, SZ_4K); +#endif } static int msm8960_change_memory_power(u64 start, u64 size, @@ -4416,6 +4449,9 @@ static struct platform_device *m2_spr_de #ifdef CONFIG_VIBETONZ &vibetonz_device, #endif /* CONFIG_VIBETONZ */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE + &ram_console_device, +#endif }; static void __init msm8960_i2c_init(void) @@ -5279,7 +5315,7 @@ static void __init samsung_m2_spr_init(v } -MACHINE_START(M2_SPR, "SAMSUNG M2_SPR") +MACHINE_START(M2_SPR, "AnThRaXed SAMSUNG M2_SPR") .map_io = msm8960_map_io, .reserve = msm8960_reserve, .init_irq = msm8960_init_irq, --- a/arch/arm/mach-msm/board-m2_vzw.c +++ b/arch/arm/mach-msm/board-m2_vzw.c @@ -172,6 +172,9 @@ #include #endif +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif #ifdef CONFIG_TOUCHSCREEN_MMS144 struct tsp_callbacks *charger_callbacks; struct tsp_callbacks { @@ -1051,6 +1054,25 @@ static int __init ext_display_setup(char } early_param("ext_display", ext_display_setup); +/* Exclude the last 4 kB to preserve the kexec hardboot page. */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE +#define RAM_CONSOLE_START 0xfff00000 +#define RAM_CONSOLE_SIZE (SZ_1M-SZ_4K) + +static struct resource ram_console_resource[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ram_console_device = { + .name = "ram_console", + .id = -1, + .num_resources = ARRAY_SIZE(ram_console_resource), + .resource = ram_console_resource, +}; +#endif + unsigned int address = 0xea000000; unsigned int size = 0x100000; @@ -1076,6 +1098,17 @@ static void __init msm8960_reserve(void) ret = memblock_remove(address, size); BUG_ON(ret); } + +#ifdef CONFIG_ANDROID_RAM_CONSOLE + if (memblock_remove(RAM_CONSOLE_START, RAM_CONSOLE_SIZE) == 0) { + ram_console_resource[0].start = RAM_CONSOLE_START; + ram_console_resource[0].end = RAM_CONSOLE_START+RAM_CONSOLE_SIZE-1; + } +#endif + +#ifdef CONFIG_KEXEC_HARDBOOT + memblock_remove(KEXEC_HB_PAGE_ADDR, SZ_4K); +#endif } static int msm8960_change_memory_power(u64 start, u64 size, @@ -4465,6 +4498,9 @@ static struct platform_device *m2_vzw_de #ifdef CONFIG_VIBETONZ &vibetonz_device, #endif /* CONFIG_VIBETONZ */ +#ifdef CONFIG_ANDROID_RAM_CONSOLE + &ram_console_device, +#endif }; static void __init msm8960_i2c_init(void) --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -19,6 +19,9 @@ /* physical offset of RAM */ #define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) +#ifdef CONFIG_HAVE_END_MEM +#define END_MEM UL(CONFIG_END_MEM) +#endif #define MAX_PHYSMEM_BITS 32 #define SECTION_SIZE_BITS 28 --- a/arch/arm/mach-msm/restart.c +++ b/arch/arm/mach-msm/restart.c @@ -40,6 +40,10 @@ #include "msm_watchdog.h" #include "timer.h" +#ifdef CONFIG_KEXEC_HARDBOOT +#include +#endif + #define WDT0_RST 0x38 #define WDT0_EN 0x40 #define WDT0_BARK_TIME 0x4C @@ -271,11 +275,6 @@ void arch_reset(char mode, const char *c __raw_writel(0x77665507, restart_reason); printk(KERN_NOTICE "peripheral_hw_reset C777!!!!\n"); #endif -#ifdef CONFIG_SEC_L1_DCACHE_PANIC_CHK - } else if (!strncmp(cmd, "l1_dcache_reset", 15)) { - __raw_writel(0x77665588, restart_reason); - printk(KERN_NOTICE "l1_dcache_reset !!!!\n"); -#endif } else if (!strncmp(cmd, "download", 8)) { __raw_writel(0x12345671, restart_reason); } else if (!strncmp(cmd, "sud", 3)) { @@ -284,11 +283,6 @@ void arch_reset(char mode, const char *c } else if (!strncmp(cmd, "debug", 5) /* set debug leve */ && !kstrtoul(cmd + 5, 0, &value)) { __raw_writel(0xabcd0000 | value, restart_reason); -#ifdef CONFIG_SEC_SSR_DEBUG_LEVEL_CHK - } else if (!strncmp(cmd, "cpdebug", 7) /* set cp debug level */ - && !kstrtoul(cmd + 7, 0, &value)) { - __raw_writel(0xfedc0000 | value, restart_reason); -#endif } else if (!strncmp(cmd, "nvbackup", 8)) { __raw_writel(0x77665511, restart_reason); } else if (!strncmp(cmd, "nvrestore", 9)) { @@ -339,6 +333,18 @@ static struct notifier_block dload_reboo }; #endif +#ifdef CONFIG_KEXEC_HARDBOOT +void msm_kexec_hardboot(void) +{ + /* Set PM8XXX PMIC to reset on power off. */ + pm8xxx_reset_pwr_off(1); + + /* Reboot with the recovery kernel since the boot kernel decompressor may + * not support the hardboot jump. */ + __raw_writel(0x77665502, restart_reason); +} +#endif + static int __init msm_restart_init(void) { int rc; @@ -364,6 +370,9 @@ static int __init msm_restart_init(void) restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR; #endif pm_power_off = msm_power_off; +#ifdef CONFIG_KEXEC_HARDBOOT + kexec_hardboot_hook = msm_kexec_hardboot; +#endif if (pmic_reset_irq != 0) { rc = request_any_context_irq(pmic_reset_irq, --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -100,6 +100,9 @@ struct kimage { #define KEXEC_TYPE_DEFAULT 0 #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; @@ -166,6 +169,9 @@ 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. @@ -184,10 +190,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) --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1005,6 +1005,10 @@ SYSCALL_DEFINE4(kexec_load, unsigned lon 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;