diff mbox series

[RFC,v2,11/22] i386/xen: implement HYPERCALL_xen_version

Message ID 20221209095612.689243-12-dwmw2@infradead.org (mailing list archive)
State New, archived
Headers show
Series Xen HVM support under KVM | expand

Commit Message

David Woodhouse Dec. 9, 2022, 9:56 a.m. UTC
From: Joao Martins <joao.m.martins@oracle.com>

This is just meant to serve as an example on how we can implement
hypercalls. xen_version specifically since Qemu does all kind of
feature controllability. So handling that here seems appropriate.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
[dwmw2: Implement kvm_gva_rw() safely]
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 target/i386/xen.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

Comments

Paul Durrant Dec. 12, 2022, 2:17 p.m. UTC | #1
On 09/12/2022 09:56, David Woodhouse wrote:
> From: Joao Martins <joao.m.martins@oracle.com>
> 
> This is just meant to serve as an example on how we can implement
> hypercalls. xen_version specifically since Qemu does all kind of
> feature controllability. So handling that here seems appropriate.
> 
> Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
> [dwmw2: Implement kvm_gva_rw() safely]
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
>   target/i386/xen.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 79 insertions(+)
> 
> diff --git a/target/i386/xen.c b/target/i386/xen.c
> index 708ab908a0..55beed1913 100644
> --- a/target/i386/xen.c
> +++ b/target/i386/xen.c
> @@ -12,9 +12,51 @@
>   #include "qemu/osdep.h"
>   #include "qemu/log.h"
>   #include "kvm/kvm_i386.h"
> +#include "exec/address-spaces.h"
>   #include "xen.h"
>   #include "trace.h"
>   
> +#include "standard-headers/xen/version.h"
> +
> +static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz,
> +                      bool is_write)
> +{
> +    uint8_t *buf = (uint8_t *)_buf;
> +    size_t i = 0, len = 0;
> +    int ret;
> +
> +    for (i = 0; i < sz; i+= len) {
> +        struct kvm_translation tr = {
> +            .linear_address = gva + i,
> +        };
> +
> +        len = TARGET_PAGE_SIZE - (tr.linear_address & ~TARGET_PAGE_MASK);
> +        if (len > sz)

Shouldn't this be (sz - i)?

   Paul
David Woodhouse Dec. 13, 2022, 12:06 a.m. UTC | #2
On Mon, 2022-12-12 at 14:17 +0000, Paul Durrant wrote:
> Shouldn't this be (sz - i)?

Turns out I hate that loop. Have refactored it to be
while (sz) { ... sz -= len; ... }.

Thanks.
diff mbox series

Patch

diff --git a/target/i386/xen.c b/target/i386/xen.c
index 708ab908a0..55beed1913 100644
--- a/target/i386/xen.c
+++ b/target/i386/xen.c
@@ -12,9 +12,51 @@ 
 #include "qemu/osdep.h"
 #include "qemu/log.h"
 #include "kvm/kvm_i386.h"
+#include "exec/address-spaces.h"
 #include "xen.h"
 #include "trace.h"
 
+#include "standard-headers/xen/version.h"
+
+static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz,
+                      bool is_write)
+{
+    uint8_t *buf = (uint8_t *)_buf;
+    size_t i = 0, len = 0;
+    int ret;
+
+    for (i = 0; i < sz; i+= len) {
+        struct kvm_translation tr = {
+            .linear_address = gva + i,
+        };
+
+        len = TARGET_PAGE_SIZE - (tr.linear_address & ~TARGET_PAGE_MASK);
+        if (len > sz)
+            len = sz;
+
+        ret = kvm_vcpu_ioctl(cs, KVM_TRANSLATE, &tr);
+        if (ret || !tr.valid || (is_write && !tr.writeable)) {
+            return -EFAULT;
+        }
+
+        cpu_physical_memory_rw(tr.physical_address, buf + i, len, is_write);
+    }
+
+    return 0;
+}
+
+static inline int kvm_copy_from_gva(CPUState *cs, uint64_t gva, void *buf,
+                                    size_t sz)
+{
+    return kvm_gva_rw(cs, gva, buf, sz, false);
+}
+
+static inline int kvm_copy_to_gva(CPUState *cs, uint64_t gva, void *buf,
+                                  size_t sz)
+{
+    return kvm_gva_rw(cs, gva, buf, sz, false);
+}
+
 int kvm_xen_init(KVMState *s, uint32_t xen_version)
 {
     const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
@@ -50,6 +92,40 @@  int kvm_xen_init(KVMState *s, uint32_t xen_version)
     return 0;
 }
 
+static bool kvm_xen_hcall_xen_version(struct kvm_xen_exit *exit, X86CPU *cpu,
+                                     int cmd, uint64_t arg)
+{
+    int err = 0;
+
+    switch (cmd) {
+    case XENVER_get_features: {
+        struct xen_feature_info fi;
+
+        err = kvm_copy_from_gva(CPU(cpu), arg, &fi, sizeof(fi));
+        if (err) {
+            break;
+        }
+
+        fi.submap = 0;
+        if (fi.submap_idx == 0) {
+            fi.submap |= 1 << XENFEAT_writable_page_tables |
+                         1 << XENFEAT_writable_descriptor_tables |
+                         1 << XENFEAT_auto_translated_physmap |
+                         1 << XENFEAT_supervisor_mode_kernel;
+        }
+
+        err = kvm_copy_to_gva(CPU(cpu), arg, &fi, sizeof(fi));
+        break;
+    }
+
+    default:
+            return false;
+    }
+
+    exit->u.hcall.result = err;
+    return true;
+}
+
 static bool __kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
 {
     uint16_t code = exit->u.hcall.input;
@@ -60,6 +136,9 @@  static bool __kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
     }
 
     switch (code) {
+    case __HYPERVISOR_xen_version:
+        return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0],
+                                         exit->u.hcall.params[1]);
     default:
         return false;
     }