Re: [Patch]IA64 kexec

Horms
2006-02-13T10:17:16Z

On Mon, Feb 13, 2006 at 05:06:59PM +0900, Horms wrote:
> On 2005-11-07 at 23:27:49 Zou Nan Hai wrote:
> > Here is my patches of kexec on IA64.
> >
> > The kernel patch is against 2.6.14
> > The kexec-tools patch is against kexec-tools-1.101
>
> Am i right in assuming that this is still the latest version of
> kexec for ia64? If not, could someone point me to a newer one.
>
> > I have tested it on a Tiger-4 and a ZX1 machine.
>
> Is it possible to get the config that you used on Tiger-4?
>
> > Please test and review it.

Hi,

Here is an as-yet untested forward port of the kexec-ia64 patch to
today's Linus git tree (~2.6.16-rc3).

The only real change to the 2.6.14 incarnation was to
remove the definitions of note_buf_t and note_buf_t as these
are now in the generic code. And to change the declaration of
machine_crash_shutdown.

machine_crash_shutdown still does nothing. As the original i386 version
did. However I notice that code has been enhanced to:

* Shut down the other CPU's using (NMI)
* Snapshot the registers
* Shut down APICS

I haven't looked into what other features have been added
to other arches kexec. Nor if the features above are applicable -
seems that they probably are, exept that ia64 doesn't have NMI
(right?) so the cpu shutdown would need to be done another way.

--
Horms

diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 845cd09..a33c092 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -376,6 +376,17 @@ config IA64_PALINFO
config SGI_SN
def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)

+config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && (!SMP || HOTPLUG_CPU)
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similiarity to the exec system call.
+
source "drivers/firmware/Kconfig"

source "fs/Kconfig.binfmt"
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 09a0dbc..d2e15df 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o relocate_kernel.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
mca_recovery-y += mca_drv.o mca_drv_asm.o

diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
new file mode 100644
index 0000000..f8276d0
--- /dev/null
+++ b/arch/ia64/kernel/crash.c
@@ -0,0 +1,21 @@
+/*
+ * arch/ia64/kernel/crash.c
+ *
+ * Copyright (C) 2005 Intel Corp
+ * Zou Nan hai <nanhai.zou@intel.com>
+ */
+#include <linux/smp.h>
+#include <linux/kexec.h>
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /* This function is only called after the system
+ * has paniced or is otherwise in a critical state.
+ * The minimum amount of code to allow a kexec'd kernel
+ * to run successfully needs to happen here.
+ *
+ * In practice this means shooting down the other cpus in
+ * an SMP system.
+ */
+}
+
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 27b222c..c2fce91 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1588,7 +1588,7 @@ sys_call_table:
data8 sys_mq_timedreceive // 1265
data8 sys_mq_notify
data8 sys_mq_getsetattr
- data8 sys_ni_syscall // reserved for kexec_load
+ data8 sys_kexec_load
data8 sys_ni_syscall // reserved for vserver
data8 sys_waitid // 1270
data8 sys_add_key
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
new file mode 100644
index 0000000..506f375
--- /dev/null
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -0,0 +1,67 @@
+/*
+ * arch/ia64/kernel/machine_exec.c
+ *
+ * Copyright (C) 2005 Intel Corp
+ * Zou Nan hai <nanhai.zou@intel.com>
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/kexec.h>
+#include <asm/meminit.h>
+#include <asm/delay.h>
+
+int
+machine_kexec_prepare(struct kimage * image)
+{
+ return 0;
+}
+
+void
+machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+void
+machine_shutdown(void)
+{
+ printk(KERN_INFO "kexec: machine_shutdown called\n");
+}
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned long relocate_new_kernel_size;
+typedef void (*relocate_kernel_t) (unsigned long, kimage_entry_t, void *,
+ unsigned long);
+
+extern void *efi_get_pal_addr(void);
+
+NORET_TYPE void
+machine_kexec(struct kimage *image)
+{
+ relocate_kernel_t relocator;
+ void *pal_addr = efi_get_pal_addr();
+ unsigned long
+ code_addr = (unsigned long)page_address(image->control_code_page);
+
+#ifdef CONFIG_SMP
+ int cpu;
+ for_each_online_cpu(cpu) {
+ if (cpu != smp_processor_id())
+ cpu_down(cpu);
+ }
+#endif
+ ia64_set_itv(1<<16);
+ local_irq_disable();
+ relocator = (relocate_kernel_t)&code_addr;
+ memcpy((void *)code_addr, relocate_new_kernel,
+ relocate_new_kernel_size);
+ flush_icache_range(code_addr, code_addr + relocate_new_kernel_size);
+
+ (*relocator)(image->start, image->head, ia64_boot_param,
+ GRANULEROUNDDOWN((unsigned long) pal_addr));
+ BUG();
+
+ for(;;);
+
+}
diff --git a/arch/ia64/kernel/relocate_kernel.S b/arch/ia64/kernel/relocate_kernel.S
new file mode 100644
index 0000000..247c436
--- /dev/null
+++ b/arch/ia64/kernel/relocate_kernel.S
@@ -0,0 +1,187 @@
+/*
+ * arch/ia64/kernel/relocate_kernel.S
+ *
+ * Copyright (C) 2005 Intel Corp
+ * Zou Nan hai <nanhai.zou@intel.com>
+ */
+#include <asm/asmmacro.h>
+#include <asm/kregs.h>
+#include <asm/pgtable.h>
+#include <asm/mca_asm.h>
+
+/* relocate new kernel
+ * => switch to physical mode
+ * => purge all TC and TR entries
+ * => go through kimage page_list to copy segments
+ * => clear system state
+ * => call to entry in physical mode
+ */
+
+GLOBAL_ENTRY(relocate_new_kernel)
+ .prologue
+ alloc r31=ar.pfs,4,0,0,0
+ .body
+.here:
+{
+ rsm psr.i| psr.ic
+ mov r15=ip
+}
+ ;;
+{
+ flushrs // must be first insn in group
+ srlz.i
+}
+ ;;
+
+ //first switch to physical mode
+ add r3\x1f-.here, r15
+ movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC
+ mov ar.rsc=0 // put RSE in enforced lazy mode
+ ;;
+ add r2=__reloc_stack-.here, r15
+ ;;
+ add spÅ92-16, r2
+ ;;
+ tpa sp=sp
+ tpa r3=r3
+ ;;
+ mov r18=ar.rnat
+ mov ar.bspstore=r2
+ ;;
+ mov cr.ipsr=r16
+ mov cr.iip=r3
+ mov cr.ifs=r0
+ srlz.i
+ ;;
+ mov ar.rnat=r18
+ rfi
+ ;;
+1:
+ //physical mode code begin
+ mov b6=in0
+ tpa r28=in2 // tpa must before TLB purge
+
+ // purge all TC entries
+#define O(member) IA64_CPUINFO_##member##_OFFSET
+ GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2
+ ;;
+ addl r17=O(PTCE_STRIDE),r2
+ addl r2=O(PTCE_BASE),r2
+ ;;
+ ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base
+ ld4 r19=[r2],4 // r19=ptce_count[0]
+ ld4 r21=[r17],4 // r21=ptce_stride[0]
+ ;;
+ ld4 r20=[r2] // r20=ptce_count[1]
+ ld4 r22=[r17] // r22=ptce_stride[1]
+ mov r24=r0
+ ;;
+ adds r20=-1,r20
+ ;;
+#undef O
+2:
+ cmp.ltu p6,p7=r24,r19
+(p7) br.cond.dpnt.few 4f
+ mov ar.lc=r20
+3:
+ ptc.e r18
+ ;;
+ add r18=r22,r18
+ br.cloop.sptk.few 3b
+ ;;
+ add r18=r21,r18
+ add r24=1,r24
+ ;;
+ br.sptk.few 2b
+4:
+ srlz.i
+ ;;
+ //purge TR entry for kernel text and data
+ movl r16=KERNEL_START
+ mov r18=KERNEL_TR_PAGE_SHIFT<<2
+ ;;
+ ptr.i r16, r18
+ ptr.d r16, r18
+ ;;
+ srlz.i
+ ;;
+
+ // purge TR entry for percpu data
+ movl r16=PERCPU_ADDR
+ mov r18=PERCPU_PAGE_SHIFT<<2
+ ;;
+ ptr.d r16,r18
+ ;;
+ srlz.d
+
+ // purge TR entry for stack
+ mov r16=IA64_KR(CURRENT_STACK)
+ ;;
+ shl r16=r16,IA64_GRANULE_SHIFT
+ movl r19=PAGE_OFFSET
+ ;;
+ add r16=r19,r16
+ mov r18=IA64_GRANULE_SHIFT<<2
+ ;;
+ ptr.d r16,r18
+ ;;
+ srlz.i
+ ;;
+
+ // purge TR entry for pal code
+ mov r16=in3
+ mov r18=IA64_GRANULE_SHIFT<<2
+ ;;
+ ptr.i r16,r18
+ ;;
+ srlz.i
+ ;;
+
+ // copy segments
+ movl r16=PAGE_MASK
+ mov r30=in1 // in1 is page_list
+ br.sptk.few .dest_page
+ ;;
+.loop:
+ ld8 r30=[in1], 8;;
+.dest_page:
+ tbit.z p0, p6=r30, 0;; // 0x1 dest page
+(p6) and r17=r30, r16
+(p6) br.cond.sptk.few .loop;;
+
+ tbit.z p0, p6=r30, 1;; // 0x2 indirect page
+(p6) and in1=r30, r16
+(p6) br.cond.sptk.few .loop;;
+
+ tbit.z p0, p6=r30, 2;; // 0x4 end flag
+(p6) br.cond.sptk.few .end_loop;;
+
+ tbit.z p6, p0=r30, 3;; // 0x8 source page
+(p6) br.cond.sptk.few .loop
+
+ and r18=r30, r16
+
+ // simple copy page, may optimize later
+ movl r14=PAGE_SIZE/8 - 1;;
+ mov ar.lc=r14;;
+1:
+ ld8 r14=[r18], 8;;
+ st8 [r17]=r14, 8;;
+ fc.i r17
+ br.ctop.sptk.few 1b
+ br.sptk.few .loop
+ ;;
+
+.end_loop:
+ sync.i // for fc.i
+ ;;
+ srlz.i
+ ;;
+ br.call.sptk.many b0∂;;
+__reloc_stack:
+.skip 8192
+relocate_new_kernel_end:
+END(relocate_new_kernel)
+ .global relocate_new_kernel_size
+relocate_new_kernel_size:
+ data8 relocate_new_kernel_end - relocate_new_kernel
diff --git a/include/asm-ia64/kexec.h b/include/asm-ia64/kexec.h
new file mode 100644
index 0000000..782bcbb
--- /dev/null
+++ b/include/asm-ia64/kexec.h
@@ -0,0 +1,27 @@
+#ifndef _IA64_KEXEC_H
+#define _IA64_KEXEC_H
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
+ * calculation for the amount of memory directly mappable into the
+ * kernel memory space.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_CODE_SIZE (1UL << 14)
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_IA_64
+
+#define MAX_NOTE_BYTES 1024
+#endif
-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html