linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Andrey Ryabinin <arbn@yandex-team.com>
To: linux-kernel@vger.kernel.org
Cc: Alexander Graf <graf@amazon.com>,
	James Gowans <jgowans@amazon.com>,
	Mike Rapoport <rppt@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	linux-mm@kvack.org, Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	x86@kernel.org, "H . Peter Anvin" <hpa@zytor.com>,
	Eric Biederman <ebiederm@xmission.com>,
	kexec@lists.infradead.org, Pratyush Yadav <ptyadav@amazon.de>,
	Jason Gunthorpe <jgg@nvidia.com>,
	Pasha Tatashin <pasha.tatashin@soleen.com>,
	David Rientjes <rientjes@google.com>,
	Andrey Ryabinin <arbn@yandex-team.com>
Subject: [PATCH v2 2/7] kstate, kexec, x86: transfer kstate data across kexec
Date: Mon, 10 Mar 2025 13:03:13 +0100	[thread overview]
Message-ID: <20250310120318.2124-3-arbn@yandex-team.com> (raw)
In-Reply-To: <20250310120318.2124-1-arbn@yandex-team.com>

Add kstate data to kexec segments so it got copied to the new kernel.
Use cmdline to inform next kernel about kstate data location and size.

Signed-off-by: Andrey Ryabinin <arbn@yandex-team.com>
---
I've used cmdline as it's the simplest way to transfer address
to the new kernel. Perhaps passing it via dtb would be more elegant
solution, but I don't have strong opinion here.
---
 arch/x86/Kconfig                  |  1 +
 arch/x86/kernel/kexec-bzimage64.c |  4 +++
 arch/x86/kernel/setup.c           |  2 ++
 include/linux/kexec.h             |  2 ++
 include/linux/kstate.h            |  5 ++++
 kernel/kexec_file.c               |  5 ++++
 kernel/kstate.c                   | 49 ++++++++++++++++++++++++++++++-
 7 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 0e27ebd7e36a..7358d9e15957 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -90,6 +90,7 @@ config X86
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_KCOV			if X86_64
 	select ARCH_HAS_KERNEL_FPU_SUPPORT
+	select ARCH_HAS_KSTATE			if X86_64
 	select ARCH_HAS_MEM_ENCRYPT
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 68530fad05f7..d3c98c8bda29 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/kexec.h>
 #include <linux/kernel.h>
+#include <linux/kstate.h>
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/random.h>
@@ -77,6 +78,9 @@ static int setup_cmdline(struct kimage *image, struct boot_params *params,
 		len = sprintf(cmdline_ptr,
 			"elfcorehdr=0x%lx ", image->elf_load_addr);
 	}
+	if (IS_ENABLED(CONFIG_KSTATE))
+		len = sprintf(cmdline_ptr, "kstate_stream=0x0%lx@%ld ",
+			image->kstate_stream_addr, image->kstate_size);
 	memcpy(cmdline_ptr + len, cmdline, cmdline_len);
 	cmdline_len += len;
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index cebee310e200..b32c141ffcdd 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -15,6 +15,7 @@
 #include <linux/init_ohci1394_dma.h>
 #include <linux/initrd.h>
 #include <linux/iscsi_ibft.h>
+#include <linux/kstate.h>
 #include <linux/memblock.h>
 #include <linux/panic_notifier.h>
 #include <linux/pci.h>
@@ -992,6 +993,7 @@ void __init setup_arch(char **cmdline_p)
 
 	memblock_set_current_limit(ISA_END_ADDRESS);
 	e820__memblock_setup();
+	kstate_init();
 
 	/*
 	 * Needs to run after memblock setup because it needs the physical
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index f0e9f8eda7a3..bd82f04888a1 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -299,6 +299,8 @@ struct kimage {
 	unsigned long start;
 	struct page *control_code_page;
 	struct page *swap_page;
+	unsigned long kstate_stream_addr;
+	size_t kstate_size;
 	void *vmcoreinfo_data_copy; /* locates in the crash memory */
 
 	unsigned long nr_segments;
diff --git a/include/linux/kstate.h b/include/linux/kstate.h
index 4fc01e535bc0..ae583d090111 100644
--- a/include/linux/kstate.h
+++ b/include/linux/kstate.h
@@ -126,6 +126,8 @@ static inline unsigned long kstate_get_ulong(struct kstate_stream *stream)
 
 #ifdef CONFIG_KSTATE
 
+void kstate_init(void);
+
 int kstate_save_state(void);
 void free_kstate_stream(void);
 
@@ -137,14 +139,17 @@ int save_kstate(struct kstate_stream *stream, int id,
 		void *obj);
 void restore_kstate(struct kstate_stream *stream, int id,
 		const struct kstate_description *kstate, void *obj);
+int kstate_load_migrate_buf(struct kimage *image);
 
 #else
 
+static inline void kstate_init(void) { }
 #define kstate_register(state, obj)
 
 static inline int kstate_save_state(void) { return 0; }
 static inline void free_kstate_stream(void) { }
 
+static inline int kstate_load_migrate_buf(struct kimage *image) { return 0; }
 #endif
 
 
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 3eedb8c226ad..a024ff379133 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -14,6 +14,7 @@
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/kexec.h>
+#include <linux/kstate.h>
 #include <linux/memblock.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
@@ -253,6 +254,10 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
 	/* IMA needs to pass the measurement list to the next kernel. */
 	ima_add_kexec_buffer(image);
 
+	ret = kstate_load_migrate_buf(image);
+	if (ret)
+		goto out;
+
 	/* Call image load handler */
 	ldata = kexec_image_load_default(image);
 
diff --git a/kernel/kstate.c b/kernel/kstate.c
index a73a9a42e55b..d35996287b76 100644
--- a/kernel/kstate.c
+++ b/kernel/kstate.c
@@ -2,6 +2,7 @@
 #include <linux/ctype.h>
 #include <linux/kexec.h>
 #include <linux/kstate.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
@@ -182,6 +183,31 @@ int kstate_save_state(void)
 	return 0;
 }
 
+int kstate_load_migrate_buf(struct kimage *image)
+{
+	int ret;
+	struct kexec_buf kbuf = { .image = image, .buf_min = 0,
+		.buf_max = ULONG_MAX, .top_down = true };
+
+	kbuf.bufsz = kstate_stream.size;
+	kbuf.buffer = kstate_stream.start;
+
+	kbuf.memsz = kstate_stream.size;
+
+	kbuf.buf_align = PAGE_SIZE;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		return ret;
+	image->kstate_stream_addr = kbuf.mem;
+	image->kstate_size = kstate_stream.size;
+
+	pr_info("kstate: Loaded mig_stream at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+	return ret;
+}
+
 void restore_kstate(struct kstate_stream *stream, int id,
 		const struct kstate_description *kstate, void *obj)
 {
@@ -258,6 +284,9 @@ static void restore_migrate_state(unsigned long kstate_data,
 	}
 }
 
+static unsigned long kstate_stream_addr = -1;
+static unsigned long kstate_size;
+
 static void __kstate_register(struct kstate_description *state, void *obj,
 			struct state_entry *se)
 {
@@ -265,7 +294,7 @@ static void __kstate_register(struct kstate_description *state, void *obj,
 	se->id = atomic_inc_return(&state->instance_id);
 	se->obj = obj;
 	list_add(&se->list, &states);
-	restore_migrate_state(0 /*migrate_stream_addr*/, se);
+	restore_migrate_state(kstate_stream_addr, se);
 }
 
 int kstate_register(struct kstate_description *state, void *obj)
@@ -280,3 +309,21 @@ int kstate_register(struct kstate_description *state, void *obj)
 	return 0;
 }
 
+static int __init setup_kstate(char *arg)
+{
+	char *end;
+
+	if (!arg)
+		return -EINVAL;
+	kstate_stream_addr = memparse(arg, &end);
+	if (*end == '@')
+		kstate_size = memparse(end + 1, &end);
+
+	return end > arg ? 0 : -EINVAL;
+}
+early_param("kstate_stream", setup_kstate);
+
+void __init kstate_init(void)
+{
+	memblock_reserve(kstate_stream_addr, kstate_size);
+}
-- 
2.45.3



  parent reply	other threads:[~2025-03-10 12:04 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-10 12:03 [PATCH v2 0/7] KSTATE: a mechanism to migrate some part of the kernel state " Andrey Ryabinin
2025-03-10 12:03 ` [PATCH v2 1/7] kstate: Add kstate - a mechanism to describe and migrate " Andrey Ryabinin
2025-03-10 12:03 ` Andrey Ryabinin [this message]
2025-03-10 12:03 ` [PATCH v2 3/7] kexec: exclude control pages from the destination addresses Andrey Ryabinin
2025-03-10 12:03 ` [PATCH v2 4/7] kexec, kstate: delay loading of kexec segments Andrey Ryabinin
2025-03-11 11:31   ` kernel test robot
2025-03-11 12:25   ` kernel test robot
2025-03-10 12:03 ` [PATCH v2 5/7] x86, kstate: Add the ability to preserve memory pages across kexec Andrey Ryabinin
2025-03-10 12:03 ` [PATCH v2 6/7] kexec, kstate: save kstate data before kexec'ing Andrey Ryabinin
2025-03-10 12:03 ` [PATCH v2 7/7] kstate, test: add test module for testing kstate subsystem Andrey Ryabinin
2025-03-11  2:27 ` [PATCH v2 0/7] KSTATE: a mechanism to migrate some part of the kernel state across kexec Cong Wang
2025-03-11 12:19   ` Andrey Ryabinin
2025-04-28 23:01     ` Chris Li
2025-04-28 23:01 ` Chris Li
2025-05-05 14:35   ` Andrey Ryabinin
2025-05-07  6:11     ` Chris Li

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250310120318.2124-3-arbn@yandex-team.com \
    --to=arbn@yandex-team.com \
    --cc=akpm@linux-foundation.org \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=ebiederm@xmission.com \
    --cc=graf@amazon.com \
    --cc=hpa@zytor.com \
    --cc=jgg@nvidia.com \
    --cc=jgowans@amazon.com \
    --cc=kexec@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mingo@redhat.com \
    --cc=pasha.tatashin@soleen.com \
    --cc=ptyadav@amazon.de \
    --cc=rientjes@google.com \
    --cc=rppt@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox