The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Sriram Nambakam <snambakam@linux.microsoft.com>
To: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: [RFC PATCH v1 11/42] Various changes to support VM Planes.
Date: Wed,  5 Aug 2026 04:02:53 -0700	[thread overview]
Message-ID: <20260805110324.25067-12-snambakam@linux.microsoft.com> (raw)
In-Reply-To: <20260805110324.25067-1-snambakam@linux.microsoft.com>

Remove custom parsing of initrd.

1. **vm_planes.c** — Core VM planes implementation (major rewrite)
   - Fixed config parser: `PLANE_COUNT=` line no longer causes fatal `-EINVAL` (returns `-ENOENT` to skip)
   - ELF loader: biases `p_paddr` by `load_offset` so kernel loads at correct GPA
   - Entry point: computes physical entry from ELF vaddr→paddr mapping, with fallback for physical `e_entry`
   - `activate_vm_planes()` now passes `plane_cfg` GPA so QEMU can read the updated `entry_point`

2. **vm_planes.h** — Added `entry_point` field declaration

3. **main.c** — Minor adjustment to `arch_init_vm_planes()` call site

4. **common.c** — KVM hypercall implementations
   - Removed hardcoded `0x1000`/`0x1001` hypercall numbers
   - `alloc_vm_planes()`: unchanged (uses correct HC numbers from UAPI header)
   - `activate_vm_planes()`: now passes `plane_cfg` GPA + `plane_count` (was just `plane_count`)

5. **cpu.h** — Updated `activate_vm_planes()` signature to include `plane_cfg`

6. **x86.c** — KVM host-side hypercall support
   - `KVM_EXIT_HYPERCALL_VALID_MASK`: added bits 13 and 14 for VM planes hypercalls
   - Added `KVM_HC_VM_PLANES_CONFIG` and `KVM_HC_VM_PLANES_ACTIVATE` case handlers that exit to userspace (QEMU)

7. **kvm_para.h** — Added hypercall numbers
   - `KVM_HC_VM_PLANES_CONFIG = 13`
   - `KVM_HC_VM_PLANES_ACTIVATE = 14`
---
 arch/x86/include/asm/cpu.h    |   3 +-
 arch/x86/kernel/cpu/common.c  |  19 +-
 arch/x86/kvm/x86.c            |  25 +-
 include/linux/vm_planes.h     |   1 +
 include/uapi/linux/kvm_para.h |   2 +
 init/main.c                   |   7 +-
 init/vm_planes.c              | 422 ++++++++++++++++++----------------
 7 files changed, 266 insertions(+), 213 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 52e80c6ac8f0..f9cb541e6367 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -15,7 +15,8 @@ struct vm_plane_config;
 
 int __init alloc_vm_planes(unsigned int plane_count,
 			    struct vm_plane_config *plane_cfg);
-int __init activate_vm_planes(unsigned int plane_count);
+int __init activate_vm_planes(unsigned int plane_count,
+			       struct vm_plane_config *plane_cfg);
 #endif
 
 #ifndef CONFIG_SMP
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 9912208d2010..7edc2c4072cc 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -80,13 +80,6 @@
 
 #include "cpu.h"
 
-#ifdef CONFIG_VM_PLANES
-/* Private hypercall number for early VM plane configuration. */
-#define KVM_HC_VM_PLANES_CONFIG		0x1000
-/* Private hypercall number to activate all configured planes. */
-#define KVM_HC_VM_PLANES_ACTIVATE	0x1001
-#endif
-
 DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
 EXPORT_PER_CPU_SYMBOL(cpu_info);
 
@@ -2708,11 +2701,13 @@ int __init alloc_vm_planes(unsigned int plane_count,
 	return 0;
 }
 
-int __init activate_vm_planes(unsigned int plane_count)
+int __init activate_vm_planes(unsigned int plane_count,
+			       struct vm_plane_config *plane_cfg)
 {
+	phys_addr_t phys;
 	long ret;
 
-	if (!plane_count)
+	if (!plane_count || !plane_cfg)
 		return -EINVAL;
 
 	if (!kvm_para_available()) {
@@ -2720,7 +2715,11 @@ int __init activate_vm_planes(unsigned int plane_count)
 		return -ENODEV;
 	}
 
-	ret = kvm_hypercall1(KVM_HC_VM_PLANES_ACTIVATE, plane_count);
+	phys = virt_to_phys((void *)plane_cfg);
+
+	ret = kvm_hypercall2(KVM_HC_VM_PLANES_ACTIVATE,
+			     (unsigned long)phys,
+			     plane_count);
 	if (ret < 0) {
 		pr_warn("vm_planes: activate hypercall failed: %ld\n", ret);
 		return (int)ret;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a0a8818b3096..b7256f155bea 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -119,7 +119,9 @@ u64 __read_mostly efer_reserved_bits = ~((u64)(EFER_SCE | EFER_LME | EFER_LMA));
 static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
 #endif
 
-#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE)
+#define KVM_EXIT_HYPERCALL_VALID_MASK (BIT(KVM_HC_MAP_GPA_RANGE) | \
+					 BIT(KVM_HC_VM_PLANES_CONFIG) | \
+					 BIT(KVM_HC_VM_PLANES_ACTIVATE))
 
 #define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE
 
@@ -10530,6 +10532,27 @@ int ____kvm_emulate_hypercall(struct kvm_vcpu *vcpu, int cpl,
 		vcpu->arch.complete_userspace_io = complete_hypercall;
 		return 0;
 	}
+	case KVM_HC_VM_PLANES_CONFIG:
+	case KVM_HC_VM_PLANES_ACTIVATE: {
+		ret = -KVM_ENOSYS;
+		if (!user_exit_on_hypercall(vcpu->kvm, nr))
+			break;
+
+		vcpu->run->exit_reason        = KVM_EXIT_HYPERCALL;
+		vcpu->run->hypercall.nr       = nr;
+		vcpu->run->hypercall.ret      = 0;
+		vcpu->run->hypercall.args[0]  = a0;
+		vcpu->run->hypercall.args[1]  = a1;
+		vcpu->run->hypercall.args[2]  = a2;
+		vcpu->run->hypercall.args[3]  = a3;
+		vcpu->run->hypercall.flags    = 0;
+		if (op_64_bit)
+			vcpu->run->hypercall.flags |= KVM_EXIT_HYPERCALL_LONG_MODE;
+
+		WARN_ON_ONCE(vcpu->run->hypercall.flags & KVM_EXIT_HYPERCALL_MBZ);
+		vcpu->arch.complete_userspace_io = complete_hypercall;
+		return 0;
+	}
 	default:
 		ret = -KVM_ENOSYS;
 		break;
diff --git a/include/linux/vm_planes.h b/include/linux/vm_planes.h
index bb06dcbcf0cb..47f05fa80039 100644
--- a/include/linux/vm_planes.h
+++ b/include/linux/vm_planes.h
@@ -19,6 +19,7 @@ enum vm_plane_kernel_format {
 struct vm_plane_config {
 	phys_addr_t load_offset;
 	phys_addr_t memory_size;
+	phys_addr_t entry_point;
 	unsigned int vcpu_count;
 	unsigned int kernel_format;
 	char kernel[VM_PLANE_KERNEL_NAME_MAX];
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
index 960c7e93d1a9..1b097f7ed937 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -30,6 +30,8 @@
 #define KVM_HC_SEND_IPI		10
 #define KVM_HC_SCHED_YIELD		11
 #define KVM_HC_MAP_GPA_RANGE		12
+#define KVM_HC_VM_PLANES_CONFIG		13
+#define KVM_HC_VM_PLANES_ACTIVATE	14
 
 /*
  * hypercalls use architecture specific
diff --git a/init/main.c b/init/main.c
index 3e35c2caca17..1c779f6d60cc 100644
--- a/init/main.c
+++ b/init/main.c
@@ -994,9 +994,6 @@ void start_kernel(void)
 	pr_notice("%s", linux_banner);
 	setup_arch(&command_line);
 	mm_core_init_early();
-#ifdef CONFIG_VM_PLANES
-	arch_init_vm_planes();
-#endif
 	/* Static keys and static calls are needed by LSMs */
 	jump_label_init();
 	static_call_init();
@@ -1666,6 +1663,10 @@ static noinline void __init kernel_init_freeable(void)
 	wait_for_initramfs();
 	console_on_rootfs();
 
+#ifdef CONFIG_VM_PLANES
+	arch_init_vm_planes();
+#endif
+
 	/*
 	 * check if there is an early userspace init.  If yes, let it do all
 	 * the work
diff --git a/init/vm_planes.c b/init/vm_planes.c
index 613daa161298..274c0015fe76 100644
--- a/init/vm_planes.c
+++ b/init/vm_planes.c
@@ -3,12 +3,15 @@
 #include <linux/init.h>
 #include <linux/initrd.h>
 #include <linux/kernel.h>
-#include <linux/memblock.h>
+#include <linux/slab.h>
 #include <linux/kstrtox.h>
 #include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/kvm_para.h>
 #include <linux/vm_planes.h>
 #include <linux/elf.h>
+#include <linux/mm.h>
 #include <asm/cpu.h>
 #include <asm/kvm_para.h>
 #include <asm-generic/early_ioremap.h>
@@ -30,46 +33,49 @@ struct vm_plane_parse_state {
 
 #define VM_PLANES_UNSET_VALUE	((phys_addr_t)~0)
 
-struct cpio_newc_header {
-	char c_magic[6];
-	char c_ino[8];
-	char c_mode[8];
-	char c_uid[8];
-	char c_gid[8];
-	char c_nlink[8];
-	char c_mtime[8];
-	char c_filesize[8];
-	char c_devmajor[8];
-	char c_devminor[8];
-	char c_rdevmajor[8];
-	char c_rdevminor[8];
-	char c_namesize[8];
-	char c_check[8];
-};
-
-static int __init parse_hex_field(const char *field, size_t len, u32 *value)
+/*
+ * Read a file from the rootfs into a newly allocated buffer.
+ * Caller must kfree(*out_data) when done.
+ */
+static int __init vm_planes_read_file(const char *path,
+				      void **out_data, loff_t *out_size)
 {
-	u32 v = 0;
-	size_t i;
-
-	for (i = 0; i < len; i++) {
-		u8 c = field[i];
-
-		v <<= 4;
-		if (c >= '0' && c <= '9')
-			v |= c - '0';
-		else if (c >= 'a' && c <= 'f')
-			v |= c - 'a' + 10;
-		else if (c >= 'A' && c <= 'F')
-			v |= c - 'A' + 10;
-		else
-			return -EINVAL;
+	struct file *fp;
+	loff_t fsize;
+	void *buf;
+	ssize_t rd;
+
+	fp = filp_open(path, O_RDONLY, 0);
+	if (IS_ERR(fp))
+		return PTR_ERR(fp);
+
+	fsize = i_size_read(file_inode(fp));
+	if (fsize <= 0) {
+		fput(fp);
+		return -ENODATA;
+	}
+
+	buf = kvmalloc(fsize, GFP_KERNEL);
+	if (!buf) {
+		fput(fp);
+		return -ENOMEM;
+	}
+
+	rd = kernel_read(fp, buf, fsize, &(loff_t){0});
+	fput(fp);
+
+	if (rd != fsize) {
+		kvfree(buf);
+		return (rd < 0) ? (int)rd : -EIO;
 	}
 
-	*value = v;
+	*out_data = buf;
+	*out_size = fsize;
 	return 0;
 }
 
+/* ---- Config file parser (unchanged) ---- */
+
 static int __init parse_plane_count_line(const char *line, size_t len,
 					 unsigned int *plane_count)
 {
@@ -174,7 +180,7 @@ static int __init parse_plane_cfg_line(const char *line, size_t len,
 
 	key = strchr(p, '_');
 	if (!key)
-		return -EINVAL;
+		return -ENOENT;
 	*key++ = '\0';
 
 	if (kstrtouint(p, 10, &plane_id) || plane_id >= plane_count)
@@ -297,16 +303,14 @@ static int __init parse_vm_planes_kconfig(const char *buf, size_t len,
 	if (*plane_count > UINT_MAX / sizeof(**plane_cfg))
 		return -E2BIG;
 
-	*plane_cfg = memblock_alloc(*plane_count * sizeof(**plane_cfg),
-				    SMP_CACHE_BYTES);
+	*plane_cfg = kzalloc(*plane_count * sizeof(**plane_cfg), GFP_KERNEL);
 	if (!*plane_cfg)
 		return -ENOMEM;
 
-	state = memblock_alloc(*plane_count * sizeof(*state), SMP_CACHE_BYTES);
+	state = kzalloc(*plane_count * sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return -ENOMEM;
 
-	memset(*plane_cfg, 0, *plane_count * sizeof(**plane_cfg));
 	for (i = 0; i < *plane_count; i++) {
 		state[i].load_offset = VM_PLANES_UNSET_VALUE;
 		state[i].memory_size = VM_PLANES_UNSET_VALUE;
@@ -329,9 +333,6 @@ static int __init parse_vm_planes_kconfig(const char *buf, size_t len,
 			p++;
 	}
 
-	/* Plane 0 is the already-running boot plane; only secondary planes
-	 * must provide full allocation metadata.
-	 */
 	for (i = 1; i < *plane_count; i++) {
 		if (state[i].load_offset == VM_PLANES_UNSET_VALUE ||
 		    state[i].memory_size == VM_PLANES_UNSET_VALUE ||
@@ -340,179 +341,192 @@ static int __init parse_vm_planes_kconfig(const char *buf, size_t len,
 			return -EINVAL;
 	}
 
+	kfree(state);
 	return 0;
 }
 
-static bool __init cpio_name_match(const char *name, size_t namesize,
-				   const char *target)
-{
-	while (namesize > 1 && (*name == '/' ||
-	       (namesize > 2 && name[0] == '.' && name[1] == '/'))) {
-		if (*name == '/') {
-			name++;
-			namesize--;
-		} else {
-			name += 2;
-			namesize -= 2;
-		}
-	}
+/* ---- Config loading via VFS ---- */
 
-	return !strncmp(name, target, namesize - 1) &&
-	       strlen(target) == namesize - 1;
-}
-
-static int __init vm_planes_get_cfg_from_initrd(unsigned int *plane_count,
-					struct vm_plane_config **plane_cfg)
+static int __init vm_planes_get_cfg(unsigned int *plane_count,
+				    struct vm_plane_config **plane_cfg)
 {
-	const u8 *p = (const u8 *)(unsigned long)initrd_start;
-	const u8 *end = (const u8 *)(unsigned long)initrd_end;
-
-	if (!initrd_start || !initrd_end || initrd_end <= initrd_start)
-		return -ENOENT;
-
-	while (p + sizeof(struct cpio_newc_header) <= end) {
-		const struct cpio_newc_header *hdr;
-		const char *name;
-		const u8 *data;
-		u32 namesize, filesize;
-		u32 name_align, data_align;
-		int ret;
-
-		hdr = (const struct cpio_newc_header *)p;
-		if (memcmp(hdr->c_magic, "070701", 6) &&
-		    memcmp(hdr->c_magic, "070702", 6))
-			return -EINVAL;
-
-		ret = parse_hex_field(hdr->c_namesize, sizeof(hdr->c_namesize), &namesize);
-		if (ret)
-			return ret;
-
-		ret = parse_hex_field(hdr->c_filesize, sizeof(hdr->c_filesize), &filesize);
-		if (ret)
-			return ret;
-
-		if (!namesize)
-			return -EINVAL;
+	void *buf;
+	loff_t size;
+	int ret;
 
-		p += sizeof(*hdr);
-		if (p + namesize > end)
-			return -EINVAL;
+	ret = vm_planes_read_file("/" VM_PLANES_CONFIG_FILE, &buf, &size);
+	if (ret) {
+		pr_err("vm_planes: cannot read /%s: %d\n",
+		       VM_PLANES_CONFIG_FILE, ret);
+		return ret;
+	}
 
-		name = (const char *)p;
-		name_align = ALIGN(namesize, 4);
-		if (p + name_align > end)
-			return -EINVAL;
+	ret = parse_vm_planes_kconfig(buf, (size_t)size, plane_count, plane_cfg);
+	kvfree(buf);
+	return ret;
+}
 
-		data = p + name_align;
-		if (data + filesize > end)
-			return -EINVAL;
+/* ---- Kernel loading ---- */
 
-		if (!strcmp(name, "TRAILER!!!"))
-			break;
+static int __init copy_to_early_mem(phys_addr_t dest, const void *src,
+				    unsigned long size)
+{
+	unsigned long slop, clen;
+	char *p;
 
-		if (cpio_name_match(name, namesize, VM_PLANES_CONFIG_FILE))
-			return parse_vm_planes_kconfig((const char *)data,
-						filesize,
-						plane_count,
-						plane_cfg);
+	while (size) {
+		slop = offset_in_page(dest);
+		clen = size;
+		if (clen > PAGE_SIZE - slop)
+			clen = PAGE_SIZE - slop;
+		p = early_memremap(dest & PAGE_MASK, clen + slop);
+		if (!p)
+			return -ENOMEM;
+		memcpy(p + slop, src, clen);
+		early_memunmap(p, clen + slop);
+		dest += clen;
+		src += clen;
+		size -= clen;
+	}
+	return 0;
+}
 
-		data_align = ALIGN(filesize, 4);
-		if (data + data_align < data || data + data_align > end)
-			return -EINVAL;
+static int __init zero_early_mem(phys_addr_t dest, unsigned long size)
+{
+	unsigned long slop, clen;
+	char *p;
 
-		p = data + data_align;
+	while (size) {
+		slop = offset_in_page(dest);
+		clen = size;
+		if (clen > PAGE_SIZE - slop)
+			clen = PAGE_SIZE - slop;
+		p = early_memremap(dest & PAGE_MASK, clen + slop);
+		if (!p)
+			return -ENOMEM;
+		memset(p + slop, 0, clen);
+		early_memunmap(p, clen + slop);
+		dest += clen;
+		size -= clen;
 	}
-
-	return -ENOENT;
+	return 0;
 }
 
-static int __init find_initrd_file(const char *filename,
-				   const u8 **out_data, u32 *out_size)
+static int __init load_plane_kernel_elf(const u8 *data, u32 size,
+					struct vm_plane_config *cfg)
 {
-	const u8 *p = (const u8 *)(unsigned long)initrd_start;
-	const u8 *end = (const u8 *)(unsigned long)initrd_end;
+	const Elf64_Ehdr *ehdr;
+	const Elf64_Phdr *phdr;
+	unsigned int i;
+	int ret;
 
-	if (!initrd_start || !initrd_end || initrd_end <= initrd_start)
-		return -ENOENT;
+	if (size < sizeof(*ehdr)) {
+		pr_err("vm_planes: ELF image too small (%u bytes)\n", size);
+		return -EINVAL;
+	}
 
-	while (p + sizeof(struct cpio_newc_header) <= end) {
-		const struct cpio_newc_header *hdr;
-		const char *name;
-		const u8 *data;
-		u32 namesize, filesize;
-		u32 name_align, data_align;
-		int ret;
+	ehdr = (const Elf64_Ehdr *)data;
 
-		hdr = (const struct cpio_newc_header *)p;
-		if (memcmp(hdr->c_magic, "070701", 6) &&
-		    memcmp(hdr->c_magic, "070702", 6))
-			return -EINVAL;
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		pr_err("vm_planes: not a valid ELF image\n");
+		return -EINVAL;
+	}
 
-		ret = parse_hex_field(hdr->c_namesize,
-				      sizeof(hdr->c_namesize), &namesize);
-		if (ret)
-			return ret;
+	if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
+	    ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
+	    ehdr->e_type != ET_EXEC ||
+	    ehdr->e_machine != EM_X86_64) {
+		pr_err("vm_planes: unsupported ELF format (need x86_64 ET_EXEC LE)\n");
+		return -EINVAL;
+	}
 
-		ret = parse_hex_field(hdr->c_filesize,
-				      sizeof(hdr->c_filesize), &filesize);
-		if (ret)
-			return ret;
+	if (!ehdr->e_phnum || ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
+		pr_err("vm_planes: invalid ELF program headers\n");
+		return -EINVAL;
+	}
 
-		if (!namesize)
-			return -EINVAL;
+	if (ehdr->e_phoff + (u64)ehdr->e_phnum * sizeof(Elf64_Phdr) > size) {
+		pr_err("vm_planes: ELF program headers extend beyond file\n");
+		return -EINVAL;
+	}
 
-		p += sizeof(*hdr);
-		if (p + namesize > end)
-			return -EINVAL;
+	phdr = (const Elf64_Phdr *)(data + ehdr->e_phoff);
 
-		name = (const char *)p;
-		name_align = ALIGN(namesize, 4);
-		if (p + name_align > end)
-			return -EINVAL;
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		phys_addr_t dest;
+		u64 bss_size;
 
-		data = p + name_align;
-		if (data + filesize > end)
-			return -EINVAL;
+		if (phdr->p_type != PT_LOAD)
+			continue;
 
-		if (!strcmp(name, "TRAILER!!!"))
-			break;
+		if (!phdr->p_memsz)
+			continue;
 
-		if (cpio_name_match(name, namesize, filename)) {
-			*out_data = data;
-			*out_size = filesize;
-			return 0;
+		/*
+		 * Bias the ELF physical address by load_offset so that the
+		 * kernel's link-time p_paddr values are treated as offsets
+		 * within the plane's memory region.
+		 */
+		dest = cfg->load_offset + phdr->p_paddr;
+
+		if (dest < cfg->load_offset ||
+		    dest + phdr->p_memsz > cfg->load_offset + cfg->memory_size) {
+			pr_err("vm_planes: ELF PT_LOAD at 0x%llx+0x%llx outside plane [0x%llx..0x%llx]\n",
+			       (unsigned long long)dest,
+			       (unsigned long long)phdr->p_memsz,
+			       (unsigned long long)cfg->load_offset,
+			       (unsigned long long)(cfg->load_offset + cfg->memory_size));
+			return -EINVAL;
 		}
 
-		data_align = ALIGN(filesize, 4);
-		if (data + data_align < data || data + data_align > end)
+		if (phdr->p_offset + phdr->p_filesz > size) {
+			pr_err("vm_planes: ELF PT_LOAD file data beyond image\n");
 			return -EINVAL;
+		}
 
-		p = data + data_align;
-	}
+		if (phdr->p_filesz) {
+			ret = copy_to_early_mem(dest, data + phdr->p_offset,
+						phdr->p_filesz);
+			if (ret)
+				return ret;
+		}
 
-	return -ENOENT;
-}
+		bss_size = phdr->p_memsz - phdr->p_filesz;
+		if (bss_size) {
+			ret = zero_early_mem(dest + phdr->p_filesz, bss_size);
+			if (ret)
+				return ret;
+		}
 
-static int __init copy_to_early_mem(phys_addr_t dest, const void *src,
-				    unsigned long size)
-{
-	unsigned long slop, clen;
-	char *p;
+		/*
+		 * Compute the physical entry point: if e_entry falls within
+		 * this segment's virtual range, convert vaddr→paddr and bias.
+		 * Also handle kernels where e_entry is already a physical
+		 * address by checking the p_paddr range as a fallback.
+		 */
+		if (ehdr->e_entry >= phdr->p_vaddr &&
+		    ehdr->e_entry < phdr->p_vaddr + phdr->p_memsz)
+			cfg->entry_point = cfg->load_offset +
+				phdr->p_paddr + (ehdr->e_entry - phdr->p_vaddr);
+		else if (ehdr->e_entry >= phdr->p_paddr &&
+			 ehdr->e_entry < phdr->p_paddr + phdr->p_memsz)
+			cfg->entry_point = cfg->load_offset + ehdr->e_entry;
+
+		pr_info("vm_planes: ELF PT_LOAD: paddr=0x%llx filesz=0x%llx memsz=0x%llx\n",
+			(unsigned long long)dest,
+			(unsigned long long)phdr->p_filesz,
+			(unsigned long long)phdr->p_memsz);
+	}
 
-	while (size) {
-		slop = offset_in_page(dest);
-		clen = size;
-		if (clen > PAGE_SIZE - slop)
-			clen = PAGE_SIZE - slop;
-		p = early_memremap(dest & PAGE_MASK, clen + slop);
-		if (!p)
-			return -ENOMEM;
-		memcpy(p + slop, src, clen);
-		early_memunmap(p, clen + slop);
-		dest += clen;
-		src += clen;
-		size -= clen;
+	if (!cfg->entry_point) {
+		pr_err("vm_planes: ELF entry point 0x%llx not in any PT_LOAD segment\n",
+		       (unsigned long long)ehdr->e_entry);
+		return -EINVAL;
 	}
+	pr_info("vm_planes: ELF entry point: 0x%llx (virt 0x%llx)\n",
+		(unsigned long long)cfg->entry_point,
+		(unsigned long long)ehdr->e_entry);
+
 	return 0;
 }
 
@@ -525,6 +539,7 @@ static int __init load_plane_kernel_raw(const u8 *data, u32 size,
 		return -ENOMEM;
 	}
 
+	cfg->entry_point = cfg->load_offset;
 	return copy_to_early_mem(cfg->load_offset, data, size);
 }
 
@@ -535,50 +550,59 @@ int __init load_vm_plane_kernels(unsigned int plane_count,
 	int err = 0;
 
 	for (i = 1; i < plane_count; i++) {
-		const u8 *data;
-		u32 size;
+		void *data;
+		loff_t fsize;
 		int ret;
 
-		ret = find_initrd_file(plane_cfg[i].kernel, &data, &size);
+		ret = vm_planes_read_file(plane_cfg[i].kernel, &data, &fsize);
 		if (ret) {
-			pr_err("vm_planes: plane %u: kernel image '%s' not found in initrd\n",
-			       i, plane_cfg[i].kernel);
+			pr_err("vm_planes: plane %u: kernel '%s' not found: %d\n",
+			       i, plane_cfg[i].kernel, ret);
 			err = ret;
 			continue;
 		}
 
 		switch (plane_cfg[i].kernel_format) {
 		case VM_PLANE_KFMT_RAW:
-			ret = load_plane_kernel_raw(data, size,
+			ret = load_plane_kernel_raw(data, (u32)fsize,
 						    &plane_cfg[i]);
 			break;
-		case VM_PLANE_KFMT_BZIMAGE:
 		case VM_PLANE_KFMT_ELF:
-			pr_err("vm_planes: plane %u: kernel format not yet supported\n",
+			ret = load_plane_kernel_elf(data, (u32)fsize,
+						    &plane_cfg[i]);
+			break;
+		case VM_PLANE_KFMT_BZIMAGE:
+			pr_err("vm_planes: plane %u: bzImage format not yet supported\n",
 			       i);
 			err = -ENOSYS;
+			kvfree(data);
 			continue;
 		default:
 			pr_err("vm_planes: plane %u: unknown kernel format %u\n",
 			       i, plane_cfg[i].kernel_format);
 			err = -EINVAL;
+			kvfree(data);
 			continue;
 		}
 
 		if (ret) {
-			pr_err("vm_planes: plane %u: failed to load kernel image: %d\n",
+			pr_err("vm_planes: plane %u: failed to load kernel: %d\n",
 			       i, ret);
 			err = ret;
 		} else {
-			pr_info("vm_planes: plane %u: loaded '%s' (%u bytes) at 0x%llx\n",
-				i, plane_cfg[i].kernel,
-				size, (unsigned long long)plane_cfg[i].load_offset);
+			pr_info("vm_planes: plane %u: loaded '%s' (%lld bytes) at 0x%llx\n",
+				i, plane_cfg[i].kernel, fsize,
+				(unsigned long long)plane_cfg[i].load_offset);
 		}
+
+		kvfree(data);
 	}
 
 	return err;
 }
 
+/* ---- Early param & activation ---- */
+
 static int __init parse_enable_vm_planes(char *str)
 {
 	bool enable;
@@ -600,7 +624,8 @@ early_param("enable-vm-planes", parse_enable_vm_planes);
 int __init __weak alloc_vm_planes(unsigned int plane_count,
 				   struct vm_plane_config *plane_cfg) { return -ENOSYS; }
 
-int __init __weak activate_vm_planes(unsigned int plane_count) { return -ENOSYS; }
+int __init __weak activate_vm_planes(unsigned int plane_count,
+				      struct vm_plane_config *plane_cfg) { return -ENOSYS; }
 
 void __init arch_init_vm_planes(void)
 {
@@ -614,9 +639,10 @@ void __init arch_init_vm_planes(void)
 	if (!kvm_para_available())
 		return;
 
-	if (vm_planes_get_cfg_from_initrd(&plane_count, &plane_cfg)) {
-		pr_warn("vm_planes: failed to parse %s from initrd\n",
-			VM_PLANES_CONFIG_FILE);
+	ret = vm_planes_get_cfg(&plane_count, &plane_cfg);
+	if (ret) {
+		pr_warn("vm_planes: failed to parse %s: %d\n",
+			VM_PLANES_CONFIG_FILE, ret);
 		return;
 	}
 
@@ -635,7 +661,7 @@ void __init arch_init_vm_planes(void)
 		return;
 	}
 
-	ret = activate_vm_planes(plane_count);
+	ret = activate_vm_planes(plane_count, plane_cfg);
 	if (ret)
 		pr_err("vm_planes: failed to activate planes: %d\n", ret);
 }
-- 
2.55.0


  parent reply	other threads:[~2026-08-05 11:03 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05 11:02 [RFC PATCH v1 00/42] VBS/VSM-on-KVM: VBS integration for KVM VM planes Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 01/42] Fix merge issue - Remove duplicate definition for kvm_arch_has_irq_bypass Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 02/42] Fix compilation Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 03/42] Fix compile error Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 04/42] Fix compile errors Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 05/42] Initial support for VM Planes - Add kernel config for CONFIG_VM_PLANES - Parse vm plane config from initrd for plane configuration - Make hypercalls to allocate memory for the vm planes Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 06/42] Use vcpu count from the plane configuration Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 07/42] skip processing plane configuration for plane 0 - plane 0 is the boot plane Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 08/42] Add plane config param to specify kernel image format Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 09/42] Activate the VM Planes through the Hypervisor - Using KVM as the VMM Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 10/42] allow the command line to be specified for kernels in other planes Sriram Nambakam
2026-08-05 11:02 ` Sriram Nambakam [this message]
2026-08-05 11:02 ` [RFC PATCH v1 12/42] Add a Virtualization Based Security (VBS) framework. - Add backends for AMD SEV-SNP, Intel TDX, Arm CCA and KVM Planes. - Support VTL on Hyper-V in addition to Planes on KVM Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 13/42] Add a inter-plane communication mechanism through KVM. - model this to use a single page similar to SEV-SNP Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 14/42] KVM: Add per-plane memory attribute support for cross-plane EPT protection Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 15/42] KVM: x86: Add KVM_HC_VBS_VTL_CALL hypercall for VBS inter-plane calls Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 16/42] vbs: Add HEKI kernel sealing and fix KVM plane memory attribute guards Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 17/42] vbs: Add module authentication via VBS/HEKI Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 18/42] vbs: Add kexec validation and make module auth non-fatal Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 19/42] Merge branch 'master' into vm-planes Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 20/42] kvm: x86: fix merged plane API/stat build regressions Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 21/42] KVM: x86: exit VM planes and VBS hypercalls to userspace Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 22/42] kexec: block legacy kexec_load when VBS is active Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 23/42] kvm: x86: fix merged plane API/stat build regressions Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 24/42] KVM: planes: expose memory-attribute setting to in-kernel callers Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 25/42] vm_planes: drop unused per-plane vcpu_count Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 26/42] drivers/virt: add VBS secure-plane park loop Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 27/42] KVM: planes: add arch-neutral in-kernel plane switch helper Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 28/42] KVM: x86: add VBS VTL call/return and cross-plane set-mem-attrs hypercalls Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 29/42] init/vm_planes: set up planes from rootfs_initcall and load ELF payloads Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 30/42] security/vbs: run backend probe and HEKI seal at rootfs_initcall Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 31/42] security/vbs: pin the VTL call hypercall to CPU0 Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 32/42] security/vbs: add secure-plane monitor backend Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 33/42] drivers/virt: rename VBS park loop to secure_monitor Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 34/42] x86/realmode: skip the sub-1M trampoline for the VBS secure plane Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 35/42] KVM: x86: deny normal-plane access to secure-plane memory Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 36/42] KVM: plane: handle KVM_CHECK_EXTENSION on the plane fd Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 37/42] KVM: selftests: run plane tests with a split IRQ chip Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 38/42] kvm: x86: drop obsolete kvm_cache_regs.h Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 39/42] kvm: arch: finalize plane hooks and kvm_arch_vcpu_create signature Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 40/42] kvm: x86: use kvm_vcpu scheduling-state accessors and struct stat fields Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 41/42] kvm: x86: finalize per-plane APIC state and CPUID placement Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 42/42] kvm: planes: reconcile core plane state, UAPI and hypercall exit Sriram Nambakam

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=20260805110324.25067-12-snambakam@linux.microsoft.com \
    --to=snambakam@linux.microsoft.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.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