i386/xen: implement XENMEM_add_to_physmap_batch

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
This commit is contained in:
David Woodhouse 2022-12-15 10:39:30 +00:00
parent fb0fd2ce38
commit 782a79601e
2 changed files with 93 additions and 0 deletions

View File

@ -15,6 +15,20 @@
typedef uint32_t compat_pfn_t;
typedef uint32_t compat_ulong_t;
typedef uint32_t compat_ptr_t;
#define __DEFINE_COMPAT_HANDLE(name, type) \
typedef struct { \
compat_ptr_t c; \
type *_[0] __attribute__((packed)); \
} __compat_handle_ ## name; \
#define DEFINE_COMPAT_HANDLE(name) __DEFINE_COMPAT_HANDLE(name, name)
#define COMPAT_HANDLE(name) __compat_handle_ ## name
DEFINE_COMPAT_HANDLE(compat_pfn_t);
DEFINE_COMPAT_HANDLE(compat_ulong_t);
DEFINE_COMPAT_HANDLE(int);
struct compat_xen_add_to_physmap {
domid_t domid;
@ -24,4 +38,14 @@ struct compat_xen_add_to_physmap {
compat_pfn_t gpfn;
};
struct compat_xen_add_to_physmap_batch {
domid_t domid;
uint16_t space;
uint16_t size;
uint16_t extra;
COMPAT_HANDLE(compat_ulong_t) idxs;
COMPAT_HANDLE(compat_pfn_t) gpfns;
COMPAT_HANDLE(int) errs;
};
#endif /* QEMU_I386_XEN_COMPAT_H */

View File

@ -262,6 +262,71 @@ static int do_add_to_physmap(struct kvm_xen_exit *exit, X86CPU *cpu,
return add_to_physmap_one(xatp.space, xatp.idx, xatp.gpfn);
}
static int do_add_to_physmap_batch(struct kvm_xen_exit *exit, X86CPU *cpu,
uint64_t arg)
{
struct xen_add_to_physmap_batch xatpb;
unsigned long idxs_gva, gpfns_gva, errs_gva;
CPUState *cs = CPU(cpu);
size_t op_sz;
if (hypercall_compat32(exit->u.hcall.longmode)) {
struct compat_xen_add_to_physmap_batch xatpb32;
qemu_build_assert(sizeof(struct compat_xen_add_to_physmap_batch) == 20);
if (kvm_copy_from_gva(cs, arg, &xatpb32, sizeof(xatpb32))) {
return -EFAULT;
}
xatpb.domid = xatpb32.domid;
xatpb.space = xatpb32.space;
xatpb.size = xatpb32.size;
idxs_gva = xatpb32.idxs.c;
gpfns_gva = xatpb32.gpfns.c;
errs_gva = xatpb32.errs.c;
op_sz = sizeof(uint32_t);
} else {
if (kvm_copy_from_gva(cs, arg, &xatpb, sizeof(xatpb))) {
return -EFAULT;
}
op_sz = sizeof(unsigned long);
idxs_gva = (unsigned long)xatpb.idxs.p;
gpfns_gva = (unsigned long)xatpb.gpfns.p;
errs_gva = (unsigned long)xatpb.errs.p;
}
if (xatpb.domid != DOMID_SELF && xatpb.domid != xen_domid) {
return -ESRCH;
}
/* Explicitly invalid for the batch op. Not that we implement it anyway. */
if (xatpb.space == XENMAPSPACE_gmfn_range) {
return -EINVAL;
}
while (xatpb.size--) {
unsigned long idx = 0;
unsigned long gpfn = 0;
int err;
/* For 32-bit compat this only copies the low 32 bits of each */
if (kvm_copy_from_gva(cs, idxs_gva, &idx, op_sz) ||
kvm_copy_from_gva(cs, gpfns_gva, &gpfn, op_sz)) {
return -EFAULT;
}
idxs_gva += op_sz;
gpfns_gva += op_sz;
err = add_to_physmap_one(xatpb.space, idx, gpfn);
if (kvm_copy_to_gva(cs, errs_gva, &err, sizeof(err))) {
return -EFAULT;
}
errs_gva += sizeof(err);
}
return 0;
}
static bool kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, X86CPU *cpu,
int cmd, uint64_t arg)
{
@ -272,6 +337,10 @@ static bool kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, X86CPU *cpu,
err = do_add_to_physmap(exit, cpu, arg);
break;
case XENMEM_add_to_physmap_batch:
err = do_add_to_physmap_batch(exit, cpu, arg);
break;
default:
return false;
}