ia64/xen-unstable

changeset 11039:bef360142b62

[IA64] copy_from/to_guest

This patch fixes the copy_from/to_guest problem.
As Akio reported, modularised netback causes dom0's down.

The following process is happened in gnttab_transfer()@
xen/common/grant_table.c:

gnttab_transfer()
=> steal_page()
=> assign_domain_page_cmpxchg_rel()
=> domain_page_flush()
=> domain_flush_vtlb_all() // all TLBs are flushed
...
=> __copy_to_guest_offset() // always fail to copy

The embedded netback module has no problem because it uses TR pinned
data. But modularised one is out of TR. So copy_from/to_guest issue
must be solved in order to modularise drivers.

Signed-off-by: Kouya SHIMURA <kouya@jp.fujitsu.com>
author awilliam@xenbuild.aw
date Mon Aug 14 14:21:21 2006 -0600 (2006-08-14)
parents 9da2cd61822e
children 92c62a897c82
files linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c linux-2.6-xen-sparse/include/asm-ia64/hypercall.h xen/arch/ia64/xen/hypercall.c xen/arch/ia64/xen/vcpu.c xen/include/asm-ia64/domain.h xen/include/asm-ia64/uaccess.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c	Mon Aug 14 13:46:05 2006 -0600
     1.2 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c	Mon Aug 14 14:21:21 2006 -0600
     1.3 @@ -371,6 +371,8 @@ gnttab_map_grant_ref_pre(struct gnttab_m
     1.4  int
     1.5  HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
     1.6  {
     1.7 +	__u64 va1, va2, pa1, pa2;
     1.8 +
     1.9  	if (cmd == GNTTABOP_map_grant_ref) {
    1.10  		unsigned int i;
    1.11  		for (i = 0; i < count; i++) {
    1.12 @@ -378,8 +380,29 @@ HYPERVISOR_grant_table_op(unsigned int c
    1.13  				(struct gnttab_map_grant_ref*)uop + i);
    1.14  		}
    1.15  	}
    1.16 -
    1.17 -	return ____HYPERVISOR_grant_table_op(cmd, uop, count);
    1.18 +	va1 = (__u64)uop & PAGE_MASK;
    1.19 +	pa1 = pa2 = 0;
    1.20 +	if ((REGION_NUMBER(va1) == 5) &&
    1.21 +	    ((va1 - KERNEL_START) >= KERNEL_TR_PAGE_SIZE)) {
    1.22 +		pa1 = ia64_tpa(va1);
    1.23 +		if (cmd <= GNTTABOP_transfer) {
    1.24 +			static uint32_t uop_size[GNTTABOP_transfer + 1] = {
    1.25 +				sizeof(struct gnttab_map_grant_ref),
    1.26 +				sizeof(struct gnttab_unmap_grant_ref),
    1.27 +				sizeof(struct gnttab_setup_table),
    1.28 +				sizeof(struct gnttab_dump_table),
    1.29 +				sizeof(struct gnttab_transfer),
    1.30 +			};
    1.31 +			va2 = (__u64)uop + (uop_size[cmd] * count) - 1;
    1.32 +			va2 &= PAGE_MASK;
    1.33 +			if (va1 != va2) {
    1.34 +				/* maximum size of uop is 2pages */
    1.35 +				BUG_ON(va2 > va1 + PAGE_SIZE);
    1.36 +				pa2 = ia64_tpa(va2);
    1.37 +			}
    1.38 +		}
    1.39 +	}
    1.40 +	return ____HYPERVISOR_grant_table_op(cmd, uop, count, pa1, pa2);
    1.41  }
    1.42  EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
    1.43  
     2.1 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h	Mon Aug 14 13:46:05 2006 -0600
     2.2 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h	Mon Aug 14 14:21:21 2006 -0600
     2.3 @@ -275,9 +275,10 @@ HYPERVISOR_physdev_op(
     2.4  //XXX __HYPERVISOR_grant_table_op is used for this hypercall constant.
     2.5  static inline int
     2.6  ____HYPERVISOR_grant_table_op(
     2.7 -    unsigned int cmd, void *uop, unsigned int count)
     2.8 +    unsigned int cmd, void *uop, unsigned int count,
     2.9 +    unsigned long pa1, unsigned long pa2)
    2.10  {
    2.11 -    return _hypercall3(int, grant_table_op, cmd, uop, count);
    2.12 +    return _hypercall5(int, grant_table_op, cmd, uop, count, pa1, pa2);
    2.13  }
    2.14  
    2.15  int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count);
     3.1 --- a/xen/arch/ia64/xen/hypercall.c	Mon Aug 14 13:46:05 2006 -0600
     3.2 +++ b/xen/arch/ia64/xen/hypercall.c	Mon Aug 14 14:21:21 2006 -0600
     3.3 @@ -105,6 +105,19 @@ static IA64FAULT
     3.4  xen_hypercall (struct pt_regs *regs)
     3.5  {
     3.6  	uint32_t cmd = (uint32_t)regs->r2;
     3.7 +	struct vcpu *v = current;
     3.8 +
     3.9 +	if (cmd == __HYPERVISOR_grant_table_op) {
    3.10 +		XEN_GUEST_HANDLE(void) uop;
    3.11 +
    3.12 +		v->arch.hypercall_param.va = regs->r15;
    3.13 +		v->arch.hypercall_param.pa1 = regs->r17;
    3.14 +		v->arch.hypercall_param.pa2 = regs->r18;
    3.15 +		set_xen_guest_handle(uop, (void *)regs->r15);
    3.16 +		regs->r8 = do_grant_table_op(regs->r14, uop, regs->r16);
    3.17 +		v->arch.hypercall_param.va = 0;
    3.18 +		return IA64_NO_FAULT;
    3.19 +	}
    3.20  
    3.21  	if (cmd < NR_hypercalls) {
    3.22  		perfc_incra(hypercalls, cmd);
     4.1 --- a/xen/arch/ia64/xen/vcpu.c	Mon Aug 14 13:46:05 2006 -0600
     4.2 +++ b/xen/arch/ia64/xen/vcpu.c	Mon Aug 14 14:21:21 2006 -0600
     4.3 @@ -2215,3 +2215,28 @@ IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 v
     4.4  
     4.5  	return IA64_NO_FAULT;
     4.6  }
     4.7 +
     4.8 +int ia64_map_hypercall_param(void)
     4.9 +{
    4.10 +	struct vcpu *v = current;
    4.11 +	struct domain *d = current->domain;
    4.12 +	u64 vaddr = v->arch.hypercall_param.va & PAGE_MASK;
    4.13 +	volatile pte_t* pte;
    4.14 +
    4.15 +	if (v->arch.hypercall_param.va == 0)
    4.16 +		return FALSE;
    4.17 +	pte = lookup_noalloc_domain_pte(d, v->arch.hypercall_param.pa1);
    4.18 +	if (!pte || !pte_present(*pte))
    4.19 +		return FALSE;
    4.20 +	vcpu_itc_no_srlz(v, 2, vaddr, pte_val(*pte), -1UL, PAGE_SHIFT);
    4.21 +	if (v->arch.hypercall_param.pa2) {
    4.22 +		vaddr += PAGE_SIZE;
    4.23 +		pte = lookup_noalloc_domain_pte(d, v->arch.hypercall_param.pa2);
    4.24 +		if (pte && pte_present(*pte)) {
    4.25 +			vcpu_itc_no_srlz(v, 2, vaddr, pte_val(*pte),
    4.26 +			                 -1UL, PAGE_SHIFT);
    4.27 +		}
    4.28 +	}
    4.29 +	ia64_srlz_d();
    4.30 +	return TRUE;
    4.31 +}
     5.1 --- a/xen/include/asm-ia64/domain.h	Mon Aug 14 13:46:05 2006 -0600
     5.2 +++ b/xen/include/asm-ia64/domain.h	Mon Aug 14 14:21:21 2006 -0600
     5.3 @@ -142,6 +142,12 @@ struct arch_domain {
     5.4      (sizeof(vcpu_info_t) * (v)->vcpu_id + \
     5.5      offsetof(vcpu_info_t, evtchn_upcall_mask))
     5.6  
     5.7 +struct hypercall_param {
     5.8 +    unsigned long va;
     5.9 +    unsigned long pa1;
    5.10 +    unsigned long pa2;
    5.11 +};
    5.12 +
    5.13  struct arch_vcpu {
    5.14      /* Save the state of vcpu.
    5.15         This is the first entry to speed up accesses.  */
    5.16 @@ -185,6 +191,9 @@ struct arch_vcpu {
    5.17      char irq_new_pending;
    5.18      char irq_new_condition;    // vpsr.i/vtpr change, check for pending VHPI
    5.19      char hypercall_continuation;
    5.20 +
    5.21 +    struct hypercall_param hypercall_param;  // used to remap a hypercall param
    5.22 +
    5.23      //for phycial  emulation
    5.24      unsigned long old_rsc;
    5.25      int mode_flags;
     6.1 --- a/xen/include/asm-ia64/uaccess.h	Mon Aug 14 13:46:05 2006 -0600
     6.2 +++ b/xen/include/asm-ia64/uaccess.h	Mon Aug 14 14:21:21 2006 -0600
     6.3 @@ -211,16 +211,30 @@ extern void __put_user_unknown (void);
     6.4  extern unsigned long __must_check __copy_user (void __user *to, const void __user *from,
     6.5  					       unsigned long count);
     6.6  
     6.7 +extern int ia64_map_hypercall_param(void);
     6.8 +
     6.9  static inline unsigned long
    6.10  __copy_to_user (void __user *to, const void *from, unsigned long count)
    6.11  {
    6.12 -	return __copy_user(to, (void __user *) from, count);
    6.13 +	unsigned long len;
    6.14 +	len = __copy_user(to, (void __user *)from, count);
    6.15 +	if (len == 0)
    6.16 +		return 0;
    6.17 +	if (ia64_map_hypercall_param())
    6.18 +		len = __copy_user(to, (void __user *)from, count); /* retry */
    6.19 +	return len;
    6.20  }
    6.21  
    6.22  static inline unsigned long
    6.23  __copy_from_user (void *to, const void __user *from, unsigned long count)
    6.24  {
    6.25 -	return __copy_user((void __user *) to, from, count);
    6.26 +	unsigned long len;
    6.27 +	len = __copy_user((void __user *)to, from, count);
    6.28 +	if (len == 0)
    6.29 +		return 0;
    6.30 +	if (ia64_map_hypercall_param())
    6.31 +		len = __copy_user((void __user *) to, from, count); /* retry */
    6.32 +	return len;
    6.33  }
    6.34  
    6.35  #define __copy_to_user_inatomic		__copy_to_user