get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/2224394/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2224394,
    "url": "http://patchwork.ozlabs.org/api/1.2/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/1.2/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/1.2/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/1.2/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"
    ]
}