i386/xen: implement HYPERVISOR_xen_version
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> Reviewed-by: Paul Durrant <paul@xen.org>
This commit is contained in:
parent
55a3f666b4
commit
bedcc13924
|
@ -14,9 +14,55 @@
|
|||
#include "sysemu/kvm_int.h"
|
||||
#include "sysemu/kvm_xen.h"
|
||||
#include "kvm/kvm_i386.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "xen-emu.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "hw/xen/interface/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;
|
||||
int ret;
|
||||
|
||||
while (sz) {
|
||||
struct kvm_translation tr = {
|
||||
.linear_address = gva,
|
||||
};
|
||||
|
||||
size_t 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, len, is_write);
|
||||
|
||||
buf += len;
|
||||
sz -= len;
|
||||
gva += len;
|
||||
}
|
||||
|
||||
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, true);
|
||||
}
|
||||
|
||||
int kvm_xen_init(KVMState *s, uint32_t hypercall_msr)
|
||||
{
|
||||
const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
|
||||
|
@ -87,6 +133,43 @@ uint32_t kvm_xen_get_caps(void)
|
|||
return kvm_state->xen_caps;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* No need for 32/64 compat handling */
|
||||
qemu_build_assert(sizeof(fi) == 8);
|
||||
|
||||
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 do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
|
||||
{
|
||||
uint16_t code = exit->u.hcall.input;
|
||||
|
@ -97,6 +180,9 @@ static bool do_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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue