return 0;
}
+#define HVMOP_op_mask 0xff
+
long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
{
struct domain *curr_d = current->domain;
+ unsigned long start_iter = op & ~HVMOP_op_mask;
long rc = 0;
- switch ( op )
+ switch ( op &= HVMOP_op_mask )
{
case HVMOP_set_param:
case HVMOP_get_param:
goto param_fail3;
rc = -EINVAL;
- if ( ((a.first_pfn + a.nr - 1) < a.first_pfn) ||
+ 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 param_fail3;
if ( !paging_mode_log_dirty(d) )
goto param_fail3;
- while ( a.nr > 0 )
+ while ( a.nr > start_iter )
{
- unsigned long pfn = a.first_pfn;
+ unsigned long pfn = a.first_pfn + start_iter;
struct page_info *page;
page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE);
put_page(page);
}
- a.first_pfn++;
- a.nr--;
-
/* Check for continuation if it's not the last interation */
- if ( a.nr > 0 && hypercall_preempt_check() )
+ if ( a.nr > ++start_iter && !(start_iter & HVMOP_op_mask) &&
+ hypercall_preempt_check() )
{
- if ( __copy_to_guest(arg, &a, 1) )
- rc = -EFAULT;
- else
- rc = -EAGAIN;
+ rc = -EAGAIN;
break;
}
}
goto param_fail4;
rc = -EINVAL;
- if ( ((a.first_pfn + a.nr - 1) < a.first_pfn) ||
+ 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 param_fail4;
if ( a.hvmmem_type >= ARRAY_SIZE(memtype) )
goto param_fail4;
- while ( a.nr )
+ while ( a.nr > start_iter )
{
- unsigned long pfn = a.first_pfn;
+ unsigned long pfn = a.first_pfn + start_iter;
p2m_type_t t;
p2m_type_t nt;
mfn_t mfn;
}
put_gfn(d, pfn);
- a.first_pfn++;
- a.nr--;
-
/* Check for continuation if it's not the last interation */
- if ( a.nr > 0 && hypercall_preempt_check() )
+ if ( a.nr > ++start_iter && !(start_iter & HVMOP_op_mask) &&
+ hypercall_preempt_check() )
{
- if ( __copy_to_guest(arg, &a, 1) )
- rc = -EFAULT;
- else
- rc = -EAGAIN;
+ rc = -EAGAIN;
goto param_fail4;
}
}
rc = -EINVAL;
if ( (a.first_pfn != ~0ull) &&
- (((a.first_pfn + a.nr - 1) < a.first_pfn) ||
+ (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 param_fail5;
- rc = p2m_set_mem_access(d, a.first_pfn, a.nr, a.hvmmem_access);
+ rc = p2m_set_mem_access(d, a.first_pfn, a.nr, start_iter,
+ HVMOP_op_mask, a.hvmmem_access);
if ( rc > 0 )
{
- a.first_pfn += a.nr - rc;
- a.nr = rc;
- if ( __copy_to_guest(arg, &a, 1) )
- rc = -EFAULT;
- else
- rc = -EAGAIN;
+ start_iter = rc;
+ rc = -EAGAIN;
}
param_fail5:
}
if ( rc == -EAGAIN )
- rc = hypercall_create_continuation(
- __HYPERVISOR_hvm_op, "lh", op, arg);
+ {
+ ASSERT(!(start_iter & HVMOP_op_mask));
+ rc = hypercall_create_continuation(__HYPERVISOR_hvm_op, "lh",
+ op | start_iter, arg);
+ }
return rc;
}
/* Set access type for a region of pfns.
* If start_pfn == -1ul, sets the default access type */
long p2m_set_mem_access(struct domain *d, unsigned long pfn, uint32_t nr,
- hvmmem_access_t access)
+ uint32_t start, uint32_t mask, hvmmem_access_t access)
{
struct p2m_domain *p2m = p2m_get_hostp2m(d);
p2m_access_t a, _a;
p2m_type_t t;
mfn_t mfn;
- long rc;
+ long rc = 0;
/* N.B. _not_ static: initializer depends on p2m->default_access */
p2m_access_t memaccess[] = {
return 0;
}
- if ( !nr )
- return 0;
-
p2m_lock(p2m);
- for ( ; ; ++pfn )
+ for ( pfn += start; nr > start; ++pfn )
{
mfn = p2m->get_entry(p2m, pfn, &t, &_a, 0, NULL);
if ( p2m->set_entry(p2m, pfn, mfn, PAGE_ORDER_4K, t, a) == 0 )
}
/* Check for continuation if it's not the last interation. */
- if ( !--nr || hypercall_preempt_check() )
+ if ( nr > ++start && !(start & mask) && hypercall_preempt_check() )
{
- rc = nr;
+ rc = start;
break;
}
}
/* Set access type for a region of pfns.
* If start_pfn == -1ul, sets the default access type */
-long p2m_set_mem_access(struct domain *d, unsigned long start_pfn,
- uint32_t nr, hvmmem_access_t access);
+long p2m_set_mem_access(struct domain *d, unsigned long start_pfn, uint32_t nr,
+ uint32_t start, uint32_t mask, hvmmem_access_t access);
/* Get access type for a pfn
* If pfn == -1ul, gets the default access type */
struct xen_hvm_track_dirty_vram {
/* Domain to be tracked. */
domid_t domid;
+ /* Number of pages to track. */
+ uint32_t nr;
/* First pfn to track. */
uint64_aligned_t first_pfn;
- /* Number of pages to track. */
- uint64_aligned_t nr;
/* OUT variable. */
/* Dirty bitmap buffer. */
XEN_GUEST_HANDLE_64(uint8) dirty_bitmap;
struct xen_hvm_modified_memory {
/* Domain to be updated. */
domid_t domid;
+ /* Number of pages. */
+ uint32_t nr;
/* First pfn. */
uint64_aligned_t first_pfn;
- /* Number of pages. */
- uint64_aligned_t nr;
};
typedef struct xen_hvm_modified_memory xen_hvm_modified_memory_t;
DEFINE_XEN_GUEST_HANDLE(xen_hvm_modified_memory_t);