Skip to contentSkip to conversation

kexec based hibernation -v7 : kexec jump

PATCH In review Huang, Ying 5 participants 25 messages Dec 7, 2007 – Dec 18, 2007

Subsystems (9)
Documentation x86 PowerPC SuperH +5 more subsystems
lore
Share & tools
lore
#0 lore raw

PATCH 1/4 kexec based hibernation -v7 : kexec jump

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S      |  214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +67 -21
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);
+			if (ret)
+				*ret = KCALL_ARGS(control_page)[0];
+			return 0;
+		}
+	}
+
+	relocate_kernel_ptr = control_page +
+		((void *)relocate_kernel - (void *)relocate_page);
 	page_list[PA_CONTROL_PAGE] = __pa(control_page);
-	page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
+	page_list[VA_CONTROL_PAGE] = (unsigned long)control_page;
 	page_list[PA_PGD] = __pa(kexec_pgd);
 	page_list[VA_PGD] = (unsigned long)kexec_pgd;
 #ifdef CONFIG_X86_PAE
@@ -127,26 +166,33 @@ NORET_TYPE void machine_kexec(struct kim
 	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
 	page_list[PA_PTE_1] = __pa(kexec_pte1);
 	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
+	page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) << PAGE_SHIFT);
 
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}
 
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);
+	return 0;
 }
 
 void arch_crash_save_vmcoreinfo(void)
include/asm-x86/kexec_32.h +33 -6
@@ -9,16 +9,40 @@
 #define VA_PTE_0         5
 #define PA_PTE_1         6
 #define VA_PTE_1         7
+#define PA_SWAP_PAGE     8
 #ifdef CONFIG_X86_PAE
-#define PA_PMD_0         8
-#define VA_PMD_0         9
-#define PA_PMD_1         10
-#define VA_PMD_1         11
-#define PAGES_NR         12
+#define PA_PMD_0         9
+#define VA_PMD_0         10
+#define PA_PMD_1         11
+#define VA_PMD_1         12
+#define PAGES_NR         13
 #else
-#define PAGES_NR         8
+#define PAGES_NR         9
 #endif
 
+#define KCALL_DATA_BASE		0x800
+
+#define KCALL_MAGIC_NUMBER	0xe1b6a57d
+
+#define KCALL_DATA(buf)		((__u8 *)(buf)+KCALL_DATA_BASE)
+#define KCALL_OFF(off)		(KCALL_DATA_BASE+(off))
+
+#define KCALL_MAGIC_OFF		KCALL_OFF(0x0)
+#define KCALL_MAGIC(buf)	(*(__u32 *)(KCALL_DATA(buf)+0x0))
+#define KCALL_ARGC_OFF		KCALL_OFF(0x4)
+#define KCALL_ARGC(buf)		(*(__u32 *)(KCALL_DATA(buf)+0x4))
+#define KCALL_ARGS_OFF		KCALL_OFF(0x8)
+#define KCALL_ARGS(buf)		((__u32 *)(KCALL_DATA(buf)+0x8))
+
+/*
+ * The following are not a part of jump back protocol, for internal
+ * use only
+ */
+#define KCALL_ENTRY_OFF		KCALL_OFF(0x200)
+#define KCALL_ENTRY(buf)	(*(__u32 *)(KCALL_DATA(buf)+0x200))
+/* Other internal data fields base */
+#define KCALL_OTHER_OFF		KCALL_OFF(0x204)
+
 #ifndef __ASSEMBLY__
 
 #include <asm/ptrace.h>
@@ -94,6 +118,9 @@ relocate_kernel(unsigned long indirectio
 		unsigned long start_address,
 		unsigned int has_pae) ATTRIB_NORET;
 
+extern char relocate_page[PAGE_SIZE];
+
+extern asmlinkage int kexec_call_save_cpu(void *buf);
 #endif /* __ASSEMBLY__ */
 
 #endif /* _I386_KEXEC_H */
include/linux/kexec.h +36 -4
@@ -9,6 +9,7 @@
 #include <linux/ioport.h>
 #include <linux/elfcore.h>
 #include <linux/elf.h>
+#include <linux/notifier.h>
 #include <asm/kexec.h>
 
 /* Verify architecture specific macros are defined */
@@ -83,6 +84,7 @@ struct kimage {
 
 	unsigned long start;
 	struct page *control_code_page;
+	struct page *swap_page;
 
 	unsigned long nr_segments;
 	struct kexec_segment segment[KEXEC_SEGMENT_MAX];
@@ -98,18 +100,34 @@ struct kimage {
 	unsigned int type : 1;
 #define KEXEC_TYPE_DEFAULT 0
 #define KEXEC_TYPE_CRASH   1
+	unsigned int preserve_cpu : 1;
+	unsigned int preserve_cpu_ext : 1;
+	unsigned int single_cpu : 1;
+	unsigned int preserve_device : 1;
+	unsigned int preserve_console : 1;
 };
 
 
 
 /* kexec interface functions */
-extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET;
+extern void machine_kexec(struct kimage *image);
+extern int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			       unsigned int argc, va_list args);
+extern int machine_kexec_call(struct kimage *image, unsigned long *ret,
+			      unsigned int argc, ...);
 extern int machine_kexec_prepare(struct kimage *image);
 extern void machine_kexec_cleanup(struct kimage *image);
 extern asmlinkage long sys_kexec_load(unsigned long entry,
 					unsigned long nr_segments,
 					struct kexec_segment __user *segments,
 					unsigned long flags);
+extern int kexec_call(struct kimage *image, unsigned long *ret,
+		      unsigned int argc, ...);
+extern int kexec_vcall(struct kimage *image, unsigned long *ret,
+		       unsigned int argc, va_list args);
+extern int kexec_jump(struct kimage *image, unsigned long *cmd_ret,
+		      unsigned long cmd);
+#define KJUMP_CMD_NONE 0
 #ifdef CONFIG_COMPAT
 extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
 				unsigned long nr_segments,
@@ -151,13 +169,21 @@ unsigned long paddr_vmcoreinfo_note(void
 
 extern struct kimage *kexec_image;
 extern struct kimage *kexec_crash_image;
+extern int kexec_lock;
+extern struct blocking_notifier_head kjump_chain_pre;
+extern struct blocking_notifier_head kjump_chain_post;
 
 #ifndef kexec_flush_icache_page
 #define kexec_flush_icache_page(page)
 #endif
 
-#define KEXEC_ON_CRASH  0x00000001
-#define KEXEC_ARCH_MASK 0xffff0000
+#define KEXEC_ON_CRASH		0x00000001
+#define KEXEC_PRESERVE_CPU	0x00000002
+#define KEXEC_PRESERVE_CPU_EXT	0x00000004
+#define KEXEC_SINGLE_CPU	0x00000008
+#define KEXEC_PRESERVE_DEVICE	0x00000010
+#define KEXEC_PRESERVE_CONSOLE	0x00000020
+#define KEXEC_ARCH_MASK		0xffff0000
 
 /* These values match the ELF architecture values.
  * Unless there is a good reason that should continue to be the case.
@@ -174,7 +200,13 @@ extern struct kimage *kexec_crash_image;
 #define KEXEC_ARCH_MIPS_LE (10 << 16)
 #define KEXEC_ARCH_MIPS    ( 8 << 16)
 
-#define KEXEC_FLAGS    (KEXEC_ON_CRASH)  /* List of defined/legal kexec flags */
+/* List of defined/legal kexec flags */
+#define KEXEC_FLAGS    (KEXEC_ON_CRASH |		\
+			KEXEC_PRESERVE_CPU |		\
+			KEXEC_PRESERVE_CPU_EXT |	\
+			KEXEC_SINGLE_CPU |		\
+			KEXEC_PRESERVE_DEVICE |		\
+			KEXEC_PRESERVE_CONSOLE)
 
 #define VMCOREINFO_BYTES           (4096)
 #define VMCOREINFO_NOTE_NAME       "VMCOREINFO"
kernel/kexec.c +187 -1

221 lines not on this page · raw message

kernel/sys.c +23 -12
@@ -301,18 +301,26 @@ EXPORT_SYMBOL_GPL(kernel_restart);
  *	Move into place and start executing a preloaded standalone
  *	executable.  If nothing was preloaded return an error.
  */
-static void kernel_kexec(void)
+static int kernel_kexec(unsigned long cmd)
 {
+	int ret = -ENOSYS;
 #ifdef CONFIG_KEXEC
-	struct kimage *image;
-	image = xchg(&kexec_image, NULL);
-	if (!image)
-		return;
-	kernel_restart_prepare(NULL);
-	printk(KERN_EMERG "Starting new kernel\n");
-	machine_shutdown();
-	machine_kexec(image);
+	if (xchg(&kexec_lock, 1))
+		return -EBUSY;
+	if (!kexec_image) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+	if (!kexec_image->preserve_cpu) {
+		kernel_restart_prepare(NULL);
+		printk(KERN_EMERG "Starting new kernel\n");
+		machine_shutdown();
+	}
+	ret = kexec_jump(kexec_image, NULL, cmd);
+unlock:
+	xchg(&kexec_lock, 0);
 #endif
+	return ret;
 }
 
 static void kernel_shutdown_prepare(enum system_states state)
@@ -420,9 +428,12 @@ asmlinkage long sys_reboot(int magic1, i
 		break;
 
 	case LINUX_REBOOT_CMD_KEXEC:
-		kernel_kexec();
-		unlock_kernel();
-		return -EINVAL;
+		{
+			int ret;
+			ret = kernel_kexec((unsigned long)arg);
+			unlock_kernel();
+			return ret;
+		}
 
 #ifdef CONFIG_HIBERNATION
 	case LINUX_REBOOT_CMD_SW_SUSPEND:
kernel/power/Kconfig +1 -1
@@ -91,7 +91,7 @@ config PM_SLEEP_SMP
 
 config PM_SLEEP
 	bool
-	depends on SUSPEND || HIBERNATION
+	depends on SUSPEND || HIBERNATION || KEXEC
 	default y
 
 config SUSPEND_UP_POSSIBLE
arch/x86/kernel/relocate_kernel_32.S +194 -20

260 lines not on this page · raw message

Documentation/i386/jump_back_protocol.txt new file +103 -0

103 lines not on this page · raw message

arch/ppc/kernel/machine_kexec.c +1 -1
@@ -66,7 +66,7 @@ void machine_kexec_cleanup(struct kimage
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+void machine_kexec(struct kimage *image)
 {
 	if (ppc_md.machine_kexec)
 		ppc_md.machine_kexec(image);
arch/x86/kernel/machine_kexec_64.c +1 -1
@@ -179,7 +179,7 @@ void machine_kexec_cleanup(struct kimage
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+void machine_kexec(struct kimage *image)
 {
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
arch/sh/kernel/machine_kexec.c +1 -1
@@ -70,7 +70,7 @@ static void kexec_info(struct kimage *im
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+void machine_kexec(struct kimage *image)
 {
 
 	unsigned long page_list;
arch/powerpc/kernel/machine_kexec.c +1 -1
@@ -47,7 +47,7 @@ void machine_kexec_cleanup(struct kimage
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+void machine_kexec(struct kimage *image)
 {
 	if (ppc_md.machine_kexec)
 		ppc_md.machine_kexec(image);

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#1 lore raw

Hi!

Quoted 30 lines

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

Quoted 5 lines

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

I'm not kexec hacker... but maybe this is in good enough state to be merged? It is useful on its own: kexec jump and back means we can dump system then continue running, for example...

Pavel

Signature · 7 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#2 lore raw
Quoted 36 lines · Pavel Machek

Hi!

Quoted 34 lines

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

Quoted 5 lines
Quoted 1 line

I'm not kexec hacker... but maybe this is in good enough state to be merged? It is useful on its own: kexec jump and back means we can dump system then continue running, for example...

As far as I'm concerned, patches [1/4] and [2/4] can go.

The other two are not in that shape yet (especially the [3/4] patch).

Greetings,
Rafael

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#3 lore raw
Quoted 7 lines · Rafael J. Wysocki
Quoted 3 lines

I'm not kexec hacker... but maybe this is in good enough state to be merged? It is useful on its own: kexec jump and back means we can dump system then continue running, for example...

As far as I'm concerned, patches [1/4] and [2/4] can go.

The other two are not in that shape yet (especially the [3/4] patch).

Ok. Then I will see if I can review these in the next couple days and give some feedback.

At a quick skim through the code it appears there is some more infrastructure then we need and things can still be simplified.

Since this applies in particular to the user space interface I'm not comfortable with these patches going in just yet.

The unused KEXEC_PRESERVE_ flags especially give me pause. Having something like that, that isn't currently wired up sounds like a bad place to start.

Eric

#4 lore raw
In reply to Rafael J. Wysocki
Quoted 7 lines · Rafael J. Wysocki
Quoted 3 lines

I'm not kexec hacker... but maybe this is in good enough state to be merged? It is useful on its own: kexec jump and back means we can dump system then continue running, for example...

As far as I'm concerned, patches [1/4] and [2/4] can go.

The other two are not in that shape yet (especially the [3/4] patch).

Ok. Then I will see if I can review these in the next couple days and give some feedback.

At a quick skim through the code it appears there is some more infrastructure then we need and things can still be simplified.

Since this applies in particular to the user space interface I'm not comfortable with these patches going in just yet.

The unused KEXEC_PRESERVE_ flags especially give me pause. Having something like that, that isn't currently wired up sounds like a bad place to start.

Eric

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#5 lore raw
In reply to Pavel Machek
Quoted 36 lines · Pavel Machek

Hi!

Quoted 34 lines

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

Quoted 5 lines
Quoted 1 line

I'm not kexec hacker... but maybe this is in good enough state to be merged? It is useful on its own: kexec jump and back means we can dump system then continue running, for example...

As far as I'm concerned, patches [1/4] and [2/4] can go.

The other two are not in that shape yet (especially the [3/4] patch).

Greetings,
Rafael

#6 lore raw
In reply to Huang, Ying

Hi!

Quoted 30 lines

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

Quoted 5 lines

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

I'm not kexec hacker... but maybe this is in good enough state to be merged? It is useful on its own: kexec jump and back means we can dump system then continue running, for example...

Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#7 lore raw
In reply to Huang, Ying
Quoted 3 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

Hi,

I am just going through your patches and trying to understand it. Don't understand many things. Asking is easy so here you go...

Quoted 8 lines

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

I need jumping back to restore a already hibernated kernel image? Can you please tell little more about jumping back and why it is needed?

Quoted 9 lines

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

Ok, so due to swapping of source and destination pages first kernel's data is still preserved. How do I get the dynamic memory required for second kernel boot (without writing first kernel's data)?

Quoted 86 lines

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S      |  214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +21 -2
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 136

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +3 -1
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 

Is 2K sufficient for all the code in relocate_kernel_32.S? What's the current size?

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 146

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +10 -0
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);

Who fills the entry point at offset 0x200?

[..]

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage

Quoted 8 lines
arch/x86/kernel/machine_kexec_32.c +2 -0
 extern int machine_kexec_prepare(struct kimage *image);
 extern void machine_kexec_cleanup(struct kimage *image);
 extern asmlinkage long sys_kexec_load(unsigned long entry,
 					unsigned long nr_segments,
 					struct kexec_segment __user *segments,
 					unsigned long flags);
+extern int kexec_call(struct kimage *image, unsigned long *ret,
+		      unsigned int argc, ...);

Who is using kexec_call(). I can't seem to locate the caller of it.

Thanks
Vivek

#8 lore raw
In reply to Huang, Ying
Quoted 3 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

Hi,

I am just going through your patches and trying to understand it. Don't understand many things. Asking is easy so here you go...

Quoted 8 lines

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

I need jumping back to restore a already hibernated kernel image? Can you please tell little more about jumping back and why it is needed?

Quoted 9 lines

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

Ok, so due to swapping of source and destination pages first kernel's data is still preserved. How do I get the dynamic memory required for second kernel boot (without writing first kernel's data)?

Quoted 86 lines

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S      |  214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +21 -2
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 136

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +3 -1
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 

Is 2K sufficient for all the code in relocate_kernel_32.S? What's the current size?

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 146

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +10 -0
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);

Who fills the entry point at offset 0x200?

[..]

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage

Quoted 8 lines
arch/x86/kernel/machine_kexec_32.c +2 -0
 extern int machine_kexec_prepare(struct kimage *image);
 extern void machine_kexec_cleanup(struct kimage *image);
 extern asmlinkage long sys_kexec_load(unsigned long entry,
 					unsigned long nr_segments,
 					struct kexec_segment __user *segments,
 					unsigned long flags);
+extern int kexec_call(struct kimage *image, unsigned long *ret,
+		      unsigned int argc, ...);

Who is using kexec_call(). I can't seem to locate the caller of it.

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#9 lore raw
Quoted 19 lines · Vivek Goyal
Quoted 3 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

Hi,

I am just going through your patches and trying to understand it. Don't understand many things. Asking is easy so here you go...

Quoted 8 lines

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

Quoted 2 lines

I need jumping back to restore a already hibernated kernel image? Can you please tell little more about jumping back and why it is needed?

Now, the jumping back is used to implement "kexec based hibernation", which uses kexec/kdump to save the memory image of hibernated kernel during hibernating, and uses /dev/oldmem to restore the memory image of hibernated kernel and jump back to the hibernated kernel to continue run.

The other usage model maybe include:

- Dump the system memory image then continue to run, that is, get some memory snapshot of system during system running.
- Cooperative multi-task of different OS. You can load another OS (B) from current OS (A), and jump between the two OSes upon needed.
- Call some code (such as firmware, etc) in physical mode.

Quoted 10 lines
Quoted 9 lines

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

Quoted 3 lines

Ok, so due to swapping of source and destination pages first kernel's data is still preserved. How do I get the dynamic memory required for second kernel boot (without writing first kernel's data)?

All dynamic memory required for second kernel should be "loaded" by sys_kexec_load in first kernel. For example, not only the Linux kernel should be loaded at 1M, the memory 0~16M (exclude kernel) should be "loaded" (all zero) by /sbin/kexec via sys_kexec_load too.

Quoted 91 lines
Quoted 91 lines

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S      |  214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +22 -2
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 136

Quoted 5 lines
arch/x86/kernel/machine_kexec_32.c +2 -1
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 

Is 2K sufficient for all the code in relocate_kernel_32.S? What's the current size?

The current size is 0x2d7 (727). I got it though objdump, machine_crash_shutdown - relocate_page. I think we have enough space.

Quoted 4 lines
Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 146

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +6 -0
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);

Who fills the entry point at offset 0x200?

The entry point is filled by assembler code in reloate_kernel_32.S upon jumping back. You can find it by "grep ENTRY relocate_kernel_32.S".

Quoted 12 lines

[..]

arch/x86/kernel/machine_kexec_32.c

Quoted 8 lines

extern int machine_kexec_prepare(struct kimage *image); extern void machine_kexec_cleanup(struct kimage *image); extern asmlinkage long sys_kexec_load(unsigned long entry,

arch/x86/kernel/machine_kexec_32.c +2 -0
 					unsigned long nr_segments,
 					struct kexec_segment __user *segments,
 					unsigned long flags);
+extern int kexec_call(struct kimage *image, unsigned long *ret,
+		      unsigned int argc, ...);

Who is using kexec_call(). I can't seem to locate the caller of it.

There is no user of kexec_call() now. But I think it may be useful as a physical mode caller for some firmware code.

Best Regards,
Huang Ying

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#10 lore raw
In reply to Vivek Goyal
Quoted 19 lines · Vivek Goyal
Quoted 3 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

Hi,

I am just going through your patches and trying to understand it. Don't understand many things. Asking is easy so here you go...

Quoted 8 lines

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

Quoted 2 lines

I need jumping back to restore a already hibernated kernel image? Can you please tell little more about jumping back and why it is needed?

Now, the jumping back is used to implement "kexec based hibernation", which uses kexec/kdump to save the memory image of hibernated kernel during hibernating, and uses /dev/oldmem to restore the memory image of hibernated kernel and jump back to the hibernated kernel to continue run.

The other usage model maybe include:

- Dump the system memory image then continue to run, that is, get some memory snapshot of system during system running.
- Cooperative multi-task of different OS. You can load another OS (B) from current OS (A), and jump between the two OSes upon needed.
- Call some code (such as firmware, etc) in physical mode.

Quoted 10 lines
Quoted 9 lines

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

Quoted 3 lines

Ok, so due to swapping of source and destination pages first kernel's data is still preserved. How do I get the dynamic memory required for second kernel boot (without writing first kernel's data)?

All dynamic memory required for second kernel should be "loaded" by sys_kexec_load in first kernel. For example, not only the Linux kernel should be loaded at 1M, the memory 0~16M (exclude kernel) should be "loaded" (all zero) by /sbin/kexec via sys_kexec_load too.

Quoted 91 lines
Quoted 91 lines

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S      |  214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +22 -2
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 136

Quoted 5 lines
arch/x86/kernel/machine_kexec_32.c +2 -1
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 

Is 2K sufficient for all the code in relocate_kernel_32.S? What's the current size?

The current size is 0x2d7 (727). I got it though objdump, machine_crash_shutdown - relocate_page. I think we have enough space.

Quoted 4 lines
Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 146

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +6 -0
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);

Who fills the entry point at offset 0x200?

The entry point is filled by assembler code in reloate_kernel_32.S upon jumping back. You can find it by "grep ENTRY relocate_kernel_32.S".

Quoted 12 lines

[..]

arch/x86/kernel/machine_kexec_32.c

Quoted 8 lines

extern int machine_kexec_prepare(struct kimage *image); extern void machine_kexec_cleanup(struct kimage *image); extern asmlinkage long sys_kexec_load(unsigned long entry,

arch/x86/kernel/machine_kexec_32.c +2 -0
 					unsigned long nr_segments,
 					struct kexec_segment __user *segments,
 					unsigned long flags);
+extern int kexec_call(struct kimage *image, unsigned long *ret,
+		      unsigned int argc, ...);

Who is using kexec_call(). I can't seem to locate the caller of it.

There is no user of kexec_call() now. But I think it may be useful as a physical mode caller for some firmware code.

Best Regards,
Huang Ying

#11 lore raw
In reply to Huang, Ying
Quoted 34 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

[..]

include/linux/kexec.h unsigned long paddr_vmcoreinfo_note(void · line 185

Quoted 9 lines
include/linux/kexec.h +6 -2
-#define KEXEC_ON_CRASH  0x00000001
-#define KEXEC_ARCH_MASK 0xffff0000
+#define KEXEC_ON_CRASH		0x00000001
+#define KEXEC_PRESERVE_CPU	0x00000002
+#define KEXEC_PRESERVE_CPU_EXT	0x00000004
+#define KEXEC_SINGLE_CPU	0x00000008
+#define KEXEC_PRESERVE_DEVICE	0x00000010
+#define KEXEC_PRESERVE_CONSOLE	0x00000020

Hi,

Why do we need so many different flags for preserving different types of state (CPU, CPU_EXT, Device, console) ? To keep things simple, can't we can create just one flag KEXEC_PRESERVE_CONTEXT, which will indicate any special action required for preserving the previous kernel's context so that one can swith back to old kernel?

Thanks
Vivek

#12 lore raw
In reply to Huang, Ying
Quoted 34 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

[..]

include/linux/kexec.h unsigned long paddr_vmcoreinfo_note(void · line 185

Quoted 9 lines
include/linux/kexec.h +6 -2
-#define KEXEC_ON_CRASH  0x00000001
-#define KEXEC_ARCH_MASK 0xffff0000
+#define KEXEC_ON_CRASH		0x00000001
+#define KEXEC_PRESERVE_CPU	0x00000002
+#define KEXEC_PRESERVE_CPU_EXT	0x00000004
+#define KEXEC_SINGLE_CPU	0x00000008
+#define KEXEC_PRESERVE_DEVICE	0x00000010
+#define KEXEC_PRESERVE_CONSOLE	0x00000020

Hi,

Why do we need so many different flags for preserving different types of state (CPU, CPU_EXT, Device, console) ? To keep things simple, can't we can create just one flag KEXEC_PRESERVE_CONTEXT, which will indicate any special action required for preserving the previous kernel's context so that one can swith back to old kernel?

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#13 lore raw
Quoted 13 lines · Vivek Goyal

[..]

include/linux/kexec.h unsigned long paddr_vmcoreinfo_note(void · line 185

Quoted 9 lines
include/linux/kexec.h +6 -2
-#define KEXEC_ON_CRASH  0x00000001
-#define KEXEC_ARCH_MASK 0xffff0000
+#define KEXEC_ON_CRASH		0x00000001
+#define KEXEC_PRESERVE_CPU	0x00000002
+#define KEXEC_PRESERVE_CPU_EXT	0x00000004
+#define KEXEC_SINGLE_CPU	0x00000008
+#define KEXEC_PRESERVE_DEVICE	0x00000010
+#define KEXEC_PRESERVE_CONSOLE	0x00000020

Hi,

Quoted 5 lines

Why do we need so many different flags for preserving different types of state (CPU, CPU_EXT, Device, console) ? To keep things simple, can't we can create just one flag KEXEC_PRESERVE_CONTEXT, which will indicate any special action required for preserving the previous kernel's context so that one can swith back to old kernel?

Yes. There are too many flags, especially when we have no users of these flags now. It is better to use one flag such as KEXEC_PRESERVE_CONTEXT now, and create the others required flags when really needed.

Best Regards,
Huang Ying

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#14 lore raw
In reply to Vivek Goyal
Quoted 13 lines · Vivek Goyal

[..]

include/linux/kexec.h unsigned long paddr_vmcoreinfo_note(void · line 185

Quoted 9 lines
include/linux/kexec.h +6 -2
-#define KEXEC_ON_CRASH  0x00000001
-#define KEXEC_ARCH_MASK 0xffff0000
+#define KEXEC_ON_CRASH		0x00000001
+#define KEXEC_PRESERVE_CPU	0x00000002
+#define KEXEC_PRESERVE_CPU_EXT	0x00000004
+#define KEXEC_SINGLE_CPU	0x00000008
+#define KEXEC_PRESERVE_DEVICE	0x00000010
+#define KEXEC_PRESERVE_CONSOLE	0x00000020

Hi,

Quoted 5 lines

Why do we need so many different flags for preserving different types of state (CPU, CPU_EXT, Device, console) ? To keep things simple, can't we can create just one flag KEXEC_PRESERVE_CONTEXT, which will indicate any special action required for preserving the previous kernel's context so that one can swith back to old kernel?

Yes. There are too many flags, especially when we have no users of these flags now. It is better to use one flag such as KEXEC_PRESERVE_CONTEXT now, and create the others required flags when really needed.

Best Regards,
Huang Ying

#15 lore raw
In reply to Huang, Ying
Quoted 91 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S | 214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +15 -1
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+ change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +2 -1
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

Quoted 70 lines
arch/x86/kernel/machine_kexec_32.c +36 -17
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);
+			if (ret)
+				*ret = KCALL_ARGS(control_page)[0];
+			return 0;
+		}
+	}
+
+	relocate_kernel_ptr = control_page +
+		((void *)relocate_kernel - (void *)relocate_page);
 	page_list[PA_CONTROL_PAGE] = __pa(control_page);
-	page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
+	page_list[VA_CONTROL_PAGE] = (unsigned long)control_page;
 	page_list[PA_PGD] = __pa(kexec_pgd);
 	page_list[VA_PGD] = (unsigned long)kexec_pgd;
 #ifdef CONFIG_X86_PAE
@@ -127,26 +166,33 @@ NORET_TYPE void machine_kexec(struct kim
 	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
 	page_list[PA_PTE_1] = __pa(kexec_pte1);
 	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
+ page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) << PAGE_SHIFT);
 
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +10 -0
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

More later.

Eric

#16 lore raw
In reply to Huang, Ying
Quoted 91 lines · Ying

This patch implements the functionality of jumping between the kexeced kernel and the original kernel.

To support jumping between two kernels, before jumping to (executing) the new kernel and jumping back to the original kernel, the devices are put into quiescent state, and the state of devices and CPU is saved. After jumping back from kexeced kernel and jumping to the new kernel, the state of devices and CPU are restored accordingly. The devices/CPU state save/restore code of software suspend is called to implement corresponding function.

To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by new (kexeced) kernel (destination page). When do kexec_load, the image of new kernel is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the new (kexeced) kernel and after jumping back to the original kernel, the destination pages and the source pages are swapped too.

A jump back protocol for kexec is defined and documented. It is an extension to ordinary function calling protocol. So, the facility provided by this patch can be used to call ordinary C function in real mode.

A set of flags for sys_kexec_load are added to control which state are saved/restored before/after real mode code executing. For example, you can specify the device state and FPU state are saved/restored before/after real mode code executing.

The states (exclude CPU state) save/restore code can be overridden based on the "command" parameter of kexec jump. Because more states need to be saved/restored by hibernating/resuming.

---
 Documentation/i386/jump_back_protocol.txt |  103 ++++++++++++++
 arch/powerpc/kernel/machine_kexec.c       |    2 
 arch/ppc/kernel/machine_kexec.c           |    2 
 arch/sh/kernel/machine_kexec.c            |    2 
 arch/x86/kernel/machine_kexec_32.c        |   88 +++++++++---
 arch/x86/kernel/machine_kexec_64.c        |    2 
 arch/x86/kernel/relocate_kernel_32.S | 214 +++++++++++++++++++++++++++---
 include/asm-x86/kexec_32.h                |   39 ++++-
 include/linux/kexec.h                     |   40 +++++
 kernel/kexec.c                            |  188 ++++++++++++++++++++++++++
 kernel/power/Kconfig                      |    2 
 kernel/sys.c                              |   35 +++-
 12 files changed, 648 insertions(+), 69 deletions(-)
arch/x86/kernel/machine_kexec_32.c +15 -1
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 static u32 kexec_pgd[1024] PAGE_ALIGNED;
@@ -83,10 +84,14 @@ static void load_segments(void)
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Currently nothing.
+ * Turn off NX bit for control page.
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	if (nx_enabled) {
+ change_page_attr(image->control_code_page, 1, PAGE_KERNEL_EXEC);
+		global_flush_tlb();
+	}
 	return 0;
 }
 
@@ -96,25 +101,59 @@ int machine_kexec_prepare(struct kimage 
  */
 void machine_kexec_cleanup(struct kimage *image)
 {
+	if (nx_enabled) {
+		change_page_attr(image->control_code_page, 1, PAGE_KERNEL);
+		global_flush_tlb();
+	}
+}
+
+void machine_kexec(struct kimage *image)
+{
+	machine_kexec_call(image, NULL, 0);

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +2 -1
 }
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

Quoted 70 lines
arch/x86/kernel/machine_kexec_32.c +36 -17
 	unsigned long page_list[PAGES_NR];
 	void *control_page;
+	asmlinkage NORET_TYPE void
+		(*relocate_kernel_ptr)(unsigned long indirection_page,
+				       unsigned long control_page,
+				       unsigned long start_address,
+				       unsigned int has_pae) ATTRIB_NORET;
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
 	control_page = page_address(image->control_code_page);
-	memcpy(control_page, relocate_kernel, PAGE_SIZE);
+	memcpy(control_page, relocate_page, PAGE_SIZE/2);
+	KCALL_MAGIC(control_page) = 0;
 
+	if (image->preserve_cpu) {
+		unsigned int i;
+		KCALL_MAGIC(control_page) = KCALL_MAGIC_NUMBER;
+		KCALL_ARGC(control_page) = argc;
+		for (i = 0; i < argc; i++)
+			KCALL_ARGS(control_page)[i] = \
+				va_arg(args, unsigned long);
+
+		if (kexec_call_save_cpu(control_page)) {
+			image->start = KCALL_ENTRY(control_page);
+			if (ret)
+				*ret = KCALL_ARGS(control_page)[0];
+			return 0;
+		}
+	}
+
+	relocate_kernel_ptr = control_page +
+		((void *)relocate_kernel - (void *)relocate_page);
 	page_list[PA_CONTROL_PAGE] = __pa(control_page);
-	page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
+	page_list[VA_CONTROL_PAGE] = (unsigned long)control_page;
 	page_list[PA_PGD] = __pa(kexec_pgd);
 	page_list[VA_PGD] = (unsigned long)kexec_pgd;
 #ifdef CONFIG_X86_PAE
@@ -127,26 +166,33 @@ NORET_TYPE void machine_kexec(struct kim
 	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
 	page_list[PA_PTE_1] = __pa(kexec_pte1);
 	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
+ page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) << PAGE_SHIFT);
 
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 10 lines
arch/x86/kernel/machine_kexec_32.c +10 -0
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

More later.

Eric

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#17 lore raw
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Another usage model may be useful is invoking the kexec image (such as firmware) from kernel space.

- kmalloc the needed memory and loaded the firmware image (if needed)
- sys_kexec_load() with a fake image (one segment with size 0), the entry point of the fake image is the entry point of the firmware image.
- kexec_call(fake_image, ...) /* maybe change entry point if needed */

This way, some kernel code can invoke the firmware in physical mode just like invoking an ordinary function.

[...]

Quoted 30 lines
Quoted 30 lines
arch/x86/kernel/machine_kexec_32.c +15 -15
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

The original idea about this code is:

If the kexec image is claimed that it need not to "perserving extensive CPU state" (such as FPU/MMX/GDT/LDT/IDT/CS/DS/ES/FS/GS/SS etc), the IDT/GDT/CS/DS/ES/FS/GS/SS are not touched in kexec image code. So the segment registers need not to be set.

But this is not clear. At least more description should be provided for each preserve flag.

Quoted 10 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

You mean I should change the function pointer name to rnk to keep consistency? I find rnk in IA64 implementation.

Best Regards,
Huang Ying

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#18 lore raw
Quoted 32 lines · Ying
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

Quoted 8 lines

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Interesting. We wind up preserving the code in between invocations.

I don't know about your particular issue, but I can see that clearly we need a way to read values back from our target image.

And if we can read everything back one way to proceed is to read everything out modify it and then write it back.

Amending a kexec image that is already stored may also make sense.

I'm not convinced that the var arg parameters make sense, but you added them because of a real need.

The kexec function is split into two separate calls so that we can unmount the filesystem the kexec image comes from before actually doing the kexec.

If extensive user space shutdown or startup is needed I will argue that doing the work in the sys_reboot call is the wrong place to do it. Although if a jump back is happening we should not need much restart.

Can you generate a minimal patch with just the minimal necessary support to return from a kexec operation?

Quoted 10 lines

Another usage model may be useful is invoking the kexec image (such as firmware) from kernel space.

- kmalloc the needed memory and loaded the firmware image (if needed)
- sys_kexec_load() with a fake image (one segment with size 0), the entry point of the fake image is the entry point of the firmware image.
- kexec_call(fake_image, ...) /* maybe change entry point if needed */

This way, some kernel code can invoke the firmware in physical mode just like invoking an ordinary function.

That certainly seems interesting. But that doesn't justify the vararg part of this.

Quoted 42 lines

[...]

Quoted 30 lines
Quoted 30 lines
arch/x86/kernel/machine_kexec_32.c +15 -15
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

The original idea about this code is:

Quoted 7 lines

If the kexec image is claimed that it need not to "perserving extensive CPU state" (such as FPU/MMX/GDT/LDT/IDT/CS/DS/ES/FS/GS/SS etc), the IDT/GDT/CS/DS/ES/FS/GS/SS are not touched in kexec image code. So the segment registers need not to be set.

But this is not clear. At least more description should be provided for each preserve flag.

yes.

Quoted 11 lines
Quoted 10 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

Quoted 2 lines

You mean I should change the function pointer name to rnk to keep consistency? I find rnk in IA64 implementation.

You were changing something that used to be a pointer back to a pointer
and I found that confusing. See the last one or two commits to
machine_kexec_32.c for when this happened. I get the feeling that we need to put the page table creation logic into machine_kexec_prepare, instead of in assembly.

Eric

#19 lore raw
In reply to Huang, Ying
Quoted 32 lines · Ying
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

Quoted 8 lines

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Interesting. We wind up preserving the code in between invocations.

I don't know about your particular issue, but I can see that clearly we need a way to read values back from our target image.

And if we can read everything back one way to proceed is to read everything out modify it and then write it back.

Amending a kexec image that is already stored may also make sense.

I'm not convinced that the var arg parameters make sense, but you added them because of a real need.

The kexec function is split into two separate calls so that we can unmount the filesystem the kexec image comes from before actually doing the kexec.

If extensive user space shutdown or startup is needed I will argue that doing the work in the sys_reboot call is the wrong place to do it. Although if a jump back is happening we should not need much restart.

Can you generate a minimal patch with just the minimal necessary support to return from a kexec operation?

Quoted 10 lines

Another usage model may be useful is invoking the kexec image (such as firmware) from kernel space.

- kmalloc the needed memory and loaded the firmware image (if needed)
- sys_kexec_load() with a fake image (one segment with size 0), the entry point of the fake image is the entry point of the firmware image.
- kexec_call(fake_image, ...) /* maybe change entry point if needed */

This way, some kernel code can invoke the firmware in physical mode just like invoking an ordinary function.

That certainly seems interesting. But that doesn't justify the vararg part of this.

Quoted 42 lines

[...]

Quoted 30 lines
Quoted 30 lines
arch/x86/kernel/machine_kexec_32.c +15 -15
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

The original idea about this code is:

Quoted 7 lines

If the kexec image is claimed that it need not to "perserving extensive CPU state" (such as FPU/MMX/GDT/LDT/IDT/CS/DS/ES/FS/GS/SS etc), the IDT/GDT/CS/DS/ES/FS/GS/SS are not touched in kexec image code. So the segment registers need not to be set.

But this is not clear. At least more description should be provided for each preserve flag.

yes.

Quoted 11 lines
Quoted 10 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

Quoted 2 lines

You mean I should change the function pointer name to rnk to keep consistency? I find rnk in IA64 implementation.

You were changing something that used to be a pointer back to a pointer
and I found that confusing. See the last one or two commits to
machine_kexec_32.c for when this happened. I get the feeling that we need to put the page table creation logic into machine_kexec_prepare, instead of in assembly.

Eric

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#20 lore raw
Quoted 51 lines · Eric W. Biederman
Quoted 32 lines · Ying
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

Quoted 8 lines

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Interesting. We wind up preserving the code in between invocations.

I don't know about your particular issue, but I can see that clearly we need a way to read values back from our target image.

And if we can read everything back one way to proceed is to read everything out modify it and then write it back.

Quoted 8 lines

Amending a kexec image that is already stored may also make sense.

I'm not convinced that the var arg parameters make sense, but you added them because of a real need.

The kexec function is split into two separate calls so that we can unmount the filesystem the kexec image comes from before actually doing the kexec.

Yes. Reading/Modifying the loaded kexec image is another way to do necessary communication between the first kernel and the second kernel. In fact, the patch [4/4] of this series with title:

[PATCH 4/4 -mm] kexec based hibernation -v7 : kimgcore

provide a ELF CORE file in /proc (/proc/kimgcore) to read the loaded kexec image. The writing function can be added easily.

But I think communication between the first kernel and the second kernel via reading/modifying the loaded kernel image is not very convenient way. The usage mode may be as follow:

- sys_kexec_load() /* with executable/data loaded */
- modify the loaded kexec image to set the parameters (A)
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- In physical mode code, check the parameters A and executing accordingly
- modify the loaded kexec image to set the parameters (B)
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- In physical mode code, check the parameters B and executing accordingly

There are some issues with this usage model:

- Some parameters in kernel needed to be exported (such as the kimage->head to let the second kernel to read the memory contents of backupped memory).

- The physical mode code invoker (the first kernel) need to know where to write the parameters. A common protocol or a protocol case by case should be defined. For example, the memory address after the entry point of kexec image is a good candidate. But for Linux kernel, there are two types of entry point, the "jump back entry" or "purgatory". Maybe different protocol should be defined for these two types of entry point.

- For the user space of the second kernel to get the parameters. A interface (maybe a file in /proc or /sys) should be provided to export the parameters to user space.

So I think the current parameters passing mechanism may be more simple and convenient (defined in Document/i386/jump_back_protocol.txt in the patch).

There is only one user of var args. But I think it is simple to be implemented and may be used by others.

Quoted 4 lines

If extensive user space shutdown or startup is needed I will argue that doing the work in the sys_reboot call is the wrong place to do it. Although if a jump back is happening we should not need much restart.

Now, the user space is not shut down or started up across kexec/jump back, just the sys_reboot call is used to trigger the kexec/jump back. Maybe sys_reboot is not the right place to do this. Can you recommended a more suitable place?

Quoted 2 lines

Can you generate a minimal patch with just the minimal necessary support to return from a kexec operation?

I plan to reduce the KEXEC_PRESERVE_XXX flags into one KEXEC_PRESERVE_CONTEXT. The var args part may be changed if we have the consensus.

Quoted 77 lines
Quoted 10 lines

Another usage model may be useful is invoking the kexec image (such as firmware) from kernel space.

- kmalloc the needed memory and loaded the firmware image (if needed)
- sys_kexec_load() with a fake image (one segment with size 0), the entry point of the fake image is the entry point of the firmware image.
- kexec_call(fake_image, ...) /* maybe change entry point if needed */

This way, some kernel code can invoke the firmware in physical mode just like invoking an ordinary function.

That certainly seems interesting. But that doesn't justify the vararg part of this.

Quoted 42 lines

[...]

Quoted 30 lines
Quoted 30 lines
arch/x86/kernel/machine_kexec_32.c +15 -15
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

The original idea about this code is:

Quoted 7 lines

If the kexec image is claimed that it need not to "perserving extensive CPU state" (such as FPU/MMX/GDT/LDT/IDT/CS/DS/ES/FS/GS/SS etc), the IDT/GDT/CS/DS/ES/FS/GS/SS are not touched in kexec image code. So the segment registers need not to be set.

But this is not clear. At least more description should be provided for each preserve flag.

yes.

Quoted 11 lines
Quoted 10 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

Quoted 6 lines
Quoted 2 lines

You mean I should change the function pointer name to rnk to keep consistency? I find rnk in IA64 implementation.

You were changing something that used to be a pointer back to a pointer
and I found that confusing. See the last one or two commits to
machine_kexec_32.c for when this happened.

After checking the history of machine_kexec_32.c, I find the pointer is removed because a specific PGD is used. My reason is a little different. I need save some information (the preserving registers, some control registers, swap page address etc) in control_page, it is more convenient to execute on identity map of control_page. I think it is not a big issue. In fact, my code can work without making relocate_kernel to pointer with some changes.

Quoted 3 lines

I get the feeling that we
need to put the page table creation logic into machine_kexec_prepare, instead of in assembly.

Yes. I think this is a good idea, and the kexec_pgd, kexec_pmd0/1, kexec_pte0/1 can be allocated in machine_kexec_prepare too to save the static memory usage.

Best Regards,
Huang Ying

#21 lore raw
In reply to Eric W. Biederman
Quoted 51 lines · Eric W. Biederman
Quoted 32 lines · Ying
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

Quoted 8 lines

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Interesting. We wind up preserving the code in between invocations.

I don't know about your particular issue, but I can see that clearly we need a way to read values back from our target image.

And if we can read everything back one way to proceed is to read everything out modify it and then write it back.

Quoted 8 lines

Amending a kexec image that is already stored may also make sense.

I'm not convinced that the var arg parameters make sense, but you added them because of a real need.

The kexec function is split into two separate calls so that we can unmount the filesystem the kexec image comes from before actually doing the kexec.

Yes. Reading/Modifying the loaded kexec image is another way to do necessary communication between the first kernel and the second kernel. In fact, the patch [4/4] of this series with title:

[PATCH 4/4 -mm] kexec based hibernation -v7 : kimgcore

provide a ELF CORE file in /proc (/proc/kimgcore) to read the loaded kexec image. The writing function can be added easily.

But I think communication between the first kernel and the second kernel via reading/modifying the loaded kernel image is not very convenient way. The usage mode may be as follow:

- sys_kexec_load() /* with executable/data loaded */
- modify the loaded kexec image to set the parameters (A)
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- In physical mode code, check the parameters A and executing accordingly
- modify the loaded kexec image to set the parameters (B)
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- In physical mode code, check the parameters B and executing accordingly

There are some issues with this usage model:

- Some parameters in kernel needed to be exported (such as the kimage->head to let the second kernel to read the memory contents of backupped memory).

- The physical mode code invoker (the first kernel) need to know where to write the parameters. A common protocol or a protocol case by case should be defined. For example, the memory address after the entry point of kexec image is a good candidate. But for Linux kernel, there are two types of entry point, the "jump back entry" or "purgatory". Maybe different protocol should be defined for these two types of entry point.

- For the user space of the second kernel to get the parameters. A interface (maybe a file in /proc or /sys) should be provided to export the parameters to user space.

So I think the current parameters passing mechanism may be more simple and convenient (defined in Document/i386/jump_back_protocol.txt in the patch).

There is only one user of var args. But I think it is simple to be implemented and may be used by others.

Quoted 4 lines

If extensive user space shutdown or startup is needed I will argue that doing the work in the sys_reboot call is the wrong place to do it. Although if a jump back is happening we should not need much restart.

Now, the user space is not shut down or started up across kexec/jump back, just the sys_reboot call is used to trigger the kexec/jump back. Maybe sys_reboot is not the right place to do this. Can you recommended a more suitable place?

Quoted 2 lines

Can you generate a minimal patch with just the minimal necessary support to return from a kexec operation?

I plan to reduce the KEXEC_PRESERVE_XXX flags into one KEXEC_PRESERVE_CONTEXT. The var args part may be changed if we have the consensus.

Quoted 77 lines
Quoted 10 lines

Another usage model may be useful is invoking the kexec image (such as firmware) from kernel space.

- kmalloc the needed memory and loaded the firmware image (if needed)
- sys_kexec_load() with a fake image (one segment with size 0), the entry point of the fake image is the entry point of the firmware image.
- kexec_call(fake_image, ...) /* maybe change entry point if needed */

This way, some kernel code can invoke the firmware in physical mode just like invoking an ordinary function.

That certainly seems interesting. But that doesn't justify the vararg part of this.

Quoted 42 lines

[...]

Quoted 30 lines
Quoted 30 lines
arch/x86/kernel/machine_kexec_32.c +15 -15
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

The original idea about this code is:

Quoted 7 lines

If the kexec image is claimed that it need not to "perserving extensive CPU state" (such as FPU/MMX/GDT/LDT/IDT/CS/DS/ES/FS/GS/SS etc), the IDT/GDT/CS/DS/ES/FS/GS/SS are not touched in kexec image code. So the segment registers need not to be set.

But this is not clear. At least more description should be provided for each preserve flag.

yes.

Quoted 11 lines
Quoted 10 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

Quoted 6 lines
Quoted 2 lines

You mean I should change the function pointer name to rnk to keep consistency? I find rnk in IA64 implementation.

You were changing something that used to be a pointer back to a pointer
and I found that confusing. See the last one or two commits to
machine_kexec_32.c for when this happened.

After checking the history of machine_kexec_32.c, I find the pointer is removed because a specific PGD is used. My reason is a little different. I need save some information (the preserving registers, some control registers, swap page address etc) in control_page, it is more convenient to execute on identity map of control_page. I think it is not a big issue. In fact, my code can work without making relocate_kernel to pointer with some changes.

Quoted 3 lines

I get the feeling that we
need to put the page table creation logic into machine_kexec_prepare, instead of in assembly.

Yes. I think this is a good idea, and the kexec_pgd, kexec_pmd0/1, kexec_pte0/1 can be allocated in machine_kexec_prepare too to save the static memory usage.

Best Regards,
Huang Ying

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#22 lore raw
In reply to Eric W. Biederman
Quoted 51 lines · Eric W. Biederman
Quoted 32 lines · Ying
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

Quoted 8 lines

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Interesting. We wind up preserving the code in between invocations.

I don't know about your particular issue, but I can see that clearly we need a way to read values back from our target image.

And if we can read everything back one way to proceed is to read everything out modify it and then write it back.

Quoted 8 lines

Amending a kexec image that is already stored may also make sense.

I'm not convinced that the var arg parameters make sense, but you added them because of a real need.

The kexec function is split into two separate calls so that we can unmount the filesystem the kexec image comes from before actually doing the kexec.

My real issue is that I need a kind of "kernel to kernel" communication method. The var args is just a convenient way to pass an array of unsigned longs between two kernels. The reason is as follow:

The kexec based hibernating process is as follow:

h1. put devices in quiescent state
h2. save devices/CPU state
h3. jump to kexeced kernel (kernel B)
*h4. normal kernel boot of kernel B
*h5. save devices/CPU state
*h6. jump back to original kernel (kernel A) h7. restore devices/CPU state
h8. put devices in quiescent state
h9. put devices in low power state
h10. execute necessary ACPI method (prepare to sleep) h11. save devices/CPU state
h12. jump to kernel B
*h13. execute necessary ACPI method (wake up) *h14. restore devices/CPU state
*h15. put devices in normal power state
*h16. write memory image of kernel A into disk *h17. put system into ACPI S4 state

The kexec based resuming process is as follow:

*r1. boot the resuming kernel (kernel C)
*r2. restore the memory image of kernel A *r3. put devices in quiescent state
*r4. execute necessary ACPI method (prepare to resume) *r5. jump to kernel A
r6. execute necessary ACPI method (wake up) r7. restore devices/CPU state

Where, line begin with "*" is executed in kernel B and kernel C, others are executed in kernel A.

The kernel A need to distinguish the difference between h7 and r6, while the kernel B/C need to distinguish between *h13 and normal jump back. The different kernel action need to be taken depends on the action of peer kernel. Now, this is solved by kernel-kernel communication, a command word is passed to peer kernel to inform the action required.

I remember you have said before that you think it is better to use only "user space to user space" communication between kernel A and kernel B. This is OK for normal kexec. But if the kexec jump is used for multiple functions with early kernel action involved (normal kexec jump, kexec jump to hibernate, kexec jump to resume), it is necessary to use "kernel to kernel" communication.

The var args in the patch is just an array of unsigned longs, it can be expresses as follow too.

int kexec_call(struct kimage *image, unsigned long *ret, unsigned int argc, unsigned long argv[]);

The var args version is as follow.

int kexec_call(struct kimage *image, unsigned long *ret, unsigned int argc, ...);

Best Regards,
Huang Ying

#23 lore raw
In reply to Eric W. Biederman
Quoted 51 lines · Eric W. Biederman
Quoted 32 lines · Ying
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

Quoted 8 lines

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Interesting. We wind up preserving the code in between invocations.

I don't know about your particular issue, but I can see that clearly we need a way to read values back from our target image.

And if we can read everything back one way to proceed is to read everything out modify it and then write it back.

Quoted 8 lines

Amending a kexec image that is already stored may also make sense.

I'm not convinced that the var arg parameters make sense, but you added them because of a real need.

The kexec function is split into two separate calls so that we can unmount the filesystem the kexec image comes from before actually doing the kexec.

My real issue is that I need a kind of "kernel to kernel" communication method. The var args is just a convenient way to pass an array of unsigned longs between two kernels. The reason is as follow:

The kexec based hibernating process is as follow:

h1. put devices in quiescent state
h2. save devices/CPU state
h3. jump to kexeced kernel (kernel B)
*h4. normal kernel boot of kernel B
*h5. save devices/CPU state
*h6. jump back to original kernel (kernel A) h7. restore devices/CPU state
h8. put devices in quiescent state
h9. put devices in low power state
h10. execute necessary ACPI method (prepare to sleep) h11. save devices/CPU state
h12. jump to kernel B
*h13. execute necessary ACPI method (wake up) *h14. restore devices/CPU state
*h15. put devices in normal power state
*h16. write memory image of kernel A into disk *h17. put system into ACPI S4 state

The kexec based resuming process is as follow:

*r1. boot the resuming kernel (kernel C)
*r2. restore the memory image of kernel A *r3. put devices in quiescent state
*r4. execute necessary ACPI method (prepare to resume) *r5. jump to kernel A
r6. execute necessary ACPI method (wake up) r7. restore devices/CPU state

Where, line begin with "*" is executed in kernel B and kernel C, others are executed in kernel A.

The kernel A need to distinguish the difference between h7 and r6, while the kernel B/C need to distinguish between *h13 and normal jump back. The different kernel action need to be taken depends on the action of peer kernel. Now, this is solved by kernel-kernel communication, a command word is passed to peer kernel to inform the action required.

I remember you have said before that you think it is better to use only "user space to user space" communication between kernel A and kernel B. This is OK for normal kexec. But if the kexec jump is used for multiple functions with early kernel action involved (normal kexec jump, kexec jump to hibernate, kexec jump to resume), it is necessary to use "kernel to kernel" communication.

The var args in the patch is just an array of unsigned longs, it can be expresses as follow too.

int kexec_call(struct kimage *image, unsigned long *ret, unsigned int argc, unsigned long argv[]);

The var args version is as follow.

int kexec_call(struct kimage *image, unsigned long *ret, unsigned int argc, ...);

Best Regards,
Huang Ying

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#24 lore raw
In reply to Eric W. Biederman
Quoted 1 line · Eric W. Biederman

"Huang, Ying" <[email protected]> writes:

[...]

Quoted 11 lines

arch/x86/kernel/machine_kexec_32.c int machine_kexec_prepare(struct kimage · line 121

Quoted 8 lines

/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now. */

arch/x86/kernel/machine_kexec_32.c +2 -1
-NORET_TYPE void machine_kexec(struct kimage *image)
+int machine_kexec_vcall(struct kimage *image, unsigned long *ret,
+			 unsigned int argc, va_list args)
 {

Why do we need var arg support?
Can't we do that with a shim we load from user space?

If all parameters are provided in user space, the usage model may be as follow:

- sys_kexec_load() /* with executable/data/parameters(A) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(A)*/
- /* jump back */
- sys_kexec_load() /* with executable/data/parameters(B) loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,) /* execute physical mode code with parameters(B)*/
- /* jump back */

That is, the kexec image should be re-loaded if the parameters are different, and there can be no state reserved in kexec image. This is OK for original kexec implementation, because there is no jumping back. But, for kexec with jumping back, another usage model may be useful too.

- sys_kexec_load() /* with executable/data loaded */
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(A)) /* execute physical mode code with parameters(A)*/
- sys_reboot(,,LINUX_REBOOT_CMD_KEXEC,parameters(B)) /* execute physical mode code with parameters(B)*/

This way the kexec image need not to be re-loaded, and the state of kexec image can be reserved across several invoking.

Another usage model may be useful is invoking the kexec image (such as firmware) from kernel space.

- kmalloc the needed memory and loaded the firmware image (if needed)
- sys_kexec_load() with a fake image (one segment with size 0), the entry point of the fake image is the entry point of the firmware image.
- kexec_call(fake_image, ...) /* maybe change entry point if needed */

This way, some kernel code can invoke the firmware in physical mode just like invoking an ordinary function.

[...]

Quoted 30 lines
Quoted 30 lines
arch/x86/kernel/machine_kexec_32.c +15 -15
-	/* The segment registers are funny things, they have both a
-	 * visible and an invisible part.  Whenever the visible part is
-	 * set to a specific selector, the invisible part is loaded
-	 * with from a table in memory.  At no other time is the
-	 * descriptor table in memory accessed.
-	 *
-	 * I take advantage of this here by force loading the
-	 * segments, before I zap the gdt with an invalid value.
-	 */
-	load_segments();
-	/* The gdt & idt are now invalid.
-	 * If you want to load them you must set up your own idt & gdt.
-	 */
-	set_gdt(phys_to_virt(0),0);
-	set_idt(phys_to_virt(0),0);
+	if (image->preserve_cpu_ext) {
+		/* The segment registers are funny things, they have
+		 * both a visible and an invisible part.  Whenever the
+		 * visible part is set to a specific selector, the
+		 * invisible part is loaded with from a table in
+		 * memory.  At no other time is the descriptor table
+		 * in memory accessed.
+		 *
+		 * I take advantage of this here by force loading the
+		 * segments, before I zap the gdt with an invalid
+		 * value.
+		 */
+		load_segments();
+		/* The gdt & idt are now invalid.  If you want to load
+		 * them you must set up your own idt & gdt.
Quoted 8 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 189

Quoted 4 lines
arch/x86/kernel/machine_kexec_32.c +4 -0
+		 */
+		set_gdt(phys_to_virt(0), 0);
+		set_idt(phys_to_virt(0), 0);
+	}

We can't keep the same idt and gdt as the pages they are on will be overwritten/reused. So explictily stomping on them sounds better so they never work. We can restore them on kernel reentry.

The original idea about this code is:

If the kexec image is claimed that it need not to "perserving extensive CPU state" (such as FPU/MMX/GDT/LDT/IDT/CS/DS/ES/FS/GS/SS etc), the IDT/GDT/CS/DS/ES/FS/GS/SS are not touched in kexec image code. So the segment registers need not to be set.

But this is not clear. At least more description should be provided for each preserve flag.

Quoted 10 lines

arch/x86/kernel/machine_kexec_32.c NORET_TYPE void machine_kexec(struct kim · line 194

Quoted 6 lines
arch/x86/kernel/machine_kexec_32.c +3 -2
 	/* now call it */
-	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
-			image->start, cpu_has_pae);
+	relocate_kernel_ptr((unsigned long)image->head,
+			    (unsigned long)page_list,
+			    image->start, cpu_has_pae);

Why rename relocate_kernel?
Ah. I see. You need to make it into a pointer again. The crazy don't stop the pgd support strikes again. It used to be named rnk.

You mean I should change the function pointer name to rnk to keep consistency? I find rnk in IA64 implementation.

Best Regards,
Huang Ying