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
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.