184 lines
5.0 KiB
Diff
184 lines
5.0 KiB
Diff
From 140f8cbaa8665f281fe3e47c81cfd0c306f02d8b Mon Sep 17 00:00:00 2001
|
|
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
|
|
Date: Tue, 16 Sep 2025 18:48:37 +0200
|
|
Subject: [PATCH 20/32] target/i386/mshv: Set local interrupt controller state
|
|
|
|
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
|
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
|
|
RH-Jira: RHEL-134212
|
|
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
RH-Commit: [18/30] ded044d2fd9c55a149d7e71d952c10ed6ea29505
|
|
|
|
To set the local interrupt controller state, perform hv calls retrieving
|
|
partition state from the hypervisor.
|
|
|
|
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
|
|
Link: https://lore.kernel.org/r/20250916164847.77883-18-magnuskulke@linux.microsoft.com
|
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
(cherry picked from commit ca20d46fa94887a6e42061646a71ee44cbc9adb0)
|
|
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
|
---
|
|
target/i386/mshv/mshv-cpu.c | 117 ++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 117 insertions(+)
|
|
|
|
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
|
|
index 8b10c79e54..0fe3cbb48d 100644
|
|
--- a/target/i386/mshv/mshv-cpu.c
|
|
+++ b/target/i386/mshv/mshv-cpu.c
|
|
@@ -12,6 +12,7 @@
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/error-report.h"
|
|
+#include "qemu/memalign.h"
|
|
#include "qemu/typedefs.h"
|
|
|
|
#include "system/mshv.h"
|
|
@@ -21,6 +22,7 @@
|
|
#include "hw/hyperv/hvgdk.h"
|
|
#include "hw/hyperv/hvgdk_mini.h"
|
|
#include "hw/hyperv/hvhdk_mini.h"
|
|
+#include "hw/i386/apic_internal.h"
|
|
|
|
#include "cpu.h"
|
|
#include "emulate/x86_decode.h"
|
|
@@ -562,6 +564,114 @@ static int set_cpu_state(const CPUState *cpu, const MshvFPU *fpu_regs,
|
|
return 0;
|
|
}
|
|
|
|
+static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, state);
|
|
+ if (ret < 0) {
|
|
+ error_report("failed to get partition state: %s", strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_lapic(int cpu_fd,
|
|
+ struct hv_local_interrupt_controller_state *state)
|
|
+{
|
|
+ int ret;
|
|
+ size_t size = 4096;
|
|
+ /* buffer aligned to 4k, as *state requires that */
|
|
+ void *buffer = qemu_memalign(size, size);
|
|
+ struct mshv_get_set_vp_state mshv_state = { 0 };
|
|
+
|
|
+ mshv_state.buf_ptr = (uint64_t) buffer;
|
|
+ mshv_state.buf_sz = size;
|
|
+ mshv_state.type = MSHV_VP_STATE_LAPIC;
|
|
+
|
|
+ ret = get_vp_state(cpu_fd, &mshv_state);
|
|
+ if (ret == 0) {
|
|
+ memcpy(state, buffer, sizeof(*state));
|
|
+ }
|
|
+ qemu_vfree(buffer);
|
|
+ if (ret < 0) {
|
|
+ error_report("failed to get lapic");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static uint32_t set_apic_delivery_mode(uint32_t reg, uint32_t mode)
|
|
+{
|
|
+ return ((reg) & ~0x700) | ((mode) << 8);
|
|
+}
|
|
+
|
|
+static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, state);
|
|
+ if (ret < 0) {
|
|
+ error_report("failed to set partition state: %s", strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int set_lapic(int cpu_fd,
|
|
+ const struct hv_local_interrupt_controller_state *state)
|
|
+{
|
|
+ int ret;
|
|
+ size_t size = 4096;
|
|
+ /* buffer aligned to 4k, as *state requires that */
|
|
+ void *buffer = qemu_memalign(size, size);
|
|
+ struct mshv_get_set_vp_state mshv_state = { 0 };
|
|
+
|
|
+ if (!state) {
|
|
+ error_report("lapic state is NULL");
|
|
+ return -1;
|
|
+ }
|
|
+ memcpy(buffer, state, sizeof(*state));
|
|
+
|
|
+ mshv_state.buf_ptr = (uint64_t) buffer;
|
|
+ mshv_state.buf_sz = size;
|
|
+ mshv_state.type = MSHV_VP_STATE_LAPIC;
|
|
+
|
|
+ ret = set_vp_state(cpu_fd, &mshv_state);
|
|
+ qemu_vfree(buffer);
|
|
+ if (ret < 0) {
|
|
+ error_report("failed to set lapic: %s", strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int set_lint(int cpu_fd)
|
|
+{
|
|
+ int ret;
|
|
+ uint32_t *lvt_lint0, *lvt_lint1;
|
|
+
|
|
+ struct hv_local_interrupt_controller_state lapic_state = { 0 };
|
|
+ ret = get_lapic(cpu_fd, &lapic_state);
|
|
+ if (ret < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ lvt_lint0 = &lapic_state.apic_lvt_lint0;
|
|
+ *lvt_lint0 = set_apic_delivery_mode(*lvt_lint0, APIC_DM_EXTINT);
|
|
+
|
|
+ lvt_lint1 = &lapic_state.apic_lvt_lint1;
|
|
+ *lvt_lint1 = set_apic_delivery_mode(*lvt_lint1, APIC_DM_NMI);
|
|
+
|
|
+ /* TODO: should we skip setting lapic if the values are the same? */
|
|
+
|
|
+ return set_lapic(cpu_fd, &lapic_state);
|
|
+}
|
|
+
|
|
/*
|
|
* TODO: populate topology info:
|
|
*
|
|
@@ -573,6 +683,7 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
|
|
uint64_t xcr0)
|
|
{
|
|
int ret;
|
|
+ int cpu_fd = mshv_vcpufd(cpu);
|
|
|
|
ret = set_cpu_state(cpu, fpu, xcr0);
|
|
if (ret < 0) {
|
|
@@ -580,6 +691,12 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
|
|
return -1;
|
|
}
|
|
|
|
+ ret = set_lint(cpu_fd);
|
|
+ if (ret < 0) {
|
|
+ error_report("failed to set lpic int");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
--
|
|
2.47.3
|
|
|