dm_op: convert HVMOP_set_mem_type

This patch removes the need for handling HVMOP restarts, so that
infrastructure is removed.

NOTE: This patch also modifies the type of the 'nr' argument of
      xc_hvm_set_mem_type() from uint64_t to uint32_t. In practice the
      value passed was always truncated to 32 bits.

Suggested-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Paul Durrant authored and Jan Beulich committed 2017-01-25 10:48:25 +01:00
1 parent b30c5979e0
commit ae20ccf070
8 files changed
+128 -176

No files matched your search

+1 -1
View File
@@ -1634,7 +1634,7 @@ int xc_hvm_modified_memory(
* Allowed types are HVMMEM_ram_rw, HVMMEM_ram_ro, HVMMEM_mmio_dm
*/
int xc_hvm_set_mem_type(
xc_interface *xch, domid_t dom, hvmmem_type_t memtype, uint64_t first_pfn, uint64_t nr);
xc_interface *xch, domid_t dom, hvmmem_type_t memtype, uint64_t first_pfn, uint32_t nr);
/*
* Injects a hardware/software CPU trap, to take effect the next time the HVM
+10 -19
View File
@@ -590,30 +590,21 @@ int xc_hvm_modified_memory(
}
int xc_hvm_set_mem_type(
xc_interface *xch, domid_t dom, hvmmem_type_t mem_type, uint64_t first_pfn, uint64_t nr)
xc_interface *xch, domid_t dom, hvmmem_type_t mem_type, uint64_t first_pfn, uint32_t nr)
{
DECLARE_HYPERCALL_BUFFER(struct xen_hvm_set_mem_type, arg);
int rc;
struct xen_dm_op op;
struct xen_dm_op_set_mem_type *data;
arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
if ( arg == NULL )
{
PERROR("Could not allocate memory for xc_hvm_set_mem_type hypercall");
return -1;
}
memset(&op, 0, sizeof(op));
arg->domid = dom;
arg->hvmmem_type = mem_type;
arg->first_pfn = first_pfn;
arg->nr = nr;
op.op = XEN_DMOP_set_mem_type;
data = &op.u.set_mem_type;
rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op,
HVMOP_set_mem_type,
HYPERCALL_BUFFER_AS_ARG(arg));
data->mem_type = mem_type;
data->first_pfn = first_pfn;
data->nr = nr;
xc_hypercall_buffer_free(xch, arg);
return rc;
return do_dm_op(xch, dom, 1, &op, sizeof(op));
}
int xc_hvm_inject_trap(
+92
View File
@@ -171,6 +171,82 @@ static int modified_memory(struct domain *d,
return rc;
}
static bool allow_p2m_type_change(p2m_type_t old, p2m_type_t new)
{
return p2m_is_ram(old) ||
(p2m_is_hole(old) && new == p2m_mmio_dm) ||
(old == p2m_ioreq_server && new == p2m_ram_rw);
}
static int set_mem_type(struct domain *d,
struct xen_dm_op_set_mem_type *data)
{
xen_pfn_t last_pfn = data->first_pfn + data->nr - 1;
unsigned int iter = 0;
int rc = 0;
/* Interface types to internal p2m types */
static const p2m_type_t memtype[] = {
[HVMMEM_ram_rw] = p2m_ram_rw,
[HVMMEM_ram_ro] = p2m_ram_ro,
[HVMMEM_mmio_dm] = p2m_mmio_dm,
[HVMMEM_unused] = p2m_invalid,
[HVMMEM_ioreq_server] = p2m_ioreq_server,
};
if ( (data->first_pfn > last_pfn) ||
(last_pfn > domain_get_maximum_gpfn(d)) )
return -EINVAL;
if ( data->mem_type >= ARRAY_SIZE(memtype) ||
unlikely(data->mem_type == HVMMEM_unused) )
return -EINVAL;
while ( iter < data->nr )
{
unsigned long pfn = data->first_pfn + iter;
p2m_type_t t;
get_gfn_unshare(d, pfn, &t);
if ( p2m_is_paging(t) )
{
put_gfn(d, pfn);
p2m_mem_paging_populate(d, pfn);
return -EAGAIN;
}
if ( p2m_is_shared(t) )
rc = -EAGAIN;
else if ( !allow_p2m_type_change(t, memtype[data->mem_type]) )
rc = -EINVAL;
else
rc = p2m_change_type_one(d, pfn, t, memtype[data->mem_type]);
put_gfn(d, pfn);
if ( rc )
break;
iter++;
/*
* Check for continuation every 256th iteration and if the
* iteration is not the last.
*/
if ( (iter < data->nr) && ((iter & 0xff) == 0) &&
hypercall_preempt_check() )
{
data->first_pfn += iter;
data->nr -= iter;
rc = -ERESTART;
break;
}
}
return rc;
}
static int dm_op(domid_t domid,
unsigned int nr_bufs,
xen_dm_op_buf_t bufs[])
@@ -352,6 +428,21 @@ static int dm_op(domid_t domid,
break;
}
case XEN_DMOP_set_mem_type:
{
struct xen_dm_op_set_mem_type *data =
&op.u.set_mem_type;
const_op = false;
rc = -EINVAL;
if ( data->pad )
break;
rc = set_mem_type(d, data);
break;
}
default:
rc = -EOPNOTSUPP;
break;
@@ -378,6 +469,7 @@ CHECK_dm_op_set_pci_intx_level;
CHECK_dm_op_set_isa_irq_level;
CHECK_dm_op_set_pci_link_route;
CHECK_dm_op_modified_memory;
CHECK_dm_op_set_mem_type;
#define MAX_NR_BUFS 2
+1 -135
View File
@@ -4850,132 +4850,11 @@ static int hvmop_get_mem_type(
return rc;
}
/*
* Note that this value is effectively part of the ABI, even if we don't need
* to make it a formal part of it: A guest suspended for migration in the
* middle of a continuation would fail to work if resumed on a hypervisor
* using a different value.
*/
#define HVMOP_op_mask 0xff
static bool_t hvm_allow_p2m_type_change(p2m_type_t old, p2m_type_t new)
{
if ( p2m_is_ram(old) ||
(p2m_is_hole(old) && new == p2m_mmio_dm) ||
(old == p2m_ioreq_server && new == p2m_ram_rw) )
return 1;
return 0;
}
static int hvmop_set_mem_type(
XEN_GUEST_HANDLE_PARAM(xen_hvm_set_mem_type_t) arg,
unsigned long *iter)
{
unsigned long start_iter = *iter;
struct xen_hvm_set_mem_type a;
struct domain *d;
int rc;
/* Interface types to internal p2m types */
static const p2m_type_t memtype[] = {
[HVMMEM_ram_rw] = p2m_ram_rw,
[HVMMEM_ram_ro] = p2m_ram_ro,
[HVMMEM_mmio_dm] = p2m_mmio_dm,
[HVMMEM_unused] = p2m_invalid,
[HVMMEM_ioreq_server] = p2m_ioreq_server
};
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
rc = rcu_lock_remote_domain_by_id(a.domid, &d);
if ( rc != 0 )
return rc;
rc = -EINVAL;
if ( !is_hvm_domain(d) )
goto out;
rc = xsm_hvm_control(XSM_DM_PRIV, d, HVMOP_set_mem_type);
if ( rc )
goto out;
rc = -EINVAL;
if ( a.nr < start_iter ||
((a.first_pfn + a.nr - 1) < a.first_pfn) ||
((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
goto out;
if ( a.hvmmem_type >= ARRAY_SIZE(memtype) ||
unlikely(a.hvmmem_type == HVMMEM_unused) )
goto out;
while ( a.nr > start_iter )
{
unsigned long pfn = a.first_pfn + start_iter;
p2m_type_t t;
get_gfn_unshare(d, pfn, &t);
if ( p2m_is_paging(t) )
{
put_gfn(d, pfn);
p2m_mem_paging_populate(d, pfn);
rc = -EAGAIN;
goto out;
}
if ( p2m_is_shared(t) )
{
put_gfn(d, pfn);
rc = -EAGAIN;
goto out;
}
if ( !hvm_allow_p2m_type_change(t, memtype[a.hvmmem_type]) )
{
put_gfn(d, pfn);
goto out;
}
rc = p2m_change_type_one(d, pfn, t, memtype[a.hvmmem_type]);
put_gfn(d, pfn);
if ( rc )
goto out;
/* Check for continuation if it's not the last interation */
if ( a.nr > ++start_iter && !(start_iter & HVMOP_op_mask) &&
hypercall_preempt_check() )
{
rc = -ERESTART;
goto out;
}
}
rc = 0;
out:
rcu_unlock_domain(d);
*iter = start_iter;
return rc;
}
long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
{
unsigned long start_iter, mask;
long rc = 0;
switch ( op & HVMOP_op_mask )
{
default:
mask = ~0UL;
break;
case HVMOP_set_mem_type:
mask = HVMOP_op_mask;
break;
}
start_iter = op & ~mask;
switch ( op &= mask )
switch ( op )
{
case HVMOP_set_evtchn_upcall_vector:
rc = hvmop_set_evtchn_upcall_vector(
@@ -5006,12 +4885,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
guest_handle_cast(arg, xen_hvm_get_mem_type_t));
break;
case HVMOP_set_mem_type:
rc = hvmop_set_mem_type(
guest_handle_cast(arg, xen_hvm_set_mem_type_t),
&start_iter);
break;
case HVMOP_pagetable_dying:
{
struct xen_hvm_pagetable_dying a;
@@ -5120,13 +4993,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
}
}
if ( rc == -ERESTART )
{
ASSERT(!(start_iter & mask));
rc = hypercall_create_continuation(__HYPERVISOR_hvm_op, "lh",
op | start_iter, arg);
}
return rc;
}
+22
View File
@@ -251,6 +251,27 @@ struct xen_dm_op_modified_memory {
uint64_aligned_t first_pfn;
};
/*
* XEN_DMOP_set_mem_type: Notify that a region of memory is to be treated
* in a specific way. (See definition of
* hvmmem_type_t).
*
* NOTE: In the event of a continuation (return code -ERESTART), the
* @first_pfn is set to the value of the pfn of the remaining
* region and @nr reduced to the size of the remaining region.
*/
#define XEN_DMOP_set_mem_type 12
struct xen_dm_op_set_mem_type {
/* IN - number of contiguous pages */
uint32_t nr;
/* IN - new hvmmem_type_t of region */
uint16_t mem_type;
uint16_t pad;
/* IN - first pfn in region */
uint64_aligned_t first_pfn;
};
struct xen_dm_op {
uint32_t op;
uint32_t pad;
@@ -266,6 +287,7 @@ struct xen_dm_op {
struct xen_dm_op_set_isa_irq_level set_isa_irq_level;
struct xen_dm_op_set_pci_link_route set_pci_link_route;
struct xen_dm_op_modified_memory modified_memory;
struct xen_dm_op_set_mem_type set_mem_type;
} u;
};
-20
View File
@@ -96,26 +96,6 @@ typedef enum {
HVMMEM_ioreq_server
} hvmmem_type_t;
/* Following tools-only interfaces may change in future. */
#if defined(__XEN__) || defined(__XEN_TOOLS__)
#define HVMOP_set_mem_type 8
/* Notify that a region of memory is to be treated in a specific way. */
struct xen_hvm_set_mem_type {
/* Domain to be updated. */
domid_t domid;
/* Memory type */
uint16_t hvmmem_type;
/* Number of pages. */
uint32_t nr;
/* First pfn. */
uint64_aligned_t first_pfn;
};
typedef struct xen_hvm_set_mem_type xen_hvm_set_mem_type_t;
DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_type_t);
#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
/* Hint from PV drivers for pagetable destruction. */
#define HVMOP_pagetable_dying 9
struct xen_hvm_pagetable_dying {
+1
View File
@@ -64,6 +64,7 @@
? dm_op_modified_memory hvm/dm_op.h
? dm_op_set_ioreq_server_state hvm/dm_op.h
? dm_op_set_isa_irq_level hvm/dm_op.h
? dm_op_set_mem_type hvm/dm_op.h
? dm_op_set_pci_intx_level hvm/dm_op.h
? dm_op_set_pci_link_route hvm/dm_op.h
? dm_op_track_dirty_vram hvm/dm_op.h
+1 -1
View File
@@ -262,7 +262,7 @@ class hvm
bind_irq
# XEN_DOMCTL_pin_mem_cacheattr
cacheattr
# HVMOP_get_mem_type, HVMOP_set_mem_type,
# HVMOP_get_mem_type,
# HVMOP_set_mem_access, HVMOP_get_mem_access, HVMOP_pagetable_dying,
# HVMOP_inject_trap
hvmctl
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.