Message ID | 4c7ecaab0295e8420ee03baf37c7722e01bb81ce.1621885749.git.sidcha@amazon.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Handle hypercall code overlay page in userspace | expand |
On 24.05.21 22:01, Siddharth Chandrasekaran wrote: > Check and enable user space MSR filtering capability and handle new exit > reason KVM_EXIT_X86_WRMSR. This will be used in a follow up patch to > implement hyper-v overlay pages. > > Signed-off-by: Siddharth Chandrasekaran <sidcha@amazon.de> This patch will break bisection, because we're no longer handling the writes in kernel space after this, but we also don't have user space handling available yet, right? It might be better to move all logic in this patch that sets up the filter for Hyper-V MSRs into the next one. > --- > target/i386/kvm/kvm.c | 72 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 72 insertions(+) > > diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c > index 362f04ab3f..3591f8cecc 100644 > --- a/target/i386/kvm/kvm.c > +++ b/target/i386/kvm/kvm.c > @@ -117,6 +117,8 @@ static bool has_msr_ucode_rev; > static bool has_msr_vmx_procbased_ctls2; > static bool has_msr_perf_capabs; > static bool has_msr_pkrs; > +static bool has_msr_filtering; > +static bool msr_filters_active; > > static uint32_t has_architectural_pmu_version; > static uint32_t num_architectural_pmu_gp_counters; > @@ -2138,6 +2140,57 @@ static void register_smram_listener(Notifier *n, void *unused) > &smram_address_space, 1); > } > > +static void kvm_set_msr_filter_range(struct kvm_msr_filter_range *range, uint32_t flags, > + uint32_t base, uint32_t nmsrs, ...) > +{ > + int i, filter_to_userspace; > + va_list ap; > + > + range->flags = flags; > + range->nmsrs = nmsrs; > + range->base = base; > + > + va_start(ap, nmsrs); > + for (i = 0; i < nmsrs; i++) { > + filter_to_userspace = va_arg(ap, int); > + if (!filter_to_userspace) { > + range->bitmap[i / 8] = 1 << (i % 8); > + } > + } > + va_end(ap); > +} > + > +static int kvm_set_msr_filters(KVMState *s) > +{ > + int r, nmsrs, nfilt = 0, bitmap_pos = 0; > + struct kvm_msr_filter filter = { }; > + struct kvm_msr_filter_range *range; > + uint8_t bitmap_buf[KVM_MSR_FILTER_MAX_RANGES * 8] = {0}; > + > + filter.flags = KVM_MSR_FILTER_DEFAULT_ALLOW; > + > + if (has_hyperv) { > + /* Hyper-V overlay page MSRs */ I think you want to extend this comment and indicate in a human readable form that you set the filter on WRMSR to trap HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL into user space here. > + nmsrs = 2; > + range = &filter.ranges[nfilt++]; > + range->bitmap = &bitmap_buf[bitmap_pos]; > + kvm_set_msr_filter_range(range, KVM_MSR_FILTER_WRITE, > + HV_X64_MSR_GUEST_OS_ID, nmsrs, > + true, /* HV_X64_MSR_GUEST_OS_ID */ > + true /* HV_X64_MSR_HYPERCALL */); > + bitmap_pos += ROUND_UP(nmsrs, 8) / 8; > + assert(bitmap_pos < sizeof(bitmap_buf)); > + } > + > + r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter); > + if (r != 0) { > + error_report("kvm: failed to set MSR filters"); > + return -1; > + } > + > + return 0; > +} > + > int kvm_arch_init(MachineState *ms, KVMState *s) > { > uint64_t identity_base = 0xfffbc000; > @@ -2269,6 +2322,17 @@ int kvm_arch_init(MachineState *ms, KVMState *s) > } > } > > + has_msr_filtering = kvm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR) && > + kvm_check_extension(s, KVM_CAP_X86_MSR_FILTER); > + if (has_msr_filtering) { > + ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, > + KVM_MSR_EXIT_REASON_FILTER); > + if (ret == 0) { > + ret = kvm_set_msr_filters(s); > + msr_filters_active = (ret == 0); > + } > + } > + > return 0; > } > > @@ -4542,6 +4606,11 @@ static bool host_supports_vmx(void) > return ecx & CPUID_EXT_VMX; > } > > +static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) > +{ > + return 0; The default handler should always set run->msr.error = 1 to mimic the existing behavior. > +} > + > #define VMX_INVALID_GUEST_STATE 0x80000021 > > int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) > @@ -4600,6 +4669,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) > ioapic_eoi_broadcast(run->eoi.vector); > ret = 0; > break; > + case KVM_EXIT_X86_WRMSR: > + ret = kvm_handle_wrmsr(cpu, run); Please provide a default RDMSR handler as well here. Alex > + break; > default: > fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); > ret = -1; > Amazon Development Center Germany GmbH Krausenstr. 38 10117 Berlin Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B Sitz: Berlin Ust-ID: DE 289 237 879
On Tue, Jun 08, 2021 at 10:48:53AM +0200, Alexander Graf wrote: > On 24.05.21 22:01, Siddharth Chandrasekaran wrote: > > Check and enable user space MSR filtering capability and handle new exit > > reason KVM_EXIT_X86_WRMSR. This will be used in a follow up patch to > > implement hyper-v overlay pages. > > > > Signed-off-by: Siddharth Chandrasekaran <sidcha@amazon.de> > > This patch will break bisection, because we're no longer handling the writes > in kernel space after this, but we also don't have user space handling > available yet, right? It might be better to move all logic in this patch > that sets up the filter for Hyper-V MSRs into the next one. Yes, that's correct. I'll just bounce back all reads/writes to KVM. That should maintain the existing behaviour. > > --- > > target/i386/kvm/kvm.c | 72 +++++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 72 insertions(+) > > > > diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c > > index 362f04ab3f..3591f8cecc 100644 > > --- a/target/i386/kvm/kvm.c > > +++ b/target/i386/kvm/kvm.c > > @@ -117,6 +117,8 @@ static bool has_msr_ucode_rev; > > static bool has_msr_vmx_procbased_ctls2; > > static bool has_msr_perf_capabs; > > static bool has_msr_pkrs; > > +static bool has_msr_filtering; > > +static bool msr_filters_active; > > static uint32_t has_architectural_pmu_version; > > static uint32_t num_architectural_pmu_gp_counters; > > @@ -2138,6 +2140,57 @@ static void register_smram_listener(Notifier *n, void *unused) > > &smram_address_space, 1); > > } > > +static void kvm_set_msr_filter_range(struct kvm_msr_filter_range *range, uint32_t flags, > > + uint32_t base, uint32_t nmsrs, ...) > > +{ > > + int i, filter_to_userspace; > > + va_list ap; > > + > > + range->flags = flags; > > + range->nmsrs = nmsrs; > > + range->base = base; > > + > > + va_start(ap, nmsrs); > > + for (i = 0; i < nmsrs; i++) { > > + filter_to_userspace = va_arg(ap, int); > > + if (!filter_to_userspace) { > > + range->bitmap[i / 8] = 1 << (i % 8); > > + } > > + } > > + va_end(ap); > > +} > > + > > +static int kvm_set_msr_filters(KVMState *s) > > +{ > > + int r, nmsrs, nfilt = 0, bitmap_pos = 0; > > + struct kvm_msr_filter filter = { }; > > + struct kvm_msr_filter_range *range; > > + uint8_t bitmap_buf[KVM_MSR_FILTER_MAX_RANGES * 8] = {0}; > > + > > + filter.flags = KVM_MSR_FILTER_DEFAULT_ALLOW; > > + > > + if (has_hyperv) { > > + /* Hyper-V overlay page MSRs */ > > I think you want to extend this comment and indicate in a human readable > form that you set the filter on WRMSR to trap HV_X64_MSR_GUEST_OS_ID and > HV_X64_MSR_HYPERCALL into user space here. Sure. > > + nmsrs = 2; > > + range = &filter.ranges[nfilt++]; > > + range->bitmap = &bitmap_buf[bitmap_pos]; > > + kvm_set_msr_filter_range(range, KVM_MSR_FILTER_WRITE, > > + HV_X64_MSR_GUEST_OS_ID, nmsrs, > > + true, /* HV_X64_MSR_GUEST_OS_ID */ > > + true /* HV_X64_MSR_HYPERCALL */); > > + bitmap_pos += ROUND_UP(nmsrs, 8) / 8; > > + assert(bitmap_pos < sizeof(bitmap_buf)); > > + } > > + > > + r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter); > > + if (r != 0) { > > + error_report("kvm: failed to set MSR filters"); > > + return -1; > > + } > > + > > + return 0; > > +} > > + > > int kvm_arch_init(MachineState *ms, KVMState *s) > > { > > uint64_t identity_base = 0xfffbc000; > > @@ -2269,6 +2322,17 @@ int kvm_arch_init(MachineState *ms, KVMState *s) > > } > > } > > + has_msr_filtering = kvm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR) && > > + kvm_check_extension(s, KVM_CAP_X86_MSR_FILTER); > > + if (has_msr_filtering) { > > + ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, > > + KVM_MSR_EXIT_REASON_FILTER); > > + if (ret == 0) { > > + ret = kvm_set_msr_filters(s); > > + msr_filters_active = (ret == 0); > > + } > > + } > > + > > return 0; > > } > > @@ -4542,6 +4606,11 @@ static bool host_supports_vmx(void) > > return ecx & CPUID_EXT_VMX; > > } > > +static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) > > +{ > > + return 0; > > The default handler should always set run->msr.error = 1 to mimic the > existing behavior. Will do, thanks. > > +} > > + > > #define VMX_INVALID_GUEST_STATE 0x80000021 > > int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) > > @@ -4600,6 +4669,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) > > ioapic_eoi_broadcast(run->eoi.vector); > > ret = 0; > > break; > > + case KVM_EXIT_X86_WRMSR: > > + ret = kvm_handle_wrmsr(cpu, run); > > Please provide a default RDMSR handler as well here. Ack. ~ Sid. Amazon Development Center Germany GmbH Krausenstr. 38 10117 Berlin Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B Sitz: Berlin Ust-ID: DE 289 237 879
On Tue, Jun 08, 2021 at 12:53:17PM +0200, Siddharth Chandrasekaran wrote: > On Tue, Jun 08, 2021 at 10:48:53AM +0200, Alexander Graf wrote: > > On 24.05.21 22:01, Siddharth Chandrasekaran wrote: > > > Check and enable user space MSR filtering capability and handle new exit > > > reason KVM_EXIT_X86_WRMSR. This will be used in a follow up patch to > > > implement hyper-v overlay pages. > > > > > > Signed-off-by: Siddharth Chandrasekaran <sidcha@amazon.de> > > > > This patch will break bisection, because we're no longer handling the writes > > in kernel space after this, but we also don't have user space handling > > available yet, right? It might be better to move all logic in this patch > > that sets up the filter for Hyper-V MSRs into the next one. > > Yes, that's correct. I'll just bounce back all reads/writes to KVM. That > should maintain the existing behaviour. Okay, bouncing back to KVM was a bad idea :). Moved filters to next patch as suggested. ~ Sid. Amazon Development Center Germany GmbH Krausenstr. 38 10117 Berlin Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B Sitz: Berlin Ust-ID: DE 289 237 879
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 362f04ab3f..3591f8cecc 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -117,6 +117,8 @@ static bool has_msr_ucode_rev; static bool has_msr_vmx_procbased_ctls2; static bool has_msr_perf_capabs; static bool has_msr_pkrs; +static bool has_msr_filtering; +static bool msr_filters_active; static uint32_t has_architectural_pmu_version; static uint32_t num_architectural_pmu_gp_counters; @@ -2138,6 +2140,57 @@ static void register_smram_listener(Notifier *n, void *unused) &smram_address_space, 1); } +static void kvm_set_msr_filter_range(struct kvm_msr_filter_range *range, uint32_t flags, + uint32_t base, uint32_t nmsrs, ...) +{ + int i, filter_to_userspace; + va_list ap; + + range->flags = flags; + range->nmsrs = nmsrs; + range->base = base; + + va_start(ap, nmsrs); + for (i = 0; i < nmsrs; i++) { + filter_to_userspace = va_arg(ap, int); + if (!filter_to_userspace) { + range->bitmap[i / 8] = 1 << (i % 8); + } + } + va_end(ap); +} + +static int kvm_set_msr_filters(KVMState *s) +{ + int r, nmsrs, nfilt = 0, bitmap_pos = 0; + struct kvm_msr_filter filter = { }; + struct kvm_msr_filter_range *range; + uint8_t bitmap_buf[KVM_MSR_FILTER_MAX_RANGES * 8] = {0}; + + filter.flags = KVM_MSR_FILTER_DEFAULT_ALLOW; + + if (has_hyperv) { + /* Hyper-V overlay page MSRs */ + nmsrs = 2; + range = &filter.ranges[nfilt++]; + range->bitmap = &bitmap_buf[bitmap_pos]; + kvm_set_msr_filter_range(range, KVM_MSR_FILTER_WRITE, + HV_X64_MSR_GUEST_OS_ID, nmsrs, + true, /* HV_X64_MSR_GUEST_OS_ID */ + true /* HV_X64_MSR_HYPERCALL */); + bitmap_pos += ROUND_UP(nmsrs, 8) / 8; + assert(bitmap_pos < sizeof(bitmap_buf)); + } + + r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter); + if (r != 0) { + error_report("kvm: failed to set MSR filters"); + return -1; + } + + return 0; +} + int kvm_arch_init(MachineState *ms, KVMState *s) { uint64_t identity_base = 0xfffbc000; @@ -2269,6 +2322,17 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + has_msr_filtering = kvm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR) && + kvm_check_extension(s, KVM_CAP_X86_MSR_FILTER); + if (has_msr_filtering) { + ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, + KVM_MSR_EXIT_REASON_FILTER); + if (ret == 0) { + ret = kvm_set_msr_filters(s); + msr_filters_active = (ret == 0); + } + } + return 0; } @@ -4542,6 +4606,11 @@ static bool host_supports_vmx(void) return ecx & CPUID_EXT_VMX; } +static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) +{ + return 0; +} + #define VMX_INVALID_GUEST_STATE 0x80000021 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) @@ -4600,6 +4669,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ioapic_eoi_broadcast(run->eoi.vector); ret = 0; break; + case KVM_EXIT_X86_WRMSR: + ret = kvm_handle_wrmsr(cpu, run); + break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1;
Check and enable user space MSR filtering capability and handle new exit reason KVM_EXIT_X86_WRMSR. This will be used in a follow up patch to implement hyper-v overlay pages. Signed-off-by: Siddharth Chandrasekaran <sidcha@amazon.de> --- target/i386/kvm/kvm.c | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+)