Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2224394/?format=api
{ "id": 2224394, "url": "http://patchwork.ozlabs.org/api/patches/2224394/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260417105618.3621-21-magnuskulke@linux.microsoft.com/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260417105618.3621-21-magnuskulke@linux.microsoft.com>", "list_archive_url": null, "date": "2026-04-17T10:56:04", "name": "[20/34] target/i386/mshv: migrate MSRs", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "77eb5bdfa0bc80efe5a84ebd13a3f8e1473f2736", "submitter": { "id": 90753, "url": "http://patchwork.ozlabs.org/api/people/90753/?format=api", "name": "Magnus Kulke", "email": "magnuskulke@linux.microsoft.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260417105618.3621-21-magnuskulke@linux.microsoft.com/mbox/", "series": [ { "id": 500310, "url": "http://patchwork.ozlabs.org/api/series/500310/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=500310", "date": "2026-04-17T10:55:44", "name": "Add migration support to the MSHV accelerator", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500310/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224394/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224394/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=linux.microsoft.com header.i=@linux.microsoft.com\n header.a=rsa-sha256 header.s=default header.b=Dw7JnsBb;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)" ], "Received": [ "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fxsLn5dc3z1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 17 Apr 2026 20:58:41 +1000 (AEST)", "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wDgtg-0002ld-Qh; Fri, 17 Apr 2026 06:58:05 -0400", "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <magnuskulke@linux.microsoft.com>)\n id 1wDgtV-0002di-O4\n for qemu-devel@nongnu.org; Fri, 17 Apr 2026 06:57:55 -0400", "from linux.microsoft.com ([13.77.154.182])\n by eggs.gnu.org with esmtp (Exim 4.90_1)\n (envelope-from <magnuskulke@linux.microsoft.com>) id 1wDgtR-0001d0-ET\n for qemu-devel@nongnu.org; Fri, 17 Apr 2026 06:57:52 -0400", "from DESKTOP-TUU1E5L.fritz.box (p5086d620.dip0.t-ipconnect.de\n [80.134.214.32])\n by linux.microsoft.com (Postfix) with ESMTPSA id 753C520B7136;\n Fri, 17 Apr 2026 03:57:34 -0700 (PDT)" ], "DKIM-Filter": "OpenDKIM Filter v2.11.0 linux.microsoft.com 753C520B7136", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com;\n s=default; t=1776423457;\n bh=K2f0mDhH3YaMavu+Y6z/Fkk1B9ptr1dYqpJLusfrqVo=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n b=Dw7JnsBbpZe1QF5fGrh9B5S1JR4IjJah9aUFxZdM+XtlqbWmHbMdXxY91jEbwoG0h\n j2Vut3rG1O5KhzEUAS2Nl2EbrUvsGwxTrZqH765j2dHqQt/6sZJSS6uU4U+HuQ6E3P\n gLeEucpBdU1Xnm7JfzNYn3S7ltw5854m/MHq6Pr8=", "From": "Magnus Kulke <magnuskulke@linux.microsoft.com>", "To": "qemu-devel@nongnu.org", "Cc": "kvm@vger.kernel.org, Magnus Kulke <magnuskulke@microsoft.com>,\n Wei Liu <liuwe@microsoft.com>, \"Michael S. Tsirkin\" <mst@redhat.com>,\n\t=?utf-8?q?C=C3=A9dric_Le_Goater?= <clg@redhat.com>,\n Zhao Liu <zhao1.liu@intel.com>,\n Richard Henderson <richard.henderson@linaro.org>,\n Paolo Bonzini <pbonzini@redhat.com>, Wei Liu <wei.liu@kernel.org>,\n Magnus Kulke <magnuskulke@linux.microsoft.com>,\n Alex Williamson <alex@shazbot.org>,\n Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, =?utf-8?q?Philippe_Mathieu-D?=\n\t=?utf-8?q?aud=C3=A9?= <philmd@linaro.org>,\n Marcelo Tosatti <mtosatti@redhat.com>", "Subject": "[PATCH 20/34] target/i386/mshv: migrate MSRs", "Date": "Fri, 17 Apr 2026 12:56:04 +0200", "Message-Id": "<20260417105618.3621-21-magnuskulke@linux.microsoft.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20260417105618.3621-1-magnuskulke@linux.microsoft.com>", "References": "<20260417105618.3621-1-magnuskulke@linux.microsoft.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=13.77.154.182;\n envelope-from=magnuskulke@linux.microsoft.com; helo=linux.microsoft.com", "X-Spam_score_int": "-42", "X-Spam_score": "-4.3", "X-Spam_bar": "----", "X-Spam_report": "(-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_MED=-2.3,\n RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001,\n 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 <qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org" }, "content": "In this change the we rewrite the existing MSR logic to make MSRs\nmigratable:\n\n- we map them on existing QEMU fields in the CPU. A table and a macro\n MSHV_ENV_FIELD is used to associate a HV register name to the their msr\n index and their offset in the cpu state struct. The list is not\n exhaustive and will be extended in follow-up commits.\n- mshv_set/get_msrs() fns are called in the arch_load/store_vcpu_state()\n fns. they use use generic registers ioctl's and map the input/output\n via load/store_to/from_env() from/to the hv register content to the\n cpu state representation.\n- init_msrs() has been moved from mshv-vcpu to the msr source file\n- we need to perform some filtering of MSR because before writing and\n reading, because the hvcalls will fail if the partition doesn't\n support a given MSRs.\n- Some MSRs are partition-wide and so we will only write the to on the\n BSP.\n\nSigned-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>\n---\n include/hw/hyperv/hvgdk_mini.h | 16 +\n include/system/mshv_int.h | 17 +-\n target/i386/mshv/mshv-cpu.c | 40 +--\n target/i386/mshv/msr.c | 554 ++++++++++++++-------------------\n 4 files changed, 259 insertions(+), 368 deletions(-)", "diff": "diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h\nindex c3a8f33280..4d1e062e48 100644\n--- a/include/hw/hyperv/hvgdk_mini.h\n+++ b/include/hw/hyperv/hvgdk_mini.h\n@@ -9,6 +9,19 @@\n \n #define MSHV_IOCTL 0xB8\n \n+/* Hyper-V specific model specific registers (MSRs) */\n+\n+/* HV_X64_SYNTHETIC_MSR */\n+#define HV_X64_MSR_GUEST_OS_ID 0x40000000\n+#define HV_X64_MSR_HYPERCALL 0x40000001\n+#define HV_X64_MSR_VP_INDEX 0x40000002\n+#define HV_X64_MSR_RESET 0x40000003\n+#define HV_X64_MSR_VP_RUNTIME 0x40000010\n+#define HV_X64_MSR_TIME_REF_COUNT 0x40000020\n+#define HV_X64_MSR_REFERENCE_TSC 0x40000021\n+#define HV_X64_MSR_TSC_FREQUENCY 0x40000022\n+#define HV_X64_MSR_APIC_FREQUENCY 0x40000023\n+\n typedef enum hv_register_name {\n /* Pending Interruption Register */\n HV_REGISTER_PENDING_INTERRUPTION = 0x00010002,\n@@ -152,12 +165,14 @@ typedef enum hv_register_name {\n /* Available */\n \n HV_X64_REGISTER_SPEC_CTRL = 0x00080084,\n+ HV_X64_REGISTER_TSC_DEADLINE = 0x00080095,\n HV_X64_REGISTER_TSC_ADJUST = 0x00080096,\n \n /* Other MSRs */\n HV_X64_REGISTER_MSR_IA32_MISC_ENABLE = 0x000800A0,\n \n /* Misc */\n+ HV_X64_REGISTER_HYPERCALL = 0x00090001,\n HV_REGISTER_GUEST_OS_ID = 0x00090002,\n HV_REGISTER_REFERENCE_TSC = 0x00090017,\n \n@@ -797,6 +812,7 @@ struct hv_cpuid {\n #define IA32_MSR_DEBUG_CTL 0x1D9\n #define IA32_MSR_SPEC_CTRL 0x00000048\n #define IA32_MSR_TSC_ADJUST 0x0000003b\n+#define IA32_MSR_TSC_DEADLINE 0x000006e0\n \n #define IA32_MSR_MISC_ENABLE 0x000001a0\n \ndiff --git a/include/system/mshv_int.h b/include/system/mshv_int.h\nindex 2c5d16bf9a..29b363e73e 100644\n--- a/include/system/mshv_int.h\n+++ b/include/system/mshv_int.h\n@@ -14,7 +14,6 @@\n #ifndef QEMU_MSHV_INT_H\n #define QEMU_MSHV_INT_H\n \n-#define MSHV_MSR_ENTRIES_COUNT 64\n #include \"hw/hyperv/hvhdk.h\"\n \n struct mshv_get_set_vp_state;\n@@ -116,18 +115,8 @@ void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,\n bool add);\n \n /* msr */\n-typedef struct MshvMsrEntry {\n- uint32_t index;\n- uint32_t reserved;\n- uint64_t data;\n-} MshvMsrEntry;\n-\n-typedef struct MshvMsrEntries {\n- MshvMsrEntry entries[MSHV_MSR_ENTRIES_COUNT];\n- uint32_t nmsrs;\n-} MshvMsrEntries;\n-\n-int mshv_configure_msr(const CPUState *cpu, const MshvMsrEntry *msrs,\n- size_t n_msrs);\n+int mshv_init_msrs(const CPUState *cpu);\n+int mshv_get_msrs(CPUState *cpu);\n+int mshv_set_msrs(const CPUState *cpu);\n \n #endif\ndiff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c\nindex 2d1f90637e..760fcfe8da 100644\n--- a/target/i386/mshv/mshv-cpu.c\n+++ b/target/i386/mshv/mshv-cpu.c\n@@ -580,6 +580,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu)\n return ret;\n }\n \n+ ret = mshv_get_msrs(cpu);\n+ if (ret < 0) {\n+ return ret;\n+ }\n+\n return 0;\n }\n \n@@ -1025,6 +1030,12 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu)\n return ret;\n }\n \n+ /* INVARIANT: LAPIC must be restored before MSRs (TSC_DEADLINE) */\n+ ret = mshv_set_msrs(cpu);\n+ if (ret < 0) {\n+ return ret;\n+ }\n+\n return 0;\n }\n \n@@ -1511,33 +1522,6 @@ void mshv_init_mmio_emu(void)\n init_emu(&mshv_x86_emul_ops);\n }\n \n-static int init_msrs(const CPUState *cpu)\n-{\n- int ret;\n- uint64_t d_t = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;\n-\n- const struct hv_register_assoc assocs[] = {\n- { .name = HV_X64_REGISTER_SYSENTER_CS, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_SYSENTER_ESP, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_SYSENTER_EIP, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_STAR, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_CSTAR, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_LSTAR, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_KERNEL_GS_BASE, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_SFMASK, .value.reg64 = 0x0 },\n- { .name = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, .value.reg64 = d_t },\n- };\n- QEMU_BUILD_BUG_ON(ARRAY_SIZE(assocs) > MSHV_MSR_ENTRIES_COUNT);\n-\n- ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));\n- if (ret < 0) {\n- error_report(\"failed to put msrs\");\n- return -1;\n- }\n-\n- return 0;\n-}\n-\n void mshv_arch_init_vcpu(CPUState *cpu)\n {\n X86CPU *x86_cpu = X86_CPU(cpu);\n@@ -1567,7 +1551,7 @@ void mshv_arch_init_vcpu(CPUState *cpu)\n ret = init_cpuid2(cpu);\n assert(ret == 0);\n \n- ret = init_msrs(cpu);\n+ ret = mshv_init_msrs(cpu);\n assert(ret == 0);\n \n ret = init_lint(cpu);\ndiff --git a/target/i386/mshv/msr.c b/target/i386/mshv/msr.c\nindex e6e5baef50..0ecd864458 100644\n--- a/target/i386/mshv/msr.c\n+++ b/target/i386/mshv/msr.c\n@@ -14,362 +14,264 @@\n #include \"hw/hyperv/hvgdk_mini.h\"\n #include \"linux/mshv.h\"\n #include \"qemu/error-report.h\"\n+#include \"cpu.h\"\n \n-static uint32_t supported_msrs[64] = {\n- IA32_MSR_TSC,\n- IA32_MSR_EFER,\n- IA32_MSR_KERNEL_GS_BASE,\n- IA32_MSR_APIC_BASE,\n- IA32_MSR_PAT,\n- IA32_MSR_SYSENTER_CS,\n- IA32_MSR_SYSENTER_ESP,\n- IA32_MSR_SYSENTER_EIP,\n- IA32_MSR_STAR,\n- IA32_MSR_LSTAR,\n- IA32_MSR_CSTAR,\n- IA32_MSR_SFMASK,\n- IA32_MSR_MTRR_DEF_TYPE,\n- IA32_MSR_MTRR_PHYSBASE0,\n- IA32_MSR_MTRR_PHYSMASK0,\n- IA32_MSR_MTRR_PHYSBASE1,\n- IA32_MSR_MTRR_PHYSMASK1,\n- IA32_MSR_MTRR_PHYSBASE2,\n- IA32_MSR_MTRR_PHYSMASK2,\n- IA32_MSR_MTRR_PHYSBASE3,\n- IA32_MSR_MTRR_PHYSMASK3,\n- IA32_MSR_MTRR_PHYSBASE4,\n- IA32_MSR_MTRR_PHYSMASK4,\n- IA32_MSR_MTRR_PHYSBASE5,\n- IA32_MSR_MTRR_PHYSMASK5,\n- IA32_MSR_MTRR_PHYSBASE6,\n- IA32_MSR_MTRR_PHYSMASK6,\n- IA32_MSR_MTRR_PHYSBASE7,\n- IA32_MSR_MTRR_PHYSMASK7,\n- IA32_MSR_MTRR_FIX64K_00000,\n- IA32_MSR_MTRR_FIX16K_80000,\n- IA32_MSR_MTRR_FIX16K_A0000,\n- IA32_MSR_MTRR_FIX4K_C0000,\n- IA32_MSR_MTRR_FIX4K_C8000,\n- IA32_MSR_MTRR_FIX4K_D0000,\n- IA32_MSR_MTRR_FIX4K_D8000,\n- IA32_MSR_MTRR_FIX4K_E0000,\n- IA32_MSR_MTRR_FIX4K_E8000,\n- IA32_MSR_MTRR_FIX4K_F0000,\n- IA32_MSR_MTRR_FIX4K_F8000,\n- IA32_MSR_TSC_AUX,\n- IA32_MSR_DEBUG_CTL,\n- HV_X64_MSR_GUEST_OS_ID,\n- HV_X64_MSR_SINT0,\n- HV_X64_MSR_SINT1,\n- HV_X64_MSR_SINT2,\n- HV_X64_MSR_SINT3,\n- HV_X64_MSR_SINT4,\n- HV_X64_MSR_SINT5,\n- HV_X64_MSR_SINT6,\n- HV_X64_MSR_SINT7,\n- HV_X64_MSR_SINT8,\n- HV_X64_MSR_SINT9,\n- HV_X64_MSR_SINT10,\n- HV_X64_MSR_SINT11,\n- HV_X64_MSR_SINT12,\n- HV_X64_MSR_SINT13,\n- HV_X64_MSR_SINT14,\n- HV_X64_MSR_SINT15,\n- HV_X64_MSR_SCONTROL,\n- HV_X64_MSR_SIEFP,\n- HV_X64_MSR_SIMP,\n- HV_X64_MSR_REFERENCE_TSC,\n- HV_X64_MSR_EOM,\n+#define MSHV_ENV_FIELD(env, offset) (*(uint64_t *)((char *)(env) + (offset)))\n+\n+typedef struct MshvMsrEnvMap {\n+ uint32_t msr_index;\n+ uint32_t hv_name;\n+ ptrdiff_t env_offset;\n+} MshvMsrEnvMap;\n+\n+/* We assert that 64bit access to sysenter_cs is safe because of padding */\n+QEMU_BUILD_BUG_ON(offsetof(CPUX86State, sysenter_esp) -\n+ offsetof(CPUX86State, sysenter_cs)\n+ < sizeof(uint64_t));\n+\n+/* Those MSRs have a direct mapping to fields in CPUX86State */\n+static const MshvMsrEnvMap msr_env_map[] = {\n+ /* Architectural */\n+ { IA32_MSR_EFER, HV_X64_REGISTER_EFER, offsetof(CPUX86State, efer) },\n+ { IA32_MSR_PAT, HV_X64_REGISTER_PAT, offsetof(CPUX86State, pat) },\n+\n+ /* Syscall */\n+ { IA32_MSR_SYSENTER_CS, HV_X64_REGISTER_SYSENTER_CS,\n+ offsetof(CPUX86State, sysenter_cs) },\n+ { IA32_MSR_SYSENTER_ESP, HV_X64_REGISTER_SYSENTER_ESP,\n+ offsetof(CPUX86State, sysenter_esp) },\n+ { IA32_MSR_SYSENTER_EIP, HV_X64_REGISTER_SYSENTER_EIP,\n+ offsetof(CPUX86State, sysenter_eip) },\n+ { IA32_MSR_STAR, HV_X64_REGISTER_STAR,\n+ offsetof(CPUX86State, star) },\n+ { IA32_MSR_LSTAR, HV_X64_REGISTER_LSTAR,\n+ offsetof(CPUX86State, lstar) },\n+ { IA32_MSR_CSTAR, HV_X64_REGISTER_CSTAR,\n+ offsetof(CPUX86State, cstar) },\n+ { IA32_MSR_SFMASK, HV_X64_REGISTER_SFMASK,\n+ offsetof(CPUX86State, fmask) },\n+ { IA32_MSR_KERNEL_GS_BASE, HV_X64_REGISTER_KERNEL_GS_BASE,\n+ offsetof(CPUX86State, kernelgsbase) },\n+\n+ /* TSC-related */\n+ { IA32_MSR_TSC, HV_X64_REGISTER_TSC,\n+ offsetof(CPUX86State, tsc) },\n+ { IA32_MSR_TSC_AUX, HV_X64_REGISTER_TSC_AUX,\n+ offsetof(CPUX86State, tsc_aux) },\n+ { IA32_MSR_TSC_ADJUST, HV_X64_REGISTER_TSC_ADJUST,\n+ offsetof(CPUX86State, tsc_adjust) },\n+ { IA32_MSR_TSC_DEADLINE, HV_X64_REGISTER_TSC_DEADLINE,\n+ offsetof(CPUX86State, tsc_deadline) },\n+\n+ /* Hyper-V per-partition MSRs */\n+ { HV_X64_MSR_HYPERCALL, HV_X64_REGISTER_HYPERCALL,\n+ offsetof(CPUX86State, msr_hv_hypercall) },\n+ { HV_X64_MSR_GUEST_OS_ID, HV_REGISTER_GUEST_OS_ID,\n+ offsetof(CPUX86State, msr_hv_guest_os_id) },\n+ { HV_X64_MSR_REFERENCE_TSC, HV_REGISTER_REFERENCE_TSC,\n+ offsetof(CPUX86State, msr_hv_tsc) },\n+\n+ /* Hyper-V MSRs (non-SINT) */\n+ { HV_X64_MSR_SCONTROL, HV_REGISTER_SCONTROL,\n+ offsetof(CPUX86State, msr_hv_synic_control) },\n+ { HV_X64_MSR_SIEFP, HV_REGISTER_SIEFP,\n+ offsetof(CPUX86State, msr_hv_synic_evt_page) },\n+ { HV_X64_MSR_SIMP, HV_REGISTER_SIMP,\n+ offsetof(CPUX86State, msr_hv_synic_msg_page) },\n+\n+ /* Other */\n+\n+ /* TODO: find out processor features that correlate to unsupported MSRs. */\n+ /* { IA32_MSR_MISC_ENABLE, HV_X64_REGISTER_MSR_IA32_MISC_ENABLE, */\n+ /* offsetof(CPUX86State, msr_ia32_misc_enable) }, */\n+ /* { IA32_MSR_BNDCFGS, HV_X64_REGISTER_BNDCFGS, */\n+ /* offsetof(CPUX86State, msr_bndcfgs) }, */\n+ { IA32_MSR_SPEC_CTRL, HV_X64_REGISTER_SPEC_CTRL,\n+ offsetof(CPUX86State, spec_ctrl) },\n };\n-static const size_t msr_count = ARRAY_SIZE(supported_msrs);\n \n-static int compare_msr_index(const void *a, const void *b)\n+int mshv_init_msrs(const CPUState *cpu)\n {\n- return *(uint32_t *)a - *(uint32_t *)b;\n+ int ret;\n+ uint64_t d_t = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;\n+\n+ const struct hv_register_assoc assocs[] = {\n+ { .name = HV_X64_REGISTER_SYSENTER_CS, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_SYSENTER_ESP, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_SYSENTER_EIP, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_STAR, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_CSTAR, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_LSTAR, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_KERNEL_GS_BASE, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_SFMASK, .value.reg64 = 0x0 },\n+ { .name = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, .value.reg64 = d_t },\n+ };\n+\n+ ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));\n+ if (ret < 0) {\n+ error_report(\"failed to put msrs\");\n+ return -1;\n+ }\n+\n+ return 0;\n }\n \n-__attribute__((constructor))\n-static void init_sorted_msr_map(void)\n+\n+/*\n+ * INVARIANT: this fn expects assocs in the same order as they appear in\n+ * msr_env_map.\n+ */\n+static void store_in_env(CPUState *cpu, const struct hv_register_assoc *assocs,\n+ size_t n_assocs)\n {\n- qsort(supported_msrs, msr_count, sizeof(uint32_t), compare_msr_index);\n+ X86CPU *x86_cpu = X86_CPU(cpu);\n+ CPUX86State *env = &x86_cpu->env;\n+ size_t i, j;\n+ const MshvMsrEnvMap *mapping;\n+ union hv_register_value hv_value;\n+ ptrdiff_t offset;\n+ uint32_t hv_name;\n+\n+ assert(n_assocs <= (ARRAY_SIZE(msr_env_map)));\n+\n+ for (i = 0, j = 0; i < ARRAY_SIZE(msr_env_map); i++) {\n+ hv_name = assocs[j].name;\n+ mapping = &msr_env_map[i];\n+ if (hv_name != mapping->hv_name) {\n+ continue;\n+ }\n+\n+ hv_value = assocs[j].value;\n+ offset = mapping->env_offset;\n+ MSHV_ENV_FIELD(env, offset) = hv_value.reg64;\n+ j++;\n+ }\n }\n \n-static int mshv_is_supported_msr(uint32_t msr)\n+static void set_hv_name_in_assocs(struct hv_register_assoc *assocs,\n+ size_t n_assocs)\n {\n- return bsearch(&msr, supported_msrs, msr_count, sizeof(uint32_t),\n- compare_msr_index) != NULL;\n+ size_t i;\n+\n+ assert(n_assocs == ARRAY_SIZE(msr_env_map));\n+ for (i = 0; i < ARRAY_SIZE(msr_env_map); i++) {\n+ assocs[i].name = msr_env_map[i].hv_name;\n+ }\n }\n \n-static int mshv_msr_to_hv_reg_name(uint32_t msr, uint32_t *hv_reg)\n+static bool msr_supported(uint32_t name)\n {\n- switch (msr) {\n- case IA32_MSR_TSC:\n- *hv_reg = HV_X64_REGISTER_TSC;\n- return 0;\n- case IA32_MSR_EFER:\n- *hv_reg = HV_X64_REGISTER_EFER;\n- return 0;\n- case IA32_MSR_KERNEL_GS_BASE:\n- *hv_reg = HV_X64_REGISTER_KERNEL_GS_BASE;\n- return 0;\n- case IA32_MSR_APIC_BASE:\n- *hv_reg = HV_X64_REGISTER_APIC_BASE;\n- return 0;\n- case IA32_MSR_PAT:\n- *hv_reg = HV_X64_REGISTER_PAT;\n- return 0;\n- case IA32_MSR_SYSENTER_CS:\n- *hv_reg = HV_X64_REGISTER_SYSENTER_CS;\n- return 0;\n- case IA32_MSR_SYSENTER_ESP:\n- *hv_reg = HV_X64_REGISTER_SYSENTER_ESP;\n- return 0;\n- case IA32_MSR_SYSENTER_EIP:\n- *hv_reg = HV_X64_REGISTER_SYSENTER_EIP;\n- return 0;\n- case IA32_MSR_STAR:\n- *hv_reg = HV_X64_REGISTER_STAR;\n- return 0;\n- case IA32_MSR_LSTAR:\n- *hv_reg = HV_X64_REGISTER_LSTAR;\n- return 0;\n- case IA32_MSR_CSTAR:\n- *hv_reg = HV_X64_REGISTER_CSTAR;\n- return 0;\n- case IA32_MSR_SFMASK:\n- *hv_reg = HV_X64_REGISTER_SFMASK;\n- return 0;\n- case IA32_MSR_MTRR_CAP:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_CAP;\n- return 0;\n- case IA32_MSR_MTRR_DEF_TYPE:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE0:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK0:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE1:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE1;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK1:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK1;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE2:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE2;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK2:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK2;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE3:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE3;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK3:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK3;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE4:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE4;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK4:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK4;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE5:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE5;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK5:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK5;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE6:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE6;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK6:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK6;\n- return 0;\n- case IA32_MSR_MTRR_PHYSBASE7:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE7;\n- return 0;\n- case IA32_MSR_MTRR_PHYSMASK7:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK7;\n- return 0;\n- case IA32_MSR_MTRR_FIX64K_00000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX64K00000;\n- return 0;\n- case IA32_MSR_MTRR_FIX16K_80000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX16K80000;\n- return 0;\n- case IA32_MSR_MTRR_FIX16K_A0000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX16KA0000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_C0000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KC0000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_C8000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KC8000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_D0000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KD0000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_D8000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KD8000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_E0000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KE0000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_E8000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KE8000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_F0000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KF0000;\n- return 0;\n- case IA32_MSR_MTRR_FIX4K_F8000:\n- *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KF8000;\n- return 0;\n- case IA32_MSR_TSC_AUX:\n- *hv_reg = HV_X64_REGISTER_TSC_AUX;\n- return 0;\n- case IA32_MSR_BNDCFGS:\n- *hv_reg = HV_X64_REGISTER_BNDCFGS;\n- return 0;\n- case IA32_MSR_DEBUG_CTL:\n- *hv_reg = HV_X64_REGISTER_DEBUG_CTL;\n- return 0;\n- case IA32_MSR_TSC_ADJUST:\n- *hv_reg = HV_X64_REGISTER_TSC_ADJUST;\n- return 0;\n- case IA32_MSR_SPEC_CTRL:\n- *hv_reg = HV_X64_REGISTER_SPEC_CTRL;\n- return 0;\n- case HV_X64_MSR_GUEST_OS_ID:\n- *hv_reg = HV_REGISTER_GUEST_OS_ID;\n- return 0;\n- case HV_X64_MSR_SINT0:\n- *hv_reg = HV_REGISTER_SINT0;\n- return 0;\n- case HV_X64_MSR_SINT1:\n- *hv_reg = HV_REGISTER_SINT1;\n- return 0;\n- case HV_X64_MSR_SINT2:\n- *hv_reg = HV_REGISTER_SINT2;\n- return 0;\n- case HV_X64_MSR_SINT3:\n- *hv_reg = HV_REGISTER_SINT3;\n- return 0;\n- case HV_X64_MSR_SINT4:\n- *hv_reg = HV_REGISTER_SINT4;\n- return 0;\n- case HV_X64_MSR_SINT5:\n- *hv_reg = HV_REGISTER_SINT5;\n- return 0;\n- case HV_X64_MSR_SINT6:\n- *hv_reg = HV_REGISTER_SINT6;\n- return 0;\n- case HV_X64_MSR_SINT7:\n- *hv_reg = HV_REGISTER_SINT7;\n- return 0;\n- case HV_X64_MSR_SINT8:\n- *hv_reg = HV_REGISTER_SINT8;\n- return 0;\n- case HV_X64_MSR_SINT9:\n- *hv_reg = HV_REGISTER_SINT9;\n- return 0;\n- case HV_X64_MSR_SINT10:\n- *hv_reg = HV_REGISTER_SINT10;\n- return 0;\n- case HV_X64_MSR_SINT11:\n- *hv_reg = HV_REGISTER_SINT11;\n- return 0;\n- case HV_X64_MSR_SINT12:\n- *hv_reg = HV_REGISTER_SINT12;\n- return 0;\n- case HV_X64_MSR_SINT13:\n- *hv_reg = HV_REGISTER_SINT13;\n- return 0;\n- case HV_X64_MSR_SINT14:\n- *hv_reg = HV_REGISTER_SINT14;\n- return 0;\n- case HV_X64_MSR_SINT15:\n- *hv_reg = HV_REGISTER_SINT15;\n- return 0;\n- case IA32_MSR_MISC_ENABLE:\n- *hv_reg = HV_X64_REGISTER_MSR_IA32_MISC_ENABLE;\n- return 0;\n- case HV_X64_MSR_SCONTROL:\n- *hv_reg = HV_REGISTER_SCONTROL;\n- return 0;\n- case HV_X64_MSR_SIEFP:\n- *hv_reg = HV_REGISTER_SIEFP;\n- return 0;\n- case HV_X64_MSR_SIMP:\n- *hv_reg = HV_REGISTER_SIMP;\n- return 0;\n- case HV_X64_MSR_REFERENCE_TSC:\n- *hv_reg = HV_REGISTER_REFERENCE_TSC;\n- return 0;\n- case HV_X64_MSR_EOM:\n- *hv_reg = HV_REGISTER_EOM;\n- return 0;\n- default:\n- error_report(\"failed to map MSR %u to HV register name\", msr);\n- return -1;\n+ /*\n+ * This check is not done comprehensively, it's meant to avoid hvcall\n+ * failures for certain MSRs on architectures that don't support them.\n+ */\n+\n+ switch (name) {\n+ case HV_X64_REGISTER_SPEC_CTRL:\n+ return mshv_state->processor_features.ibrs_support;\n+ case HV_X64_REGISTER_TSC_ADJUST:\n+ return mshv_state->processor_features.tsc_adjust_support;\n+ case HV_X64_REGISTER_TSC_DEADLINE:\n+ return mshv_state->processor_features.tsc_deadline_tmr_support;\n }\n+\n+ return true;\n }\n \n-static int set_msrs(const CPUState *cpu, GList *msrs)\n+int mshv_get_msrs(CPUState *cpu)\n {\n- size_t n_msrs;\n- GList *entries;\n- MshvMsrEntry *entry;\n- enum hv_register_name name;\n- struct hv_register_assoc *assoc;\n- int ret;\n- size_t i = 0;\n-\n- n_msrs = g_list_length(msrs);\n- hv_register_assoc *assocs = g_new0(hv_register_assoc, n_msrs);\n-\n- entries = msrs;\n- for (const GList *elem = entries; elem != NULL; elem = elem->next) {\n- entry = elem->data;\n- ret = mshv_msr_to_hv_reg_name(entry->index, &name);\n- if (ret < 0) {\n- g_free(assocs);\n- return ret;\n+ int ret = 0;\n+ size_t n_assocs = ARRAY_SIZE(msr_env_map);\n+ struct hv_register_assoc assocs[ARRAY_SIZE(msr_env_map)];\n+ size_t i, j;\n+ uint32_t name;\n+\n+ set_hv_name_in_assocs(assocs, n_assocs);\n+\n+ /* Filter out MSRs that cannot be read */\n+ for (i = 0, j = 0; i < n_assocs; i++) {\n+ name = assocs[i].name;\n+\n+ if (!msr_supported(name)) {\n+ continue;\n }\n- assoc = &assocs[i];\n- assoc->name = name;\n- /* the union has been initialized to 0 */\n- assoc->value.reg64 = entry->data;\n- i++;\n+\n+ if (j != i) {\n+ assocs[j] = assocs[i];\n+ }\n+ j++;\n }\n- ret = mshv_set_generic_regs(cpu, assocs, n_msrs);\n- g_free(assocs);\n+ n_assocs = j;\n+\n+ ret = mshv_get_generic_regs(cpu, assocs, n_assocs);\n if (ret < 0) {\n- error_report(\"failed to set msrs\");\n- return -1;\n+ error_report(\"Failed to get MSRs\");\n+ return -errno;\n }\n+\n+ store_in_env(cpu, assocs, n_assocs);\n+\n return 0;\n }\n \n+static void load_from_env(const CPUState *cpu, struct hv_register_assoc *assocs,\n+ size_t n_assocs)\n+{\n+ size_t i;\n+ const MshvMsrEnvMap *mapping;\n+ X86CPU *x86_cpu = X86_CPU(cpu);\n+ CPUX86State *env = &x86_cpu->env;\n+ ptrdiff_t offset;\n+ union hv_register_value *hv_value;\n+\n+ assert(n_assocs == ARRAY_SIZE(msr_env_map));\n+\n+ for (i = 0; i < ARRAY_SIZE(msr_env_map); i++) {\n+ mapping = &msr_env_map[i];\n+ offset = mapping->env_offset;\n+ assocs[i].name = mapping->hv_name;\n+ hv_value = &assocs[i].value;\n+ hv_value->reg64 = MSHV_ENV_FIELD(env, offset);\n+ }\n+}\n \n-int mshv_configure_msr(const CPUState *cpu, const MshvMsrEntry *msrs,\n- size_t n_msrs)\n+int mshv_set_msrs(const CPUState *cpu)\n {\n- GList *valid_msrs = NULL;\n- uint32_t msr_index;\n+ size_t n_assocs = ARRAY_SIZE(msr_env_map);\n+ struct hv_register_assoc assocs[ARRAY_SIZE(msr_env_map)];\n int ret;\n+ size_t i, j;\n+\n+ load_from_env(cpu, assocs, n_assocs);\n+\n+ /* Filter out MSRs that cannot be written */\n+ for (i = 0, j = 0; i < n_assocs; i++) {\n+ uint32_t name = assocs[i].name;\n \n- for (size_t i = 0; i < n_msrs; i++) {\n- msr_index = msrs[i].index;\n- /* check whether index of msrs is in SUPPORTED_MSRS */\n- if (mshv_is_supported_msr(msr_index)) {\n- valid_msrs = g_list_append(valid_msrs, (void *) &msrs[i]);\n+ /* Partition-wide MSRs: only write on vCPU 0 */\n+ if (cpu->cpu_index != 0 &&\n+ (name == HV_X64_REGISTER_HYPERCALL ||\n+ name == HV_REGISTER_GUEST_OS_ID ||\n+ name == HV_REGISTER_REFERENCE_TSC)) {\n+ continue;\n }\n+\n+ if (!msr_supported(name)) {\n+ continue;\n+ }\n+\n+ if (j != i) {\n+ assocs[j] = assocs[i];\n+ }\n+ j++;\n }\n+ n_assocs = j;\n \n- ret = set_msrs(cpu, valid_msrs);\n- g_list_free(valid_msrs);\n+ ret = mshv_set_generic_regs(cpu, assocs, n_assocs);\n+ if (ret < 0) {\n+ error_report(\"Failed to set MSRs\");\n+ return -errno;\n+ }\n \n- return ret;\n+ return 0;\n }\n", "prefixes": [ "20/34" ] }