return 0;
}
+#define HVMOP_op_bits 32
+
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_bits;
long rc = 0;
- switch ( op )
+ switch ( op &= ((1UL << HVMOP_op_bits) - 1) )
{
+ struct domain *d;
+ unsigned long pfn;
+
case HVMOP_set_param:
case HVMOP_get_param:
{
struct xen_hvm_param a;
struct hvm_ioreq_page *iorp;
- struct domain *d;
struct vcpu *v;
if ( copy_from_guest(&a, arg, 1) )
case HVMOP_track_dirty_vram:
{
struct xen_hvm_track_dirty_vram a;
- struct domain *d;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
case HVMOP_modified_memory:
{
struct xen_hvm_modified_memory a;
- struct domain *d;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
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 )
+ for ( pfn = a.first_pfn + start_iter; a.nr > start_iter; ++pfn )
{
- unsigned long pfn = a.first_pfn;
struct page_info *page;
page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE);
put_page(page);
}
- a.first_pfn++;
- a.nr--;
+ ++pfn;
+ ++start_iter;
/* Check for continuation if it's not the last interation */
- if ( a.nr > 0 && hypercall_preempt_check() )
+ if ( a.nr > start_iter && hypercall_preempt_check() )
{
- if ( __copy_to_guest(arg, &a, 1) )
- rc = -EFAULT;
- else
- rc = -EAGAIN;
+ rc = -EAGAIN;
break;
}
}
case HVMOP_get_mem_type:
{
struct xen_hvm_get_mem_type a;
- struct domain *d;
p2m_type_t t;
if ( copy_from_guest(&a, arg, 1) )
case HVMOP_set_mem_type:
{
struct xen_hvm_set_mem_type a;
- struct domain *d;
/* Interface types to internal p2m types */
static const p2m_type_t memtype[] = {
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 )
+ for ( pfn = a.first_pfn + start_iter; a.nr > start_iter; ++pfn )
{
- unsigned long pfn = a.first_pfn;
- p2m_type_t t;
- p2m_type_t nt;
- mfn_t mfn;
- mfn = get_gfn_unshare(d, pfn, &t);
+ p2m_type_t t, nt;
+
+ get_gfn_unshare(d, pfn, &t);
if ( p2m_is_paging(t) )
{
put_gfn(d, pfn);
}
put_gfn(d, pfn);
- a.first_pfn++;
- a.nr--;
+ ++pfn;
+ ++start_iter;
/* Check for continuation if it's not the last interation */
- if ( a.nr > 0 && hypercall_preempt_check() )
+ if ( a.nr > start_iter && hypercall_preempt_check() )
{
- if ( __copy_to_guest(arg, &a, 1) )
- rc = -EFAULT;
- else
- rc = -EAGAIN;
+ rc = -EAGAIN;
goto param_fail4;
}
}
case HVMOP_set_mem_access:
{
struct xen_hvm_set_mem_access a;
- struct domain *d;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
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 + start_iter, a.nr - start_iter,
+ 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 = a.nr - rc;
+ rc = -EAGAIN;
}
param_fail5:
case HVMOP_get_mem_access:
{
struct xen_hvm_get_mem_access a;
- struct domain *d;
hvmmem_access_t access;
if ( copy_from_guest(&a, arg, 1) )
case HVMOP_pagetable_dying:
{
struct xen_hvm_pagetable_dying a;
- struct domain *d;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
case HVMOP_inject_trap:
{
xen_hvm_inject_trap_t tr;
- struct domain *d;
struct vcpu *v;
if ( copy_from_guest(&tr, arg, 1 ) )
}
if ( rc == -EAGAIN )
- rc = hypercall_create_continuation(
- __HYPERVISOR_hvm_op, "lh", op, arg);
+ rc = hypercall_create_continuation(__HYPERVISOR_hvm_op, "lh",
+ op | (start_iter << HVMOP_op_bits),
+ arg);
return rc;
}