From nobody Wed Aug 26 12:56:54 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785927932; cv=none; d=zohomail.com; s=zohoarc; b=VOWIaFRB3pYsK0wZUCbkMmPZgGj6t9t8KZskLwss45mOKVcYN7iVMUxuAvgfWKtY4a3ypZoOvnIfRYItzZ70mA7egLfWCNMGnybwH1fkeUBtmw5qyALWA/grihI+Ydh1+oS/SklotueRFkg8cDw8iU6An9E1iroxZkRTPTBvlfY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785927932; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=cKpLSPc5Ft5FlEL2TPYsuyNO1mO7zlGBjKjNjZCumb0=; b=YoV7ABm2Y5Zl9B5O3k2/I9MnB42LPXDwX8UAPrt0NpLVgVPvYSjFSlIVUL7jAgC1osxa8v/H7Bwgs03yW86Osy3QyBQ6xlhtZBobdf6JyDdBW/ODyIC24PYtNWUI3GKca9rcGKa6+e3sqriB8lIyb+3rHUEAm1gIMUW9GYuOTgs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785927932691299.201444274354; Wed, 5 Aug 2026 04:05:32 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQR-0000mJ-7i; Wed, 05 Aug 2026 07:04:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wrZQP-0000kO-E6 for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:41 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQL-0000BO-5y for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:41 -0400 Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id 8681D20B716A; Wed, 5 Aug 2026 04:04:13 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8681D20B716A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927853; bh=cKpLSPc5Ft5FlEL2TPYsuyNO1mO7zlGBjKjNjZCumb0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jeJe8BEZS6SaED7DkDupduivx9FuLihWlULQySkpXZdklJW1abcHTC3S57j4UNwDV X8nGxMlcTK+8ySS9WnKbVSuZ5Xj8LVBfBlRhjoQgnu4IGJ2wYl9U+rViLbgRuyUhEf HXZEnN/Q0znekiHMYYzYeBASwBuyJ6l9Y/xT+M/Q= From: Sriram Nambakam To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org Subject: [RFC PATCH v1 1/5] kvm: add userspace handlers for VM planes and VBS VTL calls Date: Wed, 5 Aug 2026 04:04:28 -0700 Message-ID: <20260805110432.25167-2-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110432.25167-1-snambakam@linux.microsoft.com> References: <20260805110432.25167-1-snambakam@linux.microsoft.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=snambakam@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785927934179158500 (cherry picked from commit 47d0da9ac50640f96564997edc4b79f44e70cffa) --- accel/kvm/kvm-all.c | 18 + include/standard-headers/linux/kvm_para.h | 3 + include/system/kvm_int.h | 17 + linux-headers/linux/kvm.h | 3 + target/i386/kvm/kvm.c | 776 ++++++++++++++++++++++ 5 files changed, 817 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 46a14ac0f4..80a9791078 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -822,6 +822,24 @@ void kvm_close(void) close(kvm_get_plane_fd(kvm_state, plane_id)); kvm_set_plane_fd(kvm_state, plane_id, -1); } while (plane_id !=3D 0); + if (kvm_state->vm_planes) { + unsigned int i, j; + for (i =3D 1; i < kvm_state->vm_plane_count; i++) { + struct kvm_vm_plane_state *ps =3D &kvm_state->vm_planes[i]; + if (ps->vcpu_fds) { + for (j =3D 0; j < ps->vcpu_count; j++) { + if (ps->vcpu_fds[j] >=3D 0) { + close(ps->vcpu_fds[j]); + } + } + g_free(ps->vcpu_fds); + ps->vcpu_fds =3D NULL; + } + } + g_free(kvm_state->vm_planes); + kvm_state->vm_planes =3D NULL; + kvm_state->vm_plane_count =3D 0; + } close(kvm_state->fd); kvm_state->fd =3D -1; } diff --git a/include/standard-headers/linux/kvm_para.h b/include/standard-h= eaders/linux/kvm_para.h index 015c166302..ad19aac9d0 100644 --- a/include/standard-headers/linux/kvm_para.h +++ b/include/standard-headers/linux/kvm_para.h @@ -30,6 +30,9 @@ #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 +#define KVM_HC_VBS_VTL_CALL 15 =20 /* * hypercalls use architecture specific diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h index 70b381f1ba..e7c9dc95a2 100644 --- a/include/system/kvm_int.h +++ b/include/system/kvm_int.h @@ -109,6 +109,19 @@ struct KVMPlane { bool vcpu_dirty; }; =20 +/* Per-plane VM state managed by LVBS hypercall handlers. + * The plane fd itself is owned by the accel layer and accessed via + * kvm_get_plane_fd(s, plane_id); only LVBS-specific state lives here. */ +struct kvm_vm_plane_state { + int *vcpu_fds; + unsigned int vcpu_count; + uint64_t load_offset; + uint64_t memory_size; + uint64_t entry_point; + void *host_addr; /* host pointer to plane RAM (cleared after la= unch) */ + char cmdline[512]; +}; + struct KVMState { AccelState parent_obj; @@ -176,6 +189,10 @@ struct KVMState uint16_t xen_evtchn_max_pirq; char *device; OnOffAuto honor_guest_pat; + /* VM planes state (populated by LVBS hypercall handlers) */ + struct kvm_vm_plane_state *vm_planes; + unsigned int vm_plane_count; + unsigned int vm_planes_max; }; =20 static inline void kvm_set_plane_fd(KVMState *s, unsigned plane, int fd) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 8caa3eccce..d66ce6d272 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1654,6 +1654,9 @@ struct kvm_memory_attributes { =20 #define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3) =20 +#define KVM_MEMORY_ATTRIBUTE_NO_WRITE (1ULL << 4) +#define KVM_MEMORY_ATTRIBUTE_NO_EXEC (1ULL << 5) + #define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest= _memfd) #define GUEST_MEMFD_FLAG_MMAP (1ULL << 0) #define GUEST_MEMFD_FLAG_INIT_SHARED (1ULL << 1) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 13cfa60071..9d89e5cac6 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -71,6 +71,13 @@ #include "exec/memattrs.h" #include "exec/target_page.h" #include "trace.h" +#include "system/address-spaces.h" +#include "system/memory.h" +#include "qemu/thread.h" +#include "qemu/timer.h" +#include +#include +#include =20 #include CONFIG_DEVICES =20 @@ -3588,6 +3595,13 @@ int kvm_arch_init(MachineState *ms, KVMState *s) kvm_vmfd_add_change_notifier(&kvm_vmfd_change_notifier); } =20 + /* Enable userspace exit for VM planes and VBS hypercalls (LVBS). */ + if (!kvm_enable_hypercall(BIT_ULL(KVM_HC_VM_PLANES_CONFIG) | + BIT_ULL(KVM_HC_VM_PLANES_ACTIVATE) | + BIT_ULL(KVM_HC_VBS_VTL_CALL))) { + warn_report("kvm: failed to enable VM planes / VBS hypercall exit"= ); + } + /* * Most x86 CPUs in current use have self-snoop, so honoring guest PAT= is * preferable. As well, the bochs video driver bug which motivated ma= king @@ -6519,10 +6533,772 @@ static int kvm_handle_hc_map_gpa_range(X86CPU *cpu= , struct kvm_run *run) return 0; } =20 +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * LVBS =E2=80=94 VM planes + VBS VTL hypercall handlers + * + * Guest-side struct vm_plane_config layout (672 bytes, see Linux + * include/linux/vm_planes.h): + * off 0 u64 load_offset + * off 8 u64 memory_size + * off 16 u64 entry_point + * off 24 u32 vcpu_count + * off 28 u32 kernel_format + * off 32 char kernel[128] + * off 160 char cmdline[512] + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ + +#define VM_PLANE_CFG_STRIDE 672 + +#define VBS_CALL_INIT 0x0001 +#define VBS_CALL_SHUTDOWN 0x0002 +#define VBS_CALL_PROTECT_MEMORY 0x0100 +#define VBS_CALL_SEAL_KERNEL 0x0101 +#define VBS_CALL_VALIDATE_MODULE 0x0200 +#define VBS_CALL_SET_MODULE_PERMS 0x0201 +#define VBS_CALL_UNLOAD_MODULE 0x0202 +#define VBS_CALL_ADD_KEY 0x0300 +#define VBS_CALL_REVOKE_KEY 0x0301 +#define VBS_CALL_SEND_CERTS 0x0302 +#define VBS_CALL_KEXEC_VALIDATE 0x0400 +#define VBS_CALL_KEXEC_INVALIDATE 0x0401 + +#define CA_OFF_CALL_ID 4 +#define CA_OFF_STATUS 8 +#define CA_OFF_ARG_SIZE 12 +#define CA_OFF_RESP_SIZE 16 +#define CA_OFF_BUFFER 20 + +struct vm_plane_boot_ctx { + int vcpu_fd; + int vcpu_mmap_size; + unsigned int vcpu_idx; + uint64_t plane_id; + unsigned int *halted_count; + QemuMutex *mutex; + QemuCond *cond; + int result; + int log_fd; + QemuMutex wake_mutex; + QemuCond wake_cond; + bool halted; + bool kick; + bool stopped; +}; + +static int kvm_handle_hc_vm_planes_config(X86CPU *cpu, struct kvm_run *run) +{ + uint64_t gpa =3D run->hypercall.args[0]; + uint64_t plane_count =3D run->hypercall.args[1]; + uint64_t plane_id; + unsigned int plane0_vcpu_count; + unsigned int *plane0_vcpu_ids; + CPUState *cs; + KVMState *s =3D kvm_state; + + if (!gpa || !plane_count) { + run->hypercall.ret =3D -EINVAL; + return 0; + } + + if (!s->vm_planes_max) { + int max =3D kvm_vm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_PLANES); + if (max <=3D 0) { + error_report("vm_planes: KVM does not support planes"); + run->hypercall.ret =3D -ENOTSUP; + return 0; + } + s->vm_planes_max =3D max; + } + + if (plane_count > s->vm_planes_max) { + error_report("vm_planes: requested %" PRIu64 " planes but KVM " + "supports %u", plane_count, s->vm_planes_max); + run->hypercall.ret =3D -EINVAL; + return 0; + } + + if (s->vm_planes) { + info_report("vm_planes: already configured, ignoring"); + run->hypercall.ret =3D 0; + return 0; + } + + s->vm_planes =3D g_new0(struct kvm_vm_plane_state, plane_count); + s->vm_plane_count =3D plane_count; + + plane0_vcpu_count =3D 0; + CPU_FOREACH(cs) { + plane0_vcpu_count++; + } + if (!plane0_vcpu_count) { + error_report("vm_planes: no plane0 vCPUs available"); + run->hypercall.ret =3D -EINVAL; + return 0; + } + + plane0_vcpu_ids =3D g_new(unsigned int, plane0_vcpu_count); + plane0_vcpu_count =3D 0; + CPU_FOREACH(cs) { + plane0_vcpu_ids[plane0_vcpu_count++] =3D cs->cpu_index; + } + + for (plane_id =3D 1; plane_id < plane_count; plane_id++) { + uint64_t plane_gpa =3D gpa + (plane_id * VM_PLANE_CFG_STRIDE); + uint64_t load_offset =3D 0, memory_size =3D 0, entry_point =3D 0; + uint32_t vcpu_count =3D 0; + struct kvm_vm_plane_state *ps =3D &s->vm_planes[plane_id]; + char cmdline_buf[512]; + MemoryRegionSection section; + int plane_fd; + unsigned int i; + + cpu_physical_memory_read(plane_gpa + 0, &load_offset, 8); + cpu_physical_memory_read(plane_gpa + 8, &memory_size, 8); + cpu_physical_memory_read(plane_gpa + 16, &entry_point, 8); + cpu_physical_memory_read(plane_gpa + 24, &vcpu_count, 4); + + if (!memory_size || !vcpu_count) { + error_report("vm_planes: plane %" PRIu64 " invalid " + "(load_offset=3D0x%" PRIx64 " size=3D0x%" PRIx64 + " vcpus=3D%u)", + plane_id, load_offset, memory_size, vcpu_count); + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D -EINVAL; + return 0; + } + + if (vcpu_count > plane0_vcpu_count) { + error_report("vm_planes: plane %" PRIu64 " requests %u vCPUs, " + "but plane0 has %u", plane_id, vcpu_count, + plane0_vcpu_count); + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D -EINVAL; + return 0; + } + + memset(cmdline_buf, 0, sizeof(cmdline_buf)); + cpu_physical_memory_read(plane_gpa + 160, cmdline_buf, + sizeof(cmdline_buf)); + cmdline_buf[sizeof(cmdline_buf) - 1] =3D '\0'; + memcpy(ps->cmdline, cmdline_buf, sizeof(ps->cmdline)); + + plane_fd =3D kvm_vm_ioctl(s, KVM_CREATE_PLANE, (int)plane_id); + if (plane_fd < 0) { + error_report("vm_planes: KVM_CREATE_PLANE plane %" PRIu64 + " failed: %s", plane_id, strerror(errno)); + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D -errno; + return 0; + } + /* The kvm_vm_plane_ioctl path looks up the plane fd via + * kvm_get_plane_fd / kvm_set_plane_fd, so register the fd. */ + kvm_set_plane_fd(s, plane_id, plane_fd); + + section =3D memory_region_find(get_system_memory(), + load_offset, memory_size); + if (!section.mr || !memory_region_is_ram(section.mr)) { + error_report("vm_planes: plane %" PRIu64 " GPA 0x%" PRIx64 + " size 0x%" PRIx64 " is not RAM", + plane_id, load_offset, memory_size); + if (section.mr) { + memory_region_unref(section.mr); + } + close(plane_fd); + kvm_set_plane_fd(s, plane_id, -1); + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D -ENOMEM; + return 0; + } + ps->host_addr =3D memory_region_get_ram_ptr(section.mr) + + section.offset_within_region; + memory_region_unref(section.mr); + + ps->vcpu_fds =3D g_new0(int, vcpu_count); + for (i =3D 0; i < vcpu_count; i++) { + int vcpu_fd; + unsigned int vcpu_id =3D plane0_vcpu_ids[i]; + + vcpu_fd =3D kvm_vm_plane_ioctl(s, plane_id, KVM_CREATE_VCPU, + (void *)(uintptr_t)vcpu_id); + if (vcpu_fd < 0) { + error_report("vm_planes: KVM_CREATE_VCPU plane %" PRIu64 + " vcpu %u failed: %s", + plane_id, vcpu_id, strerror(errno)); + close(plane_fd); + kvm_set_plane_fd(s, plane_id, -1); + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D -errno; + return 0; + } + + ps->vcpu_fds[i] =3D vcpu_fd; + } + + ps->vcpu_count =3D vcpu_count; + ps->load_offset =3D load_offset; + ps->memory_size =3D memory_size; + ps->entry_point =3D entry_point; + + info_report("vm_planes: plane %" PRIu64 " ready =E2=80=94 GPA 0x%"= PRIx64 + " size 0x%" PRIx64 " entry 0x%" PRIx64 " vcpus %u", + plane_id, load_offset, memory_size, entry_point, + vcpu_count); + } + + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D 0; + return 0; +} + +static int kvm_init_plane_vcpu(int vcpu_fd, uint64_t entry_addr, + uint64_t stack_addr, uint64_t zero_page_gpa, + uint64_t page_table_gpa, uint64_t gdt_gpa, + bool is_bsp) +{ + struct kvm_regs regs =3D {}; + struct kvm_sregs sregs =3D {}; + struct kvm_mp_state mp =3D { + .mp_state =3D is_bsp ? KVM_MP_STATE_RUNNABLE + : KVM_MP_STATE_INIT_RECEIVED, + }; + int ret; + + sregs.cs.base =3D 0; sregs.cs.limit =3D 0xffffffff; sregs.cs.selector = =3D 0x10; + sregs.cs.type =3D 0xb; sregs.cs.present =3D 1; sregs.cs.dpl =3D 0; + sregs.cs.db =3D 0; sregs.cs.s =3D 1; sregs.cs.l =3D 1; sregs.cs.g =3D = 1; + + sregs.ds.base =3D 0; sregs.ds.limit =3D 0xffffffff; sregs.ds.selector = =3D 0x18; + sregs.ds.type =3D 0x3; sregs.ds.present =3D 1; sregs.ds.dpl =3D 0; + sregs.ds.db =3D 1; sregs.ds.s =3D 1; sregs.ds.g =3D 1; + sregs.es =3D sregs.ds; + sregs.ss =3D sregs.ds; + sregs.fs =3D sregs.ds; sregs.fs.selector =3D 0; + sregs.gs =3D sregs.fs; + + sregs.gdt.base =3D gdt_gpa; sregs.gdt.limit =3D 0x2f; + sregs.idt.base =3D 0; sregs.idt.limit =3D 0xffff; + sregs.tr.base =3D 0; sregs.tr.limit =3D 0x67; sregs.tr.selector =3D 0x= 28; + sregs.tr.type =3D 0xb; sregs.tr.present =3D 1; sregs.tr.dpl =3D 0; sre= gs.tr.s =3D 0; + sregs.ldt.unusable =3D 1; + + sregs.cr3 =3D page_table_gpa; + sregs.cr4 =3D (1u << 5); /* PAE */ + sregs.cr0 =3D (1u << 0) | (1u << 4) | (1u << 5) | (1u << 16) | (1u << = 31); + sregs.efer =3D (1u << 0) | (1u << 8) | (1u << 10) | (1u << 11); + sregs.apic_base =3D 0xfee00000 | (1u << 11); + if (is_bsp) { + sregs.apic_base |=3D (1u << 8); + } + + ret =3D ioctl(vcpu_fd, KVM_SET_SREGS, &sregs); + if (ret < 0) { + error_report("vm_planes: KVM_SET_SREGS: %s", strerror(errno)); + return -errno; + } + + regs.rip =3D entry_addr; + regs.rsp =3D stack_addr; + regs.rsi =3D zero_page_gpa; + regs.rflags =3D 0x2; + ret =3D ioctl(vcpu_fd, KVM_SET_REGS, ®s); + if (ret < 0) { + error_report("vm_planes: KVM_SET_REGS: %s", strerror(errno)); + return -errno; + } + + ret =3D ioctl(vcpu_fd, KVM_SET_MP_STATE, &mp); + if (ret < 0) { + error_report("vm_planes: KVM_SET_MP_STATE: %s", strerror(errno)); + return -errno; + } + return 0; +} + +static void *vm_plane_vcpu_thread(void *arg) +{ + struct vm_plane_boot_ctx *ctx =3D arg; + struct kvm_run *kvm_run; + int ret; + bool boot_signaled =3D false; + + kvm_run =3D mmap(NULL, ctx->vcpu_mmap_size, PROT_READ | PROT_WRITE, + MAP_SHARED, ctx->vcpu_fd, 0); + if (kvm_run =3D=3D MAP_FAILED) { + error_report("vm_planes: plane %" PRIu64 " vcpu %u: mmap failed: %= s", + ctx->plane_id, ctx->vcpu_idx, strerror(errno)); + ctx->result =3D -errno; + qemu_mutex_lock(ctx->mutex); + (*ctx->halted_count)++; + qemu_cond_signal(ctx->cond); + qemu_mutex_unlock(ctx->mutex); + return NULL; + } + + for (;;) { + ret =3D ioctl(ctx->vcpu_fd, KVM_RUN, 0); + if (ret < 0) { + if (errno =3D=3D EINTR || errno =3D=3D EAGAIN) { + continue; + } + error_report("vm_planes: plane %" PRIu64 " vcpu %u: KVM_RUN: %= s", + ctx->plane_id, ctx->vcpu_idx, strerror(errno)); + ctx->result =3D -errno; + break; + } + + switch (kvm_run->exit_reason) { + case KVM_EXIT_HLT: + if (!boot_signaled) { + boot_signaled =3D true; + qemu_mutex_lock(ctx->mutex); + (*ctx->halted_count)++; + qemu_cond_signal(ctx->cond); + qemu_mutex_unlock(ctx->mutex); + } + qemu_mutex_lock(&ctx->wake_mutex); + ctx->halted =3D true; + while (!ctx->kick && !ctx->stopped) { + qemu_cond_wait(&ctx->wake_cond, &ctx->wake_mutex); + } + ctx->halted =3D false; + ctx->kick =3D false; + if (ctx->stopped) { + qemu_mutex_unlock(&ctx->wake_mutex); + goto done; + } + qemu_mutex_unlock(&ctx->wake_mutex); + break; + + case KVM_EXIT_IO: { + uint8_t *io_data =3D (uint8_t *)kvm_run + kvm_run->io.data_off= set; + size_t io_size =3D kvm_run->io.size * kvm_run->io.count; + uint16_t port =3D kvm_run->io.port; + + if (kvm_run->io.direction =3D=3D KVM_EXIT_IO_OUT) { + if (port =3D=3D 0x3f8 && ctx->log_fd >=3D 0) { + ssize_t w =3D write(ctx->log_fd, io_data, io_size); + (void)w; + } + } else { + memset(io_data, 0, io_size); + switch (port) { + case 0x3fa: memset(io_data, 0xc1, io_size); break; + case 0x3fb: memset(io_data, 0x03, io_size); break; + case 0x3fc: memset(io_data, 0x08, io_size); break; + case 0x3fd: memset(io_data, 0x60, io_size); break; + case 0x3fe: memset(io_data, 0xb0, io_size); break; + default: break; + } + } + usleep(100); + break; + } + + case KVM_EXIT_MMIO: + usleep(100); + break; + + case KVM_EXIT_SHUTDOWN: { + struct kvm_regs dbg =3D {}; + ioctl(ctx->vcpu_fd, KVM_GET_REGS, &dbg); + error_report("vm_planes: plane %" PRIu64 " vcpu %u: shutdown " + "RIP=3D0x%" PRIx64 " RSP=3D0x%" PRIx64, + ctx->plane_id, ctx->vcpu_idx, + (uint64_t)dbg.rip, (uint64_t)dbg.rsp); + ctx->result =3D -EFAULT; + goto done; + } + + case KVM_EXIT_FAIL_ENTRY: + error_report("vm_planes: plane %" PRIu64 " vcpu %u: entry fail= ure " + "0x%" PRIx64, ctx->plane_id, ctx->vcpu_idx, + (uint64_t)kvm_run->fail_entry.hardware_entry_fail= ure_reason); + ctx->result =3D -EFAULT; + goto done; + + case KVM_EXIT_INTERNAL_ERROR: + error_report("vm_planes: plane %" PRIu64 " vcpu %u: internal " + "error %u", ctx->plane_id, ctx->vcpu_idx, + kvm_run->internal.suberror); + ctx->result =3D -EFAULT; + goto done; + + default: + error_report("vm_planes: plane %" PRIu64 " vcpu %u: unexpected= " + "exit %u", ctx->plane_id, ctx->vcpu_idx, + kvm_run->exit_reason); + ctx->result =3D -EFAULT; + goto done; + } + } + +done: + if (ctx->log_fd >=3D 0 && ctx->vcpu_idx =3D=3D 0) { + close(ctx->log_fd); + } + munmap(kvm_run, ctx->vcpu_mmap_size); + qemu_mutex_lock(ctx->mutex); + if (!boot_signaled) { + (*ctx->halted_count)++; + qemu_cond_signal(ctx->cond); + } + qemu_mutex_unlock(ctx->mutex); + return NULL; +} + +static int kvm_handle_hc_vm_planes_activate(X86CPU *cpu, struct kvm_run *r= un) +{ + uint64_t gpa =3D run->hypercall.args[0]; + uint64_t plane_count =3D run->hypercall.args[1]; + uint64_t plane_id; + KVMState *s =3D kvm_state; + int vcpu_mmap_size; + + if (!gpa || !plane_count || !s->vm_planes || + plane_count !=3D s->vm_plane_count) { + run->hypercall.ret =3D -EINVAL; + return 0; + } + + vcpu_mmap_size =3D kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); + if (vcpu_mmap_size <=3D 0) { + error_report("vm_planes: KVM_GET_VCPU_MMAP_SIZE failed"); + run->hypercall.ret =3D -EINVAL; + return 0; + } + + for (plane_id =3D 1; plane_id < plane_count; plane_id++) { + struct kvm_vm_plane_state *ps =3D &s->vm_planes[plane_id]; + uint64_t stack_addr; + uint64_t entry_point =3D 0; + uint64_t cmdline_gpa, zero_page_gpa; + uint64_t pt_base, pml4_gpa, pdpt_gpa, pd_base, gdt_gpa_val; + struct vm_plane_boot_ctx *ctxs; + QemuThread *threads; + QemuMutex mutex; + QemuCond cond; + unsigned int halted_count =3D 0; + unsigned int i; + int plane_log_fd =3D -1; + + if (kvm_get_plane_fd(s, plane_id) < 0 || !ps->vcpu_count || + !ps->host_addr) { + error_report("vm_planes: plane %" PRIu64 " not configured", + plane_id); + run->hypercall.ret =3D -EINVAL; + return 0; + } + + cpu_physical_memory_read(gpa + (plane_id * VM_PLANE_CFG_STRIDE) + = 16, + &entry_point, 8); + if (!entry_point) { + error_report("vm_planes: plane %" PRIu64 " bad entry_point", + plane_id); + run->hypercall.ret =3D -EIO; + return 0; + } + ps->entry_point =3D entry_point; + + stack_addr =3D ps->load_offset + ps->memory_size; + cmdline_gpa =3D stack_addr - 0x1000; + zero_page_gpa =3D stack_addr - 0x2000; + pt_base =3D ps->load_offset + ps->memory_size - 0x10000; + pml4_gpa =3D pt_base; + pdpt_gpa =3D pt_base + 0x1000; + pd_base =3D pt_base + 0x2000; + gdt_gpa_val =3D pt_base + 0x6000; + +#define PLANE_HOST(g) ((uint8_t *)ps->host_addr + ((g) - ps->load_offset)) + + /* cmdline */ + { + size_t cl =3D strlen(ps->cmdline) + 1; + memcpy(PLANE_HOST(cmdline_gpa), ps->cmdline, cl); + } + + /* boot_params zero page */ + { + uint8_t zp[4096] =3D {}; + uint32_t cl_ptr =3D (uint32_t)(cmdline_gpa & 0xffffffff); + uint32_t cl_hi =3D (uint32_t)(cmdline_gpa >> 32); + struct { + uint64_t addr; + uint64_t size; + uint32_t type; + } QEMU_PACKED e820 =3D { + ps->load_offset, ps->memory_size, 1, + }; + + zp[0x1fe] =3D 0x55; zp[0x1ff] =3D 0xAA; + zp[0x202] =3D 'H'; zp[0x203] =3D 'd'; + zp[0x204] =3D 'r'; zp[0x205] =3D 'S'; + zp[0x206] =3D 0x0f; zp[0x207] =3D 0x02; + zp[0x210] =3D 0xff; + memcpy(&zp[0x228], &cl_ptr, 4); + memcpy(&zp[0x0c8], &cl_hi, 4); + zp[0x1e8] =3D 1; + memcpy(&zp[0x2d0], &e820, 20); + memcpy(PLANE_HOST(zero_page_gpa), zp, sizeof(zp)); + } + + /* Identity-mapped page tables (PML4 =E2=86=92 PDPT =E2=86=92 4=C3= =97PD with 2MB pages) */ + { + uint8_t page[4096]; + uint64_t *entries; + int pd_idx; + + memset(page, 0, sizeof(page)); + entries =3D (uint64_t *)page; + entries[0] =3D pdpt_gpa | 0x3; + memcpy(PLANE_HOST(pml4_gpa), page, 4096); + + memset(page, 0, sizeof(page)); + entries =3D (uint64_t *)page; + for (pd_idx =3D 0; pd_idx < 4; pd_idx++) { + entries[pd_idx] =3D (pd_base + pd_idx * 0x1000) | 0x3; + } + memcpy(PLANE_HOST(pdpt_gpa), page, 4096); + + for (pd_idx =3D 0; pd_idx < 4; pd_idx++) { + int j; + memset(page, 0, sizeof(page)); + entries =3D (uint64_t *)page; + for (j =3D 0; j < 512; j++) { + uint64_t phys =3D ((uint64_t)pd_idx << 30) | + ((uint64_t)j << 21); + entries[j] =3D phys | 0x83; + } + memcpy(PLANE_HOST(pd_base + pd_idx * 0x1000), page, 4096); + } + } + + /* Minimal GDT */ + { + uint8_t gdt[48] =3D {}; + uint64_t *gdt64 =3D (uint64_t *)gdt; + + gdt64[0] =3D 0; + gdt64[1] =3D 0; + gdt64[2] =3D 0x00af9a000000ffffULL; + gdt64[3] =3D 0x00cf92000000ffffULL; + gdt64[4] =3D 0; + gdt64[5] =3D 0x0000890000000067ULL; + memcpy(PLANE_HOST(gdt_gpa_val), gdt, sizeof(gdt)); + } + + /* Initialize all plane vCPUs */ + for (i =3D 0; i < ps->vcpu_count; i++) { + int ret =3D kvm_init_plane_vcpu(ps->vcpu_fds[i], entry_point, + stack_addr, zero_page_gpa, pml4_= gpa, + gdt_gpa_val, i =3D=3D 0); + if (ret) { + error_report("vm_planes: init plane %" PRIu64 " vcpu %u " + "failed", plane_id, i); + run->hypercall.ret =3D ret; + return 0; + } + } +#undef PLANE_HOST + + /* Serial log */ + { + char lp[256]; + snprintf(lp, sizeof(lp), "/tmp/plane%" PRIu64 "-serial.log", + plane_id); + plane_log_fd =3D open(lp, O_CREAT | O_WRONLY | O_TRUNC, 0644); + } + + /* Spawn vCPU threads */ + qemu_mutex_init(&mutex); + qemu_cond_init(&cond); + + ctxs =3D g_new0(struct vm_plane_boot_ctx, ps->vcpu_count); + threads =3D g_new0(QemuThread, ps->vcpu_count); + + for (i =3D 0; i < ps->vcpu_count; i++) { + char name[48]; + + ctxs[i].vcpu_fd =3D ps->vcpu_fds[i]; + ctxs[i].vcpu_mmap_size =3D vcpu_mmap_size; + ctxs[i].vcpu_idx =3D i; + ctxs[i].plane_id =3D plane_id; + ctxs[i].halted_count =3D &halted_count; + ctxs[i].mutex =3D &mutex; + ctxs[i].cond =3D &cond; + ctxs[i].result =3D 0; + ctxs[i].log_fd =3D (i =3D=3D 0) ? plane_log_fd : -1; + qemu_mutex_init(&ctxs[i].wake_mutex); + qemu_cond_init(&ctxs[i].wake_cond); + ctxs[i].halted =3D false; + ctxs[i].kick =3D false; + ctxs[i].stopped =3D false; + + snprintf(name, sizeof(name), "plane%" PRIu64 "-vcpu%u", + plane_id, i); + qemu_thread_create(&threads[i], name, vm_plane_vcpu_thread, + &ctxs[i], QEMU_THREAD_JOINABLE); + } + + /* Wait up to 5s for plane to reach first HLT */ + { + int64_t dl =3D qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + + 5LL * 1000000000LL; + qemu_mutex_lock(&mutex); + while (halted_count < ps->vcpu_count) { + int64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + if (now >=3D dl) { + info_report("vm_planes: plane %" PRIu64 " boot timeout= " + "(%u/%u halted)", plane_id, halted_count, + ps->vcpu_count); + break; + } + qemu_cond_timedwait(&cond, &mutex, 1000); + } + qemu_mutex_unlock(&mutex); + } + + /* Note: threads keep running for the plane's lifetime; we + * intentionally leak ctxs/threads =E2=80=94 they outlive this cal= l. */ + + /* Seal plane memory via KVM_SET_MEMORY_ATTRIBUTES(NO_WRITE|NO_EXE= C) */ + { + struct kvm_memory_attributes ma =3D { + .address =3D ps->load_offset, + .size =3D ps->memory_size, + .attributes =3D KVM_MEMORY_ATTRIBUTE_NO_WRITE | + KVM_MEMORY_ATTRIBUTE_NO_EXEC, + .flags =3D 0, + }; + int pr =3D kvm_vm_ioctl(s, KVM_SET_MEMORY_ATTRIBUTES, &ma); + if (pr < 0) { + warn_report("vm_planes: plane %" PRIu64 " seal failed (%d)= ", + plane_id, pr); + } else { + info_report("vm_planes: plane %" PRIu64 " memory sealed", + plane_id); + } + } + ps->host_addr =3D NULL; + + info_report("vm_planes: plane %" PRIu64 " launched =E2=80=94 entry= 0x%" PRIx64 + " vcpus %u", plane_id, entry_point, ps->vcpu_count); + } + + run->hypercall.ret =3D 0; + return 0; +} + +static int vbs_apply_protection(KVMState *s, uint64_t gpa, uint64_t size, + uint32_t perms) +{ + uint64_t attrs =3D 0; + struct kvm_memory_attributes ma; + + if (!(perms & 2)) { + attrs |=3D KVM_MEMORY_ATTRIBUTE_NO_WRITE; + } + if (!(perms & 4)) { + attrs |=3D KVM_MEMORY_ATTRIBUTE_NO_EXEC; + } + if (!attrs) { + return 0; + } + + ma.address =3D gpa; + ma.size =3D size; + ma.attributes =3D attrs; + ma.flags =3D 0; + return kvm_vm_ioctl(s, KVM_SET_MEMORY_ATTRIBUTES, &ma); +} + +static int32_t vbs_handle_protect_memory(KVMState *s, uint64_t ca_gpa) +{ + uint64_t gpa, size; + uint32_t perms, arg_size; + + cpu_physical_memory_read(ca_gpa + CA_OFF_ARG_SIZE, &arg_size, 4); + if (arg_size < 24) { + return -22; + } + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 0, &gpa, 8); + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 8, &size, 8); + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 16, &perms, 4); + return vbs_apply_protection(s, gpa, size, perms); +} + +static int32_t vbs_handle_seal_kernel(KVMState *s, uint64_t ca_gpa) +{ + uint64_t text_gpa, text_size, rodata_gpa, rodata_size; + uint32_t arg_size; + int ret; + + cpu_physical_memory_read(ca_gpa + CA_OFF_ARG_SIZE, &arg_size, 4); + if (arg_size < 40) { + return -22; + } + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 0, &text_gpa, 8); + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 8, &text_size, 8); + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 16, &rodata_gpa, 8); + cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 24, &rodata_size, 8); + + ret =3D vbs_apply_protection(s, text_gpa, text_size, 1 | 4); + if (ret < 0) { + return ret; + } + return vbs_apply_protection(s, rodata_gpa, rodata_size, 1); +} + +static int kvm_handle_hc_vbs_vtl_call(X86CPU *cpu, struct kvm_run *run) +{ + uint64_t ca_gpa =3D run->hypercall.args[0]; + uint32_t call_id; + int32_t status; + KVMState *s =3D kvm_state; + + cpu_physical_memory_read(ca_gpa + CA_OFF_CALL_ID, &call_id, 4); + + switch (call_id) { + case VBS_CALL_INIT: + case VBS_CALL_SHUTDOWN: + status =3D 0; + break; + case VBS_CALL_PROTECT_MEMORY: + status =3D vbs_handle_protect_memory(s, ca_gpa); + break; + case VBS_CALL_SEAL_KERNEL: + status =3D vbs_handle_seal_kernel(s, ca_gpa); + break; + case VBS_CALL_VALIDATE_MODULE: + case VBS_CALL_SET_MODULE_PERMS: + case VBS_CALL_UNLOAD_MODULE: + case VBS_CALL_ADD_KEY: + case VBS_CALL_REVOKE_KEY: + case VBS_CALL_SEND_CERTS: + case VBS_CALL_KEXEC_VALIDATE: + case VBS_CALL_KEXEC_INVALIDATE: + status =3D 0; /* acknowledge */ + break; + default: + warn_report("vbs_vtl_call: unknown call_id 0x%04x", call_id); + status =3D -38; + break; + } + + cpu_physical_memory_write(ca_gpa + CA_OFF_STATUS, &status, 4); + run->hypercall.ret =3D 0; + return 0; +} + static int kvm_handle_hypercall(X86CPU *cpu, struct kvm_run *run) { if (run->hypercall.nr =3D=3D KVM_HC_MAP_GPA_RANGE) return kvm_handle_hc_map_gpa_range(cpu, run); + if (run->hypercall.nr =3D=3D KVM_HC_VM_PLANES_CONFIG) + return kvm_handle_hc_vm_planes_config(cpu, run); + if (run->hypercall.nr =3D=3D KVM_HC_VM_PLANES_ACTIVATE) + return kvm_handle_hc_vm_planes_activate(cpu, run); + if (run->hypercall.nr =3D=3D KVM_HC_VBS_VTL_CALL) + return kvm_handle_hc_vbs_vtl_call(cpu, run); =20 return -EINVAL; } --=20 2.55.0 From nobody Wed Aug 26 12:56:54 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785927919; cv=none; d=zohomail.com; s=zohoarc; b=G87Q2gYWCKfdhNTB4WC5tJ2eXIzMoX8uVFveY8WemSxMUojIreBjGg2IkHYqt3dg/LLCpqJv85KPcBhZtp50KS8RdVMoJpuaBYL5/wz0RvDPFRVlIxJPqSFv2l7SssqFTT294KAWHttM45JvCvynDq2yEIxgC4tcfgVZKwLrNbY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785927919; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=04q3RI9A0fv9Xv+CMnIW2+ug2+E5td90cLNjC3O338o=; b=js1jhnxG76Yv/cqcBD0EPeVqqeUMueFsozRq/uvPNBcDr2b6PSlkpoyVBIL/gxyoz1M/675KyanLjjYhQ3c2QTTF5ROanBJS/25wwlPRZklZdPGZ7q5bVl2Uu8on1js2kkKQT+g7UMVxPXBFhHWesrwMHDnF5dsuyh6tOZgXvWQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178592791934914.38892717691624; Wed, 5 Aug 2026 04:05:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQS-0000mo-I8; Wed, 05 Aug 2026 07:04:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wrZQO-0000jX-9q for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:40 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQL-0000CA-Vg for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:39 -0400 Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id 8876620B716B; Wed, 5 Aug 2026 04:04:15 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8876620B716B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927855; bh=04q3RI9A0fv9Xv+CMnIW2+ug2+E5td90cLNjC3O338o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cf09I0XR8R2W07hl3fGLpXOq8j1M18pEWCZofQxc9vmvmSLxgtUn+ohS7Ly05r0k5 +7J6dgvhRxSV9AglW/1olZyReiSLgZXYcNMVByExMl164o5vbtXAF2ZsCBiqmHGEIQ lAj+OnfnXZ9OHS2TG1RcsFqokEsXpA7J62eI3n2o= From: Sriram Nambakam To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org Subject: [RFC PATCH v1 2/5] vm_planes: Add VBS VTL call handling and plane memory sealing Date: Wed, 5 Aug 2026 04:04:29 -0700 Message-ID: <20260805110432.25167-3-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110432.25167-1-snambakam@linux.microsoft.com> References: <20260805110432.25167-1-snambakam@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=snambakam@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785927920147158501 Content-Type: text/plain; charset="utf-8" Wire up the VBS inter-plane communication and memory protection infrastructure on the QEMU side. Memory sealing (plane activate path): After plane-1 boots and its vCPU threads are running, seal plane-1's memory from plane-0 access: 1. Issue KVM_SET_PLANE_MEMORY_ATTRIBUTES to set NO_WRITE|NO_EXEC on plane-0's EPT for the GPA range occupied by plane-1. 2. Clear ps->host_addr so QEMU userspace can no longer access the region. VBS VTL hypercall handler: Handle KVM_HC_VBS_VTL_CALL (hypercall 15) exits from the guest. The plane-0 VBS subsystem passes the GPA of a shared calling-area (CAA) page; QEMU reads the call_id from the page, logs it, and returns -ENOSYS for now (plane-1 responder not yet implemented). Enable the hypercall in kvm_enable_hypercall() alongside the existing VM planes hypercalls. Header sync: - linux-headers/linux/kvm.h: Add KVM_MEMORY_ATTRIBUTE_NO_WRITE, KVM_MEMORY_ATTRIBUTE_NO_EXEC, struct kvm_plane_memory_attributes, and KVM_SET_PLANE_MEMORY_ATTRIBUTES ioctl definition. - include/standard-headers/linux/kvm_para.h: Add KVM_HC_VBS_VTL_CALL. (cherry picked from commit 414016c40ec8226b0f5d4cbd5eed0589b7c1689e) --- linux-headers/linux/kvm.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index d66ce6d272..9dbd3824e9 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1653,6 +1653,19 @@ struct kvm_memory_attributes { }; =20 #define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3) +#define KVM_MEMORY_ATTRIBUTE_NO_WRITE (1ULL << 4) +#define KVM_MEMORY_ATTRIBUTE_NO_EXEC (1ULL << 5) + +/* Set memory attributes on a specific plane's address space. */ +struct kvm_plane_memory_attributes { + __u32 plane; + __u32 flags; + __u64 address; + __u64 size; + __u64 attributes; +}; + +#define KVM_SET_PLANE_MEMORY_ATTRIBUTES _IOW(KVMIO, 0xd6, struct kvm_plane= _memory_attributes) =20 #define KVM_MEMORY_ATTRIBUTE_NO_WRITE (1ULL << 4) #define KVM_MEMORY_ATTRIBUTE_NO_EXEC (1ULL << 5) --=20 2.55.0 From nobody Wed Aug 26 12:56:54 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785927974; cv=none; d=zohomail.com; s=zohoarc; b=WzcCMk5I3TVpKxsMA+5u+GTia5eYLT8rsqklcti2AIij1P7HQDqJmnqtNGa9LKFyZxVR158tkKP2mACltTo0l2G+ov7umcBKdXu4UPExpqQ8pHn9LdCiG7MRl0GCP6UkS4m64I6WSHpk+kpLErsbye5qFaMMx3POCHI5vzs7b3w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785927974; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=LWWPECdd7trZNFf94dG6xpNIuU8Yn0i5MN5bN/aqB+A=; b=BMBLq2Rp3RTpnAWGuEaKy8wSsQcCI5RakFlIEjpMeA3n6aCQ1UwMScOsOlROPXinj78pwe1M23a9gAG7qZcXGYJQqpUh80fdFG6V143yWY0r6zfpg9apo8Z/btSdQVhNJVFMBgoP0uvRbWMvtxKK1b9BFAVOobpIC6a3GWE6b4A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785927974876165.4183935085331; Wed, 5 Aug 2026 04:06:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQQ-0000lT-Jl; Wed, 05 Aug 2026 07:04:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wrZQO-0000jm-LW for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:40 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQL-0000CI-Vu for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:40 -0400 Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id 1A2E620B716C; Wed, 5 Aug 2026 04:04:16 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 1A2E620B716C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927856; bh=LWWPECdd7trZNFf94dG6xpNIuU8Yn0i5MN5bN/aqB+A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YqpS+TH0f7HQDBtfEPknq2m0RL4xbBCPp3NfCUWeskp1Uk9flxxrsRfE4rHK1WtdV qOFYQIyjytZLj+H0g6pCFdjrt+xF7kF0+omOptH5UTIvLAeTAN3xTX46YrjgnWBSIl ZjOhk3+bKxiLnqAK9tVX5PhSIYcSYepe8i7G65uw= From: Sriram Nambakam To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org Subject: [RFC PATCH v1 3/5] linux-headers: sync kvm_para.h VBS VTL hypercalls Date: Wed, 5 Aug 2026 04:04:30 -0700 Message-ID: <20260805110432.25167-4-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110432.25167-1-snambakam@linux.microsoft.com> References: <20260805110432.25167-1-snambakam@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=snambakam@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785927976349158500 Content-Type: text/plain; charset="utf-8" Import the two new VBS secure-plane hypercall numbers from the kernel UAPI: KVM_HC_VBS_VTL_RETURN (16) and KVM_HC_VBS_SET_MEM_ATTRS (17). Signed-off-by: Sriram Nambakam (cherry picked from commit 92f71c68c2eb42588694ac23fb4a6a8ef8dfa12b) --- include/standard-headers/linux/kvm_para.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/standard-headers/linux/kvm_para.h b/include/standard-h= eaders/linux/kvm_para.h index ad19aac9d0..def451c43c 100644 --- a/include/standard-headers/linux/kvm_para.h +++ b/include/standard-headers/linux/kvm_para.h @@ -33,6 +33,8 @@ #define KVM_HC_VM_PLANES_CONFIG 13 #define KVM_HC_VM_PLANES_ACTIVATE 14 #define KVM_HC_VBS_VTL_CALL 15 +#define KVM_HC_VBS_VTL_RETURN 16 +#define KVM_HC_VBS_SET_MEM_ATTRS 17 =20 /* * hypercalls use architecture specific --=20 2.55.0 From nobody Wed Aug 26 12:56:54 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785927952; cv=none; d=zohomail.com; s=zohoarc; b=J5zfERnBDczrhDy3eMMskaTwd1PCzCgh6z+17F6udK6HyliS9gaRUaMpfM4UVTHX58YPs2Owuqdaf8ga5JqY8GfLb8+vZXWvMw3qiMyEoKExKcNMG7iMpIfAHvf7fjPiypmmTQQEbauN2vfJfb4XvBLZouMgfFAItl8poVSowkQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785927952; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=yjbu25v6uYx/tC7572WVZCaIO5Pyb1mNt2gKgiiUzwo=; b=RY101OYP508qMK2v4eeqrhYCBYmv/IOLzW2JzZEf/19eiM4FhsppFZKGDuctJuizkZoetV3m5moYxiMCLDGY8PFQ23v8j44ox7avhbtOEOIJVYrz8pvS7nz2yOJkaMdsPOmYwWBC3yYrws/3NM2deCmAqD5H4RkOEofLjAYr7AI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785927952529552.4619189264348; Wed, 5 Aug 2026 04:05:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQT-0000mu-CX; Wed, 05 Aug 2026 07:04:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wrZQQ-0000m9-Uo for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:43 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQN-0000DV-6Q for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:42 -0400 Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id 9046920B716D; Wed, 5 Aug 2026 04:04:16 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 9046920B716D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927856; bh=yjbu25v6uYx/tC7572WVZCaIO5Pyb1mNt2gKgiiUzwo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sbFYykHAZKwQXyxWBPI0FoBVuLeeMLplg1WhwbCEb+VeSDKbfCGu4ufDU6bZ6amKK JkOIhOM3ijItBvFOviFBGuNLTSxKpENfJNrjMEt2vjqFYEW21xpykxAxlU6hLK5MZu E9jIH1iDv9WtFn39jaSumxVZdrxHaZ71Vj1shxDw= From: Sriram Nambakam To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org Subject: [RFC PATCH v1 4/5] target/i386/kvm: run the secure plane in-kernel (Option B) Date: Wed, 5 Aug 2026 04:04:31 -0700 Message-ID: <20260805110432.25167-5-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110432.25167-1-snambakam@linux.microsoft.com> References: <20260805110432.25167-1-snambakam@linux.microsoft.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=snambakam@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785927954270158500 Move secure-plane execution into the kernel and out of QEMU. Plane vCPUs are now created and initialised on their owning plane-0 CPU thread via run_on_cpu() (plane_vcpu_create_cb / plane_vcpu_init_cb), and the activate path leaves the secure vCPU stopped: it boots lazily inside KVM on the first KVM_HC_VBS_VTL_CALL, which KVM now services itself. Drop the userspace secure-world emulation that this replaces: the dedicated vm_plane_vcpu_thread (with its 8250 emulation and per-plane serial capture), vbs_apply_protection, vbs_handle_protect_memory, vbs_handle_seal_kernel and the kvm_handle_hc_vbs_vtl_call dispatch. Track each plane vCPU's owning CPU index (vcpu_cpu_index) so the run_on_cpu callbacks target the right thread. Signed-off-by: Sriram Nambakam (cherry picked from commit cbecc9eda1514d200fefe2bb89f330be4f1ab1be) --- include/system/kvm_int.h | 1 + target/i386/kvm/kvm.c | 536 ++++++++++++--------------------------- 2 files changed, 157 insertions(+), 380 deletions(-) diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h index e7c9dc95a2..cde0a148e1 100644 --- a/include/system/kvm_int.h +++ b/include/system/kvm_int.h @@ -114,6 +114,7 @@ struct KVMPlane { * kvm_get_plane_fd(s, plane_id); only LVBS-specific state lives here. */ struct kvm_vm_plane_state { int *vcpu_fds; + unsigned int *vcpu_cpu_index; /* owning plane-0 CPU index per plane v= CPU */ unsigned int vcpu_count; uint64_t load_offset; uint64_t memory_size; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 9d89e5cac6..5ac7962e61 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -6541,10 +6541,9 @@ static int kvm_handle_hc_map_gpa_range(X86CPU *cpu, = struct kvm_run *run) * off 0 u64 load_offset * off 8 u64 memory_size * off 16 u64 entry_point - * off 24 u32 vcpu_count - * off 28 u32 kernel_format - * off 32 char kernel[128] - * off 160 char cmdline[512] + * off 24 u32 kernel_format + * off 28 char kernel[128] + * off 156 char cmdline[512] * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ =20 #define VM_PLANE_CFG_STRIDE 672 @@ -6568,23 +6567,37 @@ static int kvm_handle_hc_map_gpa_range(X86CPU *cpu,= struct kvm_run *run) #define CA_OFF_RESP_SIZE 16 #define CA_OFF_BUFFER 20 =20 -struct vm_plane_boot_ctx { - int vcpu_fd; - int vcpu_mmap_size; - unsigned int vcpu_idx; - uint64_t plane_id; - unsigned int *halted_count; - QemuMutex *mutex; - QemuCond *cond; - int result; - int log_fd; - QemuMutex wake_mutex; - QemuCond wake_cond; - bool halted; - bool kick; - bool stopped; +/* + * Plane>0 vCPU creation and initialization must run on the OWNING plane-0 + * vCPU's thread. A plane>0 vCPU shares its plane-0 sibling's + * struct kvm_vcpu_common, including the single embedded preempt_notifier. + * KVM_CREATE_VCPU and KVM_SET_{S,}REGS / KVM_SET_MP_STATE all vcpu_load() + * the plane vCPU, which registers that shared notifier on the *calling* + * task. If issued from the config/activate-hypercall vCPU's thread while= a + * sibling is concurrently in KVM_RUN on another host CPU, the same + * hlist_node would be linked onto two tasks' preempt-notifier lists -> + * list corruption -> host hard lockup. run_on_cpu() forces the sibling o= ut + * of KVM_RUN (KVM_RUN returns, vcpu_put() unregisters the notifier) and + * runs the work on that sibling's own thread, so the notifier is owned by + * exactly one task. For the current vCPU, run_on_cpu() runs inline. + */ +struct plane_vcpu_create_ctx { + KVMState *s; + unsigned int plane_id; + unsigned int vcpu_id; + int fd; /* out: vcpu fd, or -errno on failure */ }; =20 +static void plane_vcpu_create_cb(CPUState *cs, run_on_cpu_data data) +{ + struct plane_vcpu_create_ctx *ctx =3D data.host_ptr; + int fd; + + fd =3D kvm_vm_plane_ioctl(ctx->s, ctx->plane_id, KVM_CREATE_VCPU, + (void *)(uintptr_t)ctx->vcpu_id); + ctx->fd =3D (fd < 0) ? -errno : fd; +} + static int kvm_handle_hc_vm_planes_config(X86CPU *cpu, struct kvm_run *run) { uint64_t gpa =3D run->hypercall.args[0]; @@ -6645,7 +6658,7 @@ static int kvm_handle_hc_vm_planes_config(X86CPU *cpu= , struct kvm_run *run) for (plane_id =3D 1; plane_id < plane_count; plane_id++) { uint64_t plane_gpa =3D gpa + (plane_id * VM_PLANE_CFG_STRIDE); uint64_t load_offset =3D 0, memory_size =3D 0, entry_point =3D 0; - uint32_t vcpu_count =3D 0; + uint32_t vcpu_count =3D plane0_vcpu_count; struct kvm_vm_plane_state *ps =3D &s->vm_planes[plane_id]; char cmdline_buf[512]; MemoryRegionSection section; @@ -6655,29 +6668,24 @@ static int kvm_handle_hc_vm_planes_config(X86CPU *c= pu, struct kvm_run *run) cpu_physical_memory_read(plane_gpa + 0, &load_offset, 8); cpu_physical_memory_read(plane_gpa + 8, &memory_size, 8); cpu_physical_memory_read(plane_gpa + 16, &entry_point, 8); - cpu_physical_memory_read(plane_gpa + 24, &vcpu_count, 4); =20 - if (!memory_size || !vcpu_count) { + /* + * joergroedel plane model: a plane has exactly one vCPU per + * plane-0 vCPU =E2=80=94 each is the sibling of a plane-0 vCPU sh= aring the + * same logical CPU. The guest does not configure a count; QEMU + * mirrors the plane-0 vCPU set. + */ + if (!memory_size) { error_report("vm_planes: plane %" PRIu64 " invalid " - "(load_offset=3D0x%" PRIx64 " size=3D0x%" PRIx64 - " vcpus=3D%u)", - plane_id, load_offset, memory_size, vcpu_count); - g_free(plane0_vcpu_ids); - run->hypercall.ret =3D -EINVAL; - return 0; - } - - if (vcpu_count > plane0_vcpu_count) { - error_report("vm_planes: plane %" PRIu64 " requests %u vCPUs, " - "but plane0 has %u", plane_id, vcpu_count, - plane0_vcpu_count); + "(load_offset=3D0x%" PRIx64 " size=3D0x%" PRIx64 = ")", + plane_id, load_offset, memory_size); g_free(plane0_vcpu_ids); run->hypercall.ret =3D -EINVAL; return 0; } =20 memset(cmdline_buf, 0, sizeof(cmdline_buf)); - cpu_physical_memory_read(plane_gpa + 160, cmdline_buf, + cpu_physical_memory_read(plane_gpa + 156, cmdline_buf, sizeof(cmdline_buf)); cmdline_buf[sizeof(cmdline_buf) - 1] =3D '\0'; memcpy(ps->cmdline, cmdline_buf, sizeof(ps->cmdline)); @@ -6714,24 +6722,46 @@ static int kvm_handle_hc_vm_planes_config(X86CPU *c= pu, struct kvm_run *run) memory_region_unref(section.mr); =20 ps->vcpu_fds =3D g_new0(int, vcpu_count); + ps->vcpu_cpu_index =3D g_new0(unsigned int, vcpu_count); for (i =3D 0; i < vcpu_count; i++) { - int vcpu_fd; unsigned int vcpu_id =3D plane0_vcpu_ids[i]; + CPUState *target =3D qemu_get_cpu(vcpu_id); + struct plane_vcpu_create_ctx cctx =3D { + .s =3D s, + .plane_id =3D plane_id, + .vcpu_id =3D vcpu_id, + .fd =3D -EINVAL, + }; + + if (!target) { + error_report("vm_planes: plane %" PRIu64 " no CPU for id= =3D%u", + plane_id, vcpu_id); + close(plane_fd); + kvm_set_plane_fd(s, plane_id, -1); + g_free(plane0_vcpu_ids); + run->hypercall.ret =3D -EINVAL; + return 0; + } =20 - vcpu_fd =3D kvm_vm_plane_ioctl(s, plane_id, KVM_CREATE_VCPU, - (void *)(uintptr_t)vcpu_id); - if (vcpu_fd < 0) { + /* Create on the owning CPU's thread; see plane_vcpu_create_cb= . */ + bql_lock(); + run_on_cpu(target, plane_vcpu_create_cb, + RUN_ON_CPU_HOST_PTR(&cctx)); + bql_unlock(); + + if (cctx.fd < 0) { error_report("vm_planes: KVM_CREATE_VCPU plane %" PRIu64 " vcpu %u failed: %s", - plane_id, vcpu_id, strerror(errno)); + plane_id, vcpu_id, strerror(-cctx.fd)); close(plane_fd); kvm_set_plane_fd(s, plane_id, -1); g_free(plane0_vcpu_ids); - run->hypercall.ret =3D -errno; + run->hypercall.ret =3D cctx.fd; return 0; } =20 - ps->vcpu_fds[i] =3D vcpu_fd; + ps->vcpu_fds[i] =3D cctx.fd; + ps->vcpu_cpu_index[i] =3D vcpu_id; } =20 ps->vcpu_count =3D vcpu_count; @@ -6757,10 +6787,6 @@ static int kvm_init_plane_vcpu(int vcpu_fd, uint64_t= entry_addr, { struct kvm_regs regs =3D {}; struct kvm_sregs sregs =3D {}; - struct kvm_mp_state mp =3D { - .mp_state =3D is_bsp ? KVM_MP_STATE_RUNNABLE - : KVM_MP_STATE_INIT_RECEIVED, - }; int ret; =20 sregs.cs.base =3D 0; sregs.cs.limit =3D 0xffffffff; sregs.cs.selector = =3D 0x10; @@ -6806,144 +6832,42 @@ static int kvm_init_plane_vcpu(int vcpu_fd, uint64= _t entry_addr, return -errno; } =20 - ret =3D ioctl(vcpu_fd, KVM_SET_MP_STATE, &mp); - if (ret < 0) { - error_report("vm_planes: KVM_SET_MP_STATE: %s", strerror(errno)); - return -errno; - } + /* + * Do NOT issue KVM_SET_MP_STATE on a plane (plane_level > 0) vCPU fd: + * the VM-planes kernel only whitelists a subset of vCPU ioctls for + * plane vCPUs (KVM_SET_*REGS/SREGS/FPU/LAPIC/...), and KVM_SET_MP_STA= TE + * is intentionally excluded -> it returns -EINVAL. The kernel already + * establishes the correct initial MP state at create time: the plane + * BSP (vcpu_id =3D=3D bsp_vcpu_id) is left RUNNABLE, and APs are left + * UNINITIALIZED (wait-for-INIT), which is the correct power-on state. + * The plane guest's own SMP bringup INIT/SIPIs its APs via the + * in-kernel LAPIC, so no userspace MP-state poke is needed. + */ return 0; } =20 -static void *vm_plane_vcpu_thread(void *arg) -{ - struct vm_plane_boot_ctx *ctx =3D arg; - struct kvm_run *kvm_run; - int ret; - bool boot_signaled =3D false; - - kvm_run =3D mmap(NULL, ctx->vcpu_mmap_size, PROT_READ | PROT_WRITE, - MAP_SHARED, ctx->vcpu_fd, 0); - if (kvm_run =3D=3D MAP_FAILED) { - error_report("vm_planes: plane %" PRIu64 " vcpu %u: mmap failed: %= s", - ctx->plane_id, ctx->vcpu_idx, strerror(errno)); - ctx->result =3D -errno; - qemu_mutex_lock(ctx->mutex); - (*ctx->halted_count)++; - qemu_cond_signal(ctx->cond); - qemu_mutex_unlock(ctx->mutex); - return NULL; - } - - for (;;) { - ret =3D ioctl(ctx->vcpu_fd, KVM_RUN, 0); - if (ret < 0) { - if (errno =3D=3D EINTR || errno =3D=3D EAGAIN) { - continue; - } - error_report("vm_planes: plane %" PRIu64 " vcpu %u: KVM_RUN: %= s", - ctx->plane_id, ctx->vcpu_idx, strerror(errno)); - ctx->result =3D -errno; - break; - } - - switch (kvm_run->exit_reason) { - case KVM_EXIT_HLT: - if (!boot_signaled) { - boot_signaled =3D true; - qemu_mutex_lock(ctx->mutex); - (*ctx->halted_count)++; - qemu_cond_signal(ctx->cond); - qemu_mutex_unlock(ctx->mutex); - } - qemu_mutex_lock(&ctx->wake_mutex); - ctx->halted =3D true; - while (!ctx->kick && !ctx->stopped) { - qemu_cond_wait(&ctx->wake_cond, &ctx->wake_mutex); - } - ctx->halted =3D false; - ctx->kick =3D false; - if (ctx->stopped) { - qemu_mutex_unlock(&ctx->wake_mutex); - goto done; - } - qemu_mutex_unlock(&ctx->wake_mutex); - break; - - case KVM_EXIT_IO: { - uint8_t *io_data =3D (uint8_t *)kvm_run + kvm_run->io.data_off= set; - size_t io_size =3D kvm_run->io.size * kvm_run->io.count; - uint16_t port =3D kvm_run->io.port; - - if (kvm_run->io.direction =3D=3D KVM_EXIT_IO_OUT) { - if (port =3D=3D 0x3f8 && ctx->log_fd >=3D 0) { - ssize_t w =3D write(ctx->log_fd, io_data, io_size); - (void)w; - } - } else { - memset(io_data, 0, io_size); - switch (port) { - case 0x3fa: memset(io_data, 0xc1, io_size); break; - case 0x3fb: memset(io_data, 0x03, io_size); break; - case 0x3fc: memset(io_data, 0x08, io_size); break; - case 0x3fd: memset(io_data, 0x60, io_size); break; - case 0x3fe: memset(io_data, 0xb0, io_size); break; - default: break; - } - } - usleep(100); - break; - } - - case KVM_EXIT_MMIO: - usleep(100); - break; - - case KVM_EXIT_SHUTDOWN: { - struct kvm_regs dbg =3D {}; - ioctl(ctx->vcpu_fd, KVM_GET_REGS, &dbg); - error_report("vm_planes: plane %" PRIu64 " vcpu %u: shutdown " - "RIP=3D0x%" PRIx64 " RSP=3D0x%" PRIx64, - ctx->plane_id, ctx->vcpu_idx, - (uint64_t)dbg.rip, (uint64_t)dbg.rsp); - ctx->result =3D -EFAULT; - goto done; - } - - case KVM_EXIT_FAIL_ENTRY: - error_report("vm_planes: plane %" PRIu64 " vcpu %u: entry fail= ure " - "0x%" PRIx64, ctx->plane_id, ctx->vcpu_idx, - (uint64_t)kvm_run->fail_entry.hardware_entry_fail= ure_reason); - ctx->result =3D -EFAULT; - goto done; - - case KVM_EXIT_INTERNAL_ERROR: - error_report("vm_planes: plane %" PRIu64 " vcpu %u: internal " - "error %u", ctx->plane_id, ctx->vcpu_idx, - kvm_run->internal.suberror); - ctx->result =3D -EFAULT; - goto done; +/* Initialize a plane vCPU on its owning CPU's thread (see + * plane_vcpu_create_cb for why KVM_SET_*REGS / KVM_SET_MP_STATE, which + * vcpu_load() the shared common, must not race the running sibling). */ +struct plane_vcpu_init_ctx { + int vcpu_fd; + uint64_t entry_addr; + uint64_t stack_addr; + uint64_t zero_page_gpa; + uint64_t page_table_gpa; + uint64_t gdt_gpa; + bool is_bsp; + int ret; /* out: 0 on success, -errno on failure */ +}; =20 - default: - error_report("vm_planes: plane %" PRIu64 " vcpu %u: unexpected= " - "exit %u", ctx->plane_id, ctx->vcpu_idx, - kvm_run->exit_reason); - ctx->result =3D -EFAULT; - goto done; - } - } +static void plane_vcpu_init_cb(CPUState *cs, run_on_cpu_data data) +{ + struct plane_vcpu_init_ctx *ctx =3D data.host_ptr; =20 -done: - if (ctx->log_fd >=3D 0 && ctx->vcpu_idx =3D=3D 0) { - close(ctx->log_fd); - } - munmap(kvm_run, ctx->vcpu_mmap_size); - qemu_mutex_lock(ctx->mutex); - if (!boot_signaled) { - (*ctx->halted_count)++; - qemu_cond_signal(ctx->cond); - } - qemu_mutex_unlock(ctx->mutex); - return NULL; + ctx->ret =3D kvm_init_plane_vcpu(ctx->vcpu_fd, ctx->entry_addr, + ctx->stack_addr, ctx->zero_page_gpa, + ctx->page_table_gpa, ctx->gdt_gpa, + ctx->is_bsp); } =20 static int kvm_handle_hc_vm_planes_activate(X86CPU *cpu, struct kvm_run *r= un) @@ -6952,7 +6876,6 @@ static int kvm_handle_hc_vm_planes_activate(X86CPU *c= pu, struct kvm_run *run) uint64_t plane_count =3D run->hypercall.args[1]; uint64_t plane_id; KVMState *s =3D kvm_state; - int vcpu_mmap_size; =20 if (!gpa || !plane_count || !s->vm_planes || plane_count !=3D s->vm_plane_count) { @@ -6960,26 +6883,13 @@ static int kvm_handle_hc_vm_planes_activate(X86CPU = *cpu, struct kvm_run *run) return 0; } =20 - vcpu_mmap_size =3D kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); - if (vcpu_mmap_size <=3D 0) { - error_report("vm_planes: KVM_GET_VCPU_MMAP_SIZE failed"); - run->hypercall.ret =3D -EINVAL; - return 0; - } - for (plane_id =3D 1; plane_id < plane_count; plane_id++) { struct kvm_vm_plane_state *ps =3D &s->vm_planes[plane_id]; uint64_t stack_addr; uint64_t entry_point =3D 0; uint64_t cmdline_gpa, zero_page_gpa; uint64_t pt_base, pml4_gpa, pdpt_gpa, pd_base, gdt_gpa_val; - struct vm_plane_boot_ctx *ctxs; - QemuThread *threads; - QemuMutex mutex; - QemuCond cond; - unsigned int halted_count =3D 0; unsigned int i; - int plane_log_fd =3D -1; =20 if (kvm_get_plane_fd(s, plane_id) < 0 || !ps->vcpu_count || !ps->host_addr) { @@ -7086,98 +6996,60 @@ static int kvm_handle_hc_vm_planes_activate(X86CPU = *cpu, struct kvm_run *run) memcpy(PLANE_HOST(gdt_gpa_val), gdt, sizeof(gdt)); } =20 - /* Initialize all plane vCPUs */ + /* Initialize all plane vCPUs on their owning CPU threads. */ for (i =3D 0; i < ps->vcpu_count; i++) { - int ret =3D kvm_init_plane_vcpu(ps->vcpu_fds[i], entry_point, - stack_addr, zero_page_gpa, pml4_= gpa, - gdt_gpa_val, i =3D=3D 0); - if (ret) { - error_report("vm_planes: init plane %" PRIu64 " vcpu %u " - "failed", plane_id, i); - run->hypercall.ret =3D ret; + CPUState *target =3D qemu_get_cpu(ps->vcpu_cpu_index[i]); + struct plane_vcpu_init_ctx ictx =3D { + .vcpu_fd =3D ps->vcpu_fds[i], + .entry_addr =3D entry_point, + .stack_addr =3D stack_addr, + .zero_page_gpa =3D zero_page_gpa, + .page_table_gpa =3D pml4_gpa, + .gdt_gpa =3D gdt_gpa_val, + .is_bsp =3D (i =3D=3D 0), + .ret =3D -EINVAL, + }; + + if (!target) { + error_report("vm_planes: plane %" PRIu64 " no CPU for vcpu= %u", + plane_id, i); + run->hypercall.ret =3D -EINVAL; return 0; } - } -#undef PLANE_HOST - - /* Serial log */ - { - char lp[256]; - snprintf(lp, sizeof(lp), "/tmp/plane%" PRIu64 "-serial.log", - plane_id); - plane_log_fd =3D open(lp, O_CREAT | O_WRONLY | O_TRUNC, 0644); - } =20 - /* Spawn vCPU threads */ - qemu_mutex_init(&mutex); - qemu_cond_init(&cond); - - ctxs =3D g_new0(struct vm_plane_boot_ctx, ps->vcpu_count); - threads =3D g_new0(QemuThread, ps->vcpu_count); + /* See plane_vcpu_init_cb: must run on the sibling's own threa= d. */ + bql_lock(); + run_on_cpu(target, plane_vcpu_init_cb, + RUN_ON_CPU_HOST_PTR(&ictx)); + bql_unlock(); =20 - for (i =3D 0; i < ps->vcpu_count; i++) { - char name[48]; - - ctxs[i].vcpu_fd =3D ps->vcpu_fds[i]; - ctxs[i].vcpu_mmap_size =3D vcpu_mmap_size; - ctxs[i].vcpu_idx =3D i; - ctxs[i].plane_id =3D plane_id; - ctxs[i].halted_count =3D &halted_count; - ctxs[i].mutex =3D &mutex; - ctxs[i].cond =3D &cond; - ctxs[i].result =3D 0; - ctxs[i].log_fd =3D (i =3D=3D 0) ? plane_log_fd : -1; - qemu_mutex_init(&ctxs[i].wake_mutex); - qemu_cond_init(&ctxs[i].wake_cond); - ctxs[i].halted =3D false; - ctxs[i].kick =3D false; - ctxs[i].stopped =3D false; - - snprintf(name, sizeof(name), "plane%" PRIu64 "-vcpu%u", - plane_id, i); - qemu_thread_create(&threads[i], name, vm_plane_vcpu_thread, - &ctxs[i], QEMU_THREAD_JOINABLE); - } - - /* Wait up to 5s for plane to reach first HLT */ - { - int64_t dl =3D qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + - 5LL * 1000000000LL; - qemu_mutex_lock(&mutex); - while (halted_count < ps->vcpu_count) { - int64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - if (now >=3D dl) { - info_report("vm_planes: plane %" PRIu64 " boot timeout= " - "(%u/%u halted)", plane_id, halted_count, - ps->vcpu_count); - break; - } - qemu_cond_timedwait(&cond, &mutex, 1000); + if (ictx.ret) { + error_report("vm_planes: init plane %" PRIu64 " vcpu %u " + "failed", plane_id, i); + run->hypercall.ret =3D ictx.ret; + return 0; } - qemu_mutex_unlock(&mutex); } +#undef PLANE_HOST =20 - /* Note: threads keep running for the plane's lifetime; we - * intentionally leak ctxs/threads =E2=80=94 they outlive this cal= l. */ - - /* Seal plane memory via KVM_SET_MEMORY_ATTRIBUTES(NO_WRITE|NO_EXE= C) */ - { - struct kvm_memory_attributes ma =3D { - .address =3D ps->load_offset, - .size =3D ps->memory_size, - .attributes =3D KVM_MEMORY_ATTRIBUTE_NO_WRITE | - KVM_MEMORY_ATTRIBUTE_NO_EXEC, - .flags =3D 0, - }; - int pr =3D kvm_vm_ioctl(s, KVM_SET_MEMORY_ATTRIBUTES, &ma); - if (pr < 0) { - warn_report("vm_planes: plane %" PRIu64 " seal failed (%d)= ", - plane_id, pr); - } else { - info_report("vm_planes: plane %" PRIu64 " memory sealed", - plane_id); - } - } + /* + * Full Option B: do NOT run the secure plane from a dedicated + * userspace thread. The plane's vCPU has been initialized (entry + * point, page tables, MP state) but is left STOPPED. It boots + * lazily and in-kernel the first time the normal plane issues a + * VBS/VTL call: KVM switches to the secure plane within the normal + * plane's KVM_RUN, the secure kernel boots to its dispatch loop a= nd + * parks itself via KVM_HC_VBS_VTL_RETURN. This removes the racy + * per-plane thread that concurrently drove the shared vcpu->run + * page and caused host lockups. + * + * NB: the secure plane's own memory is intentionally NOT sealed + * here. Because memory attributes are currently applied to every + * plane's EPT alike, sealing the secure plane's region NO_EXEC + * would prevent the secure kernel from executing its own dispatch + * loop. Protecting the secure plane's memory from the normal pla= ne + * requires plane-aware EPT attributes and is left as a follow-up. + */ ps->host_addr =3D NULL; =20 info_report("vm_planes: plane %" PRIu64 " launched =E2=80=94 entry= 0x%" PRIx64 @@ -7188,107 +7060,13 @@ static int kvm_handle_hc_vm_planes_activate(X86CPU= *cpu, struct kvm_run *run) return 0; } =20 -static int vbs_apply_protection(KVMState *s, uint64_t gpa, uint64_t size, - uint32_t perms) -{ - uint64_t attrs =3D 0; - struct kvm_memory_attributes ma; - - if (!(perms & 2)) { - attrs |=3D KVM_MEMORY_ATTRIBUTE_NO_WRITE; - } - if (!(perms & 4)) { - attrs |=3D KVM_MEMORY_ATTRIBUTE_NO_EXEC; - } - if (!attrs) { - return 0; - } - - ma.address =3D gpa; - ma.size =3D size; - ma.attributes =3D attrs; - ma.flags =3D 0; - return kvm_vm_ioctl(s, KVM_SET_MEMORY_ATTRIBUTES, &ma); -} - -static int32_t vbs_handle_protect_memory(KVMState *s, uint64_t ca_gpa) -{ - uint64_t gpa, size; - uint32_t perms, arg_size; - - cpu_physical_memory_read(ca_gpa + CA_OFF_ARG_SIZE, &arg_size, 4); - if (arg_size < 24) { - return -22; - } - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 0, &gpa, 8); - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 8, &size, 8); - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 16, &perms, 4); - return vbs_apply_protection(s, gpa, size, perms); -} - -static int32_t vbs_handle_seal_kernel(KVMState *s, uint64_t ca_gpa) -{ - uint64_t text_gpa, text_size, rodata_gpa, rodata_size; - uint32_t arg_size; - int ret; - - cpu_physical_memory_read(ca_gpa + CA_OFF_ARG_SIZE, &arg_size, 4); - if (arg_size < 40) { - return -22; - } - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 0, &text_gpa, 8); - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 8, &text_size, 8); - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 16, &rodata_gpa, 8); - cpu_physical_memory_read(ca_gpa + CA_OFF_BUFFER + 24, &rodata_size, 8); - - ret =3D vbs_apply_protection(s, text_gpa, text_size, 1 | 4); - if (ret < 0) { - return ret; - } - return vbs_apply_protection(s, rodata_gpa, rodata_size, 1); -} - -static int kvm_handle_hc_vbs_vtl_call(X86CPU *cpu, struct kvm_run *run) -{ - uint64_t ca_gpa =3D run->hypercall.args[0]; - uint32_t call_id; - int32_t status; - KVMState *s =3D kvm_state; - - cpu_physical_memory_read(ca_gpa + CA_OFF_CALL_ID, &call_id, 4); - - switch (call_id) { - case VBS_CALL_INIT: - case VBS_CALL_SHUTDOWN: - status =3D 0; - break; - case VBS_CALL_PROTECT_MEMORY: - status =3D vbs_handle_protect_memory(s, ca_gpa); - break; - case VBS_CALL_SEAL_KERNEL: - status =3D vbs_handle_seal_kernel(s, ca_gpa); - break; - case VBS_CALL_VALIDATE_MODULE: - case VBS_CALL_SET_MODULE_PERMS: - case VBS_CALL_UNLOAD_MODULE: - case VBS_CALL_ADD_KEY: - case VBS_CALL_REVOKE_KEY: - case VBS_CALL_SEND_CERTS: - case VBS_CALL_KEXEC_VALIDATE: - case VBS_CALL_KEXEC_INVALIDATE: - status =3D 0; /* acknowledge */ - break; - default: - warn_report("vbs_vtl_call: unknown call_id 0x%04x", call_id); - status =3D -38; - break; - } - - cpu_physical_memory_write(ca_gpa + CA_OFF_STATUS, &status, 4); - run->hypercall.ret =3D 0; - return 0; -} - +/* + * Full Option B: VBS/VTL calls (KVM_HC_VBS_VTL_CALL / _RETURN) are now + * serviced entirely in-kernel by switching to the secure plane, which runs + * a real in-guest dispatcher. QEMU no longer emulates the secure world, = so + * those hypercalls never exit to userspace here. Only the plane + * configuration/activation hypercalls are handled by QEMU. + */ static int kvm_handle_hypercall(X86CPU *cpu, struct kvm_run *run) { if (run->hypercall.nr =3D=3D KVM_HC_MAP_GPA_RANGE) @@ -7297,8 +7075,6 @@ static int kvm_handle_hypercall(X86CPU *cpu, struct k= vm_run *run) return kvm_handle_hc_vm_planes_config(cpu, run); if (run->hypercall.nr =3D=3D KVM_HC_VM_PLANES_ACTIVATE) return kvm_handle_hc_vm_planes_activate(cpu, run); - if (run->hypercall.nr =3D=3D KVM_HC_VBS_VTL_CALL) - return kvm_handle_hc_vbs_vtl_call(cpu, run); =20 return -EINVAL; } --=20 2.55.0 From nobody Wed Aug 26 12:56:54 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785927910; cv=none; d=zohomail.com; s=zohoarc; b=TJOKlYnqCLOq5b+iTmLShPsBgooLdhXgdhCDY+ePN3BVZpXMKoTGmDPU0v7PsCCAmQUroAQa3HI2pzFxqtRNmBSfh+EGx72lpF7boy+rRlm5COxjMI9wCjB+/pkwgygGO8AJz5mBPVByiwC3Fgbe8nlwSOnEn9W7dYLTAy/5lKk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785927910; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=2Lr3z941HXJaQ18Cjd5S16Yzqdy/e1fawMbuefz9a3E=; b=Eiap4tT9Cz3zPHL7ahpMISihcRN/iTou/j12iZGGRE3zsOjbENjWre0qbifJvxICq5EHQW1Sd8cDfb2skm+L6ryjEdCB7ZdAkQS3V82WRazkgwFMMBNl40YcGpZuZpAqHGNIkwTUYu2gUBeeGemzztYsE3NO8WEccyCq6Dbp2ms= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785927910920205.89244013647033; Wed, 5 Aug 2026 04:05:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQS-0000mq-Qf; Wed, 05 Aug 2026 07:04:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wrZQP-0000kt-VT for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:41 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wrZQO-0000Da-01 for qemu-devel@nongnu.org; Wed, 05 Aug 2026 07:04:41 -0400 Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id 0C6B920B7169; Wed, 5 Aug 2026 04:04:18 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0C6B920B7169 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927858; bh=2Lr3z941HXJaQ18Cjd5S16Yzqdy/e1fawMbuefz9a3E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=P2C64b5oh8gvtnqw/fn3FIlU9TIcefbqXyc3HB47Dqukunlt6YGQnN9tze9G4q+tT 8ehEW1bT18v13xqQNwdUi9VWwMJs2Mm6m858EgfEoRbMlW9GS237DV/FTKVGJU/1vR rVe6gUUAhvVZfzIUSwWDYNQnWyjIHpVPeBUSMiD0= From: Sriram Nambakam To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org Subject: [RFC PATCH v1 5/5] target/i386/kvm: read plane config via address_space API Date: Wed, 5 Aug 2026 04:04:32 -0700 Message-ID: <20260805110432.25167-6-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110432.25167-1-snambakam@linux.microsoft.com> References: <20260805110432.25167-1-snambakam@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=snambakam@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785927912234158500 Content-Type: text/plain; charset="utf-8" Match the vm-planes-merged integration result: read the guest vm_plane_config/calling-area through address_space_read() (with the address-spaces/memory/thread includes) instead of the cpu_physical_memory_read() helpers, and pick up the kvm_para.h whitespace from the header re-sync. This delta originated in the integration branch's merge-commit conflict resolution. --- include/standard-headers/linux/kvm_para.h | 2 +- target/i386/kvm/kvm.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/standard-headers/linux/kvm_para.h b/include/standard-h= eaders/linux/kvm_para.h index def451c43c..3094d70c8d 100644 --- a/include/standard-headers/linux/kvm_para.h +++ b/include/standard-headers/linux/kvm_para.h @@ -27,7 +27,7 @@ #define KVM_HC_MIPS_EXIT_VM 7 #define KVM_HC_MIPS_CONSOLE_OUTPUT 8 #define KVM_HC_CLOCK_PAIRING 9 -#define KVM_HC_SEND_IPI 10 +#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 diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 5ac7962e61..b8a68a1c56 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -21,6 +21,7 @@ #include #include #include +#include =20 #include #include @@ -36,6 +37,8 @@ #include "system/kvm_int.h" #include "system/runstate.h" #include "system/ramblock.h" +#include "system/address-spaces.h" +#include "system/memory.h" #include "kvm_i386.h" #include "../confidential-guest.h" #include "sev.h" @@ -47,6 +50,7 @@ #include "gdbstub/enums.h" #include "qemu/host-utils.h" #include "qemu/main-loop.h" +#include "qemu/thread.h" #include "qemu/ratelimit.h" #include "qemu/config-file.h" #include "qemu/error-report.h" @@ -6665,9 +6669,12 @@ static int kvm_handle_hc_vm_planes_config(X86CPU *cp= u, struct kvm_run *run) int plane_fd; unsigned int i; =20 - cpu_physical_memory_read(plane_gpa + 0, &load_offset, 8); - cpu_physical_memory_read(plane_gpa + 8, &memory_size, 8); - cpu_physical_memory_read(plane_gpa + 16, &entry_point, 8); + address_space_read(&address_space_memory, plane_gpa + 0, + MEMTXATTRS_UNSPECIFIED, &load_offset, 8); + address_space_read(&address_space_memory, plane_gpa + 8, + MEMTXATTRS_UNSPECIFIED, &memory_size, 8); + address_space_read(&address_space_memory, plane_gpa + 16, + MEMTXATTRS_UNSPECIFIED, &entry_point, 8); =20 /* * joergroedel plane model: a plane has exactly one vCPU per @@ -6685,8 +6692,9 @@ static int kvm_handle_hc_vm_planes_config(X86CPU *cpu= , struct kvm_run *run) } =20 memset(cmdline_buf, 0, sizeof(cmdline_buf)); - cpu_physical_memory_read(plane_gpa + 156, cmdline_buf, - sizeof(cmdline_buf)); + address_space_read(&address_space_memory, plane_gpa + 156, + MEMTXATTRS_UNSPECIFIED, cmdline_buf, + sizeof(cmdline_buf)); cmdline_buf[sizeof(cmdline_buf) - 1] =3D '\0'; memcpy(ps->cmdline, cmdline_buf, sizeof(ps->cmdline)); =20 @@ -6899,8 +6907,9 @@ static int kvm_handle_hc_vm_planes_activate(X86CPU *c= pu, struct kvm_run *run) return 0; } =20 - cpu_physical_memory_read(gpa + (plane_id * VM_PLANE_CFG_STRIDE) + = 16, - &entry_point, 8); + address_space_read(&address_space_memory, + gpa + (plane_id * VM_PLANE_CFG_STRIDE) + 16, + MEMTXATTRS_UNSPECIFIED, &entry_point, 8); if (!entry_point) { error_report("vm_planes: plane %" PRIu64 " bad entry_point", plane_id); --=20 2.55.0