[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 33/37] i386: kvm: Add support for MSR filtering
From: |
Paolo Bonzini |
Subject: |
[PULL 33/37] i386: kvm: Add support for MSR filtering |
Date: |
Tue, 11 Oct 2022 12:26:56 +0200 |
From: Alexander Graf <agraf@csgraf.de>
KVM has grown support to deflect arbitrary MSRs to user space since
Linux 5.10. For now we don't expect to make a lot of use of this
feature, so let's expose it the easiest way possible: With up to 16
individually maskable MSRs.
This patch adds a kvm_filter_msr() function that other code can call
to install a hook on KVM MSR reads or writes.
Signed-off-by: Alexander Graf <agraf@csgraf.de>
Message-Id: <20221004225643.65036-3-agraf@csgraf.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/kvm/kvm.c | 123 +++++++++++++++++++++++++++++++++++++
target/i386/kvm/kvm_i386.h | 11 ++++
2 files changed, 134 insertions(+)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index ec63b5eb10..1d9a50b02b 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -141,6 +141,8 @@ static struct kvm_cpuid2 *cpuid_cache;
static struct kvm_cpuid2 *hv_cpuid_cache;
static struct kvm_msr_list *kvm_feature_msrs;
+static KVMMSRHandlers msr_handlers[KVM_MSR_FILTER_MAX_RANGES];
+
#define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */
static RateLimit bus_lock_ratelimit_ctrl;
static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value);
@@ -2610,6 +2612,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
return ret;
}
}
+ if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) {
+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0,
+ KVM_MSR_EXIT_REASON_FILTER);
+ if (ret) {
+ error_report("Could not enable user space MSRs: %s",
+ strerror(-ret));
+ exit(1);
+ }
+ }
return 0;
}
@@ -5109,6 +5120,108 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct
kvm_guest_debug *dbg)
}
}
+static bool kvm_install_msr_filters(KVMState *s)
+{
+ uint64_t zero = 0;
+ struct kvm_msr_filter filter = {
+ .flags = KVM_MSR_FILTER_DEFAULT_ALLOW,
+ };
+ int r, i, j = 0;
+
+ for (i = 0; i < KVM_MSR_FILTER_MAX_RANGES; i++) {
+ KVMMSRHandlers *handler = &msr_handlers[i];
+ if (handler->msr) {
+ struct kvm_msr_filter_range *range = &filter.ranges[j++];
+
+ *range = (struct kvm_msr_filter_range) {
+ .flags = 0,
+ .nmsrs = 1,
+ .base = handler->msr,
+ .bitmap = (__u8 *)&zero,
+ };
+
+ if (handler->rdmsr) {
+ range->flags |= KVM_MSR_FILTER_READ;
+ }
+
+ if (handler->wrmsr) {
+ range->flags |= KVM_MSR_FILTER_WRITE;
+ }
+ }
+ }
+
+ r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter);
+ if (r) {
+ return false;
+ }
+
+ return true;
+}
+
+bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
+ QEMUWRMSRHandler *wrmsr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
+ if (!msr_handlers[i].msr) {
+ msr_handlers[i] = (KVMMSRHandlers) {
+ .msr = msr,
+ .rdmsr = rdmsr,
+ .wrmsr = wrmsr,
+ };
+
+ if (!kvm_install_msr_filters(s)) {
+ msr_handlers[i] = (KVMMSRHandlers) { };
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run)
+{
+ int i;
+ bool r;
+
+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
+ KVMMSRHandlers *handler = &msr_handlers[i];
+ if (run->msr.index == handler->msr) {
+ if (handler->rdmsr) {
+ r = handler->rdmsr(cpu, handler->msr,
+ (uint64_t *)&run->msr.data);
+ run->msr.error = r ? 0 : 1;
+ return 0;
+ }
+ }
+ }
+
+ assert(false);
+}
+
+static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run)
+{
+ int i;
+ bool r;
+
+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
+ KVMMSRHandlers *handler = &msr_handlers[i];
+ if (run->msr.index == handler->msr) {
+ if (handler->wrmsr) {
+ r = handler->wrmsr(cpu, handler->msr, run->msr.data);
+ run->msr.error = r ? 0 : 1;
+ return 0;
+ }
+ }
+ }
+
+ assert(false);
+}
+
static bool has_sgx_provisioning;
static bool __kvm_enable_sgx_provisioning(KVMState *s)
@@ -5226,6 +5339,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run
*run)
ret = 0;
}
break;
+ case KVM_EXIT_X86_RDMSR:
+ /* We only enable MSR filtering, any other exit is bogus */
+ assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER);
+ ret = kvm_handle_rdmsr(cpu, run);
+ break;
+ case KVM_EXIT_X86_WRMSR:
+ /* We only enable MSR filtering, any other exit is bogus */
+ assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER);
+ ret = kvm_handle_wrmsr(cpu, run);
+ break;
default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1;
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 4124912c20..2ed586c11b 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -54,4 +54,15 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
bool kvm_enable_sgx_provisioning(KVMState *s);
void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask);
+typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val);
+typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val);
+typedef struct kvm_msr_handlers {
+ uint32_t msr;
+ QEMURDMSRHandler *rdmsr;
+ QEMUWRMSRHandler *wrmsr;
+} KVMMSRHandlers;
+
+bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
+ QEMUWRMSRHandler *wrmsr);
+
#endif
--
2.37.3
- [PULL 24/37] target/i386: Use gen_jmp_rel for gen_jcc, (continued)
- [PULL 24/37] target/i386: Use gen_jmp_rel for gen_jcc, Paolo Bonzini, 2022/10/11
- [PULL 25/37] target/i386: Use gen_jmp_rel for DISAS_TOO_MANY, Paolo Bonzini, 2022/10/11
- [PULL 27/37] target/i386: Merge gen_jmp_tb and gen_goto_tb into gen_jmp_rel, Paolo Bonzini, 2022/10/11
- [PULL 29/37] target/i386: Add cpu_eip, Paolo Bonzini, 2022/10/11
- [PULL 26/37] target/i386: Remove MemOp argument to gen_op_j*_ecx, Paolo Bonzini, 2022/10/11
- [PULL 30/37] target/i386: Inline gen_jmp_im, Paolo Bonzini, 2022/10/11
- [PULL 28/37] target/i386: Create eip_cur_tl, Paolo Bonzini, 2022/10/11
- [PULL 31/37] target/i386: Enable TARGET_TB_PCREL, Paolo Bonzini, 2022/10/11
- [PULL 32/37] x86: Implement MSR_CORE_THREAD_COUNT MSR, Paolo Bonzini, 2022/10/11
- [PULL 35/37] linux-user: i386/signal: move fpstate at the end of the 32-bit frames, Paolo Bonzini, 2022/10/11
- [PULL 33/37] i386: kvm: Add support for MSR filtering,
Paolo Bonzini <=
- [PULL 36/37] linux-user: i386/signal: support FXSAVE fpstate on 32-bit emulation, Paolo Bonzini, 2022/10/11
- [PULL 34/37] KVM: x86: Implement MSR_CORE_THREAD_COUNT MSR, Paolo Bonzini, 2022/10/11
- [PULL 37/37] linux-user: i386/signal: support XSAVE/XRSTOR for signal frame fpstate, Paolo Bonzini, 2022/10/11
- Re: [PULL 00/37] SCSI, i386 patches for 2022-10-11, Stefan Hajnoczi, 2022/10/13