mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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:
1 parent
b30c5979e0
commit
ae20ccf070
8 files changed
+128
-176
No files matched your search
@@ -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
@@ -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(
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||