ia64/linux-2.6.18-xen.hg

changeset 197:e1466633683c

[IA64] Foreign p2m: linux side

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Thu Sep 06 14:33:25 2007 -0600 (2007-09-06)
parents d796a96253a2
children 8aa8af371be0
files arch/ia64/xen/hypervisor.c arch/ia64/xen/xcom_hcall.c arch/ia64/xen/xcom_privcmd.c include/asm-ia64/hypercall.h include/asm-ia64/xen/xcom_hcall.h include/xen/interface/arch-ia64.h
line diff
     1.1 --- a/arch/ia64/xen/hypervisor.c	Thu Sep 06 12:05:58 2007 -0600
     1.2 +++ b/arch/ia64/xen/hypervisor.c	Thu Sep 06 14:33:25 2007 -0600
     1.3 @@ -584,6 +584,10 @@ struct xen_ia64_privcmd_range {
     1.4  	unsigned long			pgoff; // in PAGE_SIZE
     1.5  	struct resource*		res;
     1.6  
     1.7 +	// for foreign domain p2m mapping
     1.8 +	void*				private;
     1.9 +	void (*callback)(struct xen_ia64_privcmd_range* range, void* arg);
    1.10 +
    1.11  	unsigned long			num_entries;
    1.12  	struct xen_ia64_privcmd_entry	entries[0];
    1.13  };
    1.14 @@ -765,6 +769,9 @@ xen_ia64_privcmd_vma_close(struct vm_are
    1.15  			BUG_ON(entry->gpfn != INVALID_GPFN);
    1.16  		}
    1.17  #endif
    1.18 +		if (privcmd_range->callback)
    1.19 +			(*privcmd_range->callback)(privcmd_range,
    1.20 +						   privcmd_range->private);
    1.21  		release_resource(privcmd_range->res);
    1.22  		kfree(privcmd_range->res);
    1.23  		vfree(privcmd_range);
    1.24 @@ -825,6 +832,8 @@ privcmd_mmap(struct file * file, struct 
    1.25  	atomic_set(&privcmd_range->ref_count, 1);
    1.26  	privcmd_range->pgoff = vma->vm_pgoff;
    1.27  	privcmd_range->num_entries = num_entries;
    1.28 +	privcmd_range->private = NULL;
    1.29 +	privcmd_range->callback = NULL;
    1.30  	for (i = 0; i < privcmd_range->num_entries; i++) {
    1.31  		xen_ia64_privcmd_init_entry(&privcmd_range->entries[i]);
    1.32  	}
    1.33 @@ -979,6 +988,12 @@ static struct notifier_block p2m_expose_
    1.34  };
    1.35  #endif
    1.36  
    1.37 +static inline unsigned long
    1.38 +p2m_table_size(unsigned long num_pfn)
    1.39 +{
    1.40 +	return ((num_pfn + PTRS_PER_PTE - 1) / PTRS_PER_PTE) << PAGE_SHIFT;
    1.41 +}
    1.42 +
    1.43  static int
    1.44  p2m_expose_init(void)
    1.45  {
    1.46 @@ -1018,8 +1033,7 @@ p2m_expose_init(void)
    1.47  	if (xen_ia64_p2m_expose_use_dtr) {
    1.48  		unsigned long page_size = 0;
    1.49  		unsigned long granule_pfn = 0;
    1.50 -		p2m_size = ((p2m_max_low_pfn - p2m_min_low_pfn +
    1.51 -			     PTRS_PER_PTE - 1) / PTRS_PER_PTE) << PAGE_SHIFT;
    1.52 +		p2m_size = p2m_table_size(p2m_max_low_pfn - p2m_min_low_pfn);
    1.53  		for (i = 0;
    1.54  		     i < sizeof(p2m_page_shifts)/sizeof(p2m_page_shifts[0]);
    1.55  		     i++) {
    1.56 @@ -1036,8 +1050,7 @@ p2m_expose_init(void)
    1.57  			                              granule_pfn);
    1.58  			num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
    1.59  			p2m_expose_size = num_pfn << PAGE_SHIFT;
    1.60 -			p2m_size = ((num_pfn + PTRS_PER_PTE - 1) /
    1.61 -				    PTRS_PER_PTE) << PAGE_SHIFT;
    1.62 +			p2m_size = p2m_table_size(num_pfn);
    1.63  			p2m_size = ROUNDUP(p2m_size, granule_pfn << PAGE_SHIFT);
    1.64  			if (p2m_size == page_size)
    1.65  				break;
    1.66 @@ -1057,8 +1070,7 @@ p2m_expose_init(void)
    1.67  		p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, p2m_granule_pfn);
    1.68  		num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
    1.69  		p2m_expose_size = num_pfn << PAGE_SHIFT;
    1.70 -		p2m_size = ((num_pfn + PTRS_PER_PTE - 1) / PTRS_PER_PTE) <<
    1.71 -			PAGE_SHIFT;
    1.72 +		p2m_size = p2m_table_size(num_pfn);
    1.73  		p2m_size = ROUNDUP(p2m_size, p2m_granule_pfn << PAGE_SHIFT);
    1.74  		align = max(privcmd_resource_align,
    1.75  		            p2m_granule_pfn << PAGE_SHIFT);
    1.76 @@ -1204,6 +1216,205 @@ EXPORT_SYMBOL_GPL(p2m_convert_min_pfn);
    1.77  EXPORT_SYMBOL_GPL(p2m_convert_max_pfn);
    1.78  EXPORT_SYMBOL_GPL(p2m_pte);
    1.79  EXPORT_SYMBOL_GPL(p2m_phystomach);
    1.80 +
    1.81 +///////////////////////////////////////////////////////////////////////////
    1.82 +// foreign domain p2m mapping
    1.83 +#include <asm/xen/xencomm.h>
    1.84 +#include <xen/public/privcmd.h>
    1.85 +
    1.86 +struct foreign_p2m_private {
    1.87 +	unsigned long	gpfn;
    1.88 +	domid_t		domid;
    1.89 +};
    1.90 +
    1.91 +static void
    1.92 +xen_foreign_p2m_unexpose(struct xen_ia64_privcmd_range* privcmd_range,
    1.93 +			 void* arg)
    1.94 +{
    1.95 +	struct foreign_p2m_private* private = (struct foreign_p2m_private*)arg;
    1.96 +	int ret;
    1.97 +
    1.98 +	privcmd_range->private = NULL;
    1.99 +	privcmd_range->callback = NULL;
   1.100 +
   1.101 +	ret = HYPERVISOR_unexpose_foreign_p2m(private->gpfn, private->domid);
   1.102 +	if (ret)
   1.103 +		printk(KERN_WARNING
   1.104 +		       "unexpose_foreign_p2m hypercall failed.\n");
   1.105 +	kfree(private);
   1.106 +}
   1.107 +
   1.108 +int
   1.109 +xen_foreign_p2m_expose(privcmd_hypercall_t* hypercall)
   1.110 +{
   1.111 +	// hypercall->
   1.112 +	// arg0: cmd = IA64_DOM0VP_expose_foreign_p2m
   1.113 +	// arg1: va
   1.114 +	// arg2: domid
   1.115 +	// arg3: __user* memmap_info
   1.116 +	// arg4: flags
   1.117 +
   1.118 +	int ret = 0;
   1.119 +	struct mm_struct* mm = current->mm;
   1.120 +
   1.121 +	unsigned long vaddr = hypercall->arg[1];
   1.122 +	domid_t domid = hypercall->arg[2];
   1.123 +	struct xen_ia64_memmap_info __user *u_memmap_info =
   1.124 +		(struct xen_ia64_memmap_info __user *)hypercall->arg[3];
   1.125 +
   1.126 +	struct xen_ia64_memmap_info memmap_info;
   1.127 +	size_t memmap_size;
   1.128 +	struct xen_ia64_memmap_info* k_memmap_info = NULL;
   1.129 +	unsigned long max_gpfn;
   1.130 +	unsigned long p2m_size;
   1.131 +	struct resource* res;
   1.132 +	unsigned long gpfn;
   1.133 +
   1.134 +	struct vm_area_struct* vma;
   1.135 +	void* p;
   1.136 +	unsigned long prev_src_gpfn_end;
   1.137 +
   1.138 +	struct xen_ia64_privcmd_vma* privcmd_vma;
   1.139 +	struct xen_ia64_privcmd_range* privcmd_range;
   1.140 +	struct foreign_p2m_private* private = NULL;
   1.141 +
   1.142 +	BUG_ON(hypercall->arg[0] != IA64_DOM0VP_expose_foreign_p2m);
   1.143 +
   1.144 +	private = kmalloc(sizeof(*private), GFP_KERNEL);
   1.145 +	if (private == NULL)
   1.146 +		goto kfree_out;
   1.147 +
   1.148 +	if (copy_from_user(&memmap_info, u_memmap_info, sizeof(memmap_info)))
   1.149 +		return -EFAULT;
   1.150 +	/* memmap_info integrity check */
   1.151 +	if (memmap_info.efi_memdesc_size < sizeof(efi_memory_desc_t) ||
   1.152 +	    memmap_info.efi_memmap_size < memmap_info.efi_memdesc_size ||
   1.153 +	    (memmap_info.efi_memmap_size % memmap_info.efi_memdesc_size)
   1.154 +	    != 0) {
   1.155 +		ret = -EINVAL;
   1.156 +		goto kfree_out;
   1.157 +	}
   1.158 +
   1.159 +	memmap_size = sizeof(*k_memmap_info) + memmap_info.efi_memmap_size;
   1.160 +	k_memmap_info = kmalloc(memmap_size, GFP_KERNEL);
   1.161 +	if (k_memmap_info == NULL)
   1.162 +		return -ENOMEM;
   1.163 +	if (copy_from_user(k_memmap_info, u_memmap_info, memmap_size)) {
   1.164 +		ret = -EFAULT;
   1.165 +		goto kfree_out;
   1.166 +	}
   1.167 +	/* k_memmap_info integrity check is done by the expose foreng p2m 
   1.168 +	   hypercall */
   1.169 +
   1.170 +	max_gpfn = HYPERVISOR_memory_op(XENMEM_maximum_gpfn, &domid);
   1.171 +	if (max_gpfn < 0) {
   1.172 +		ret = max_gpfn;
   1.173 +		goto kfree_out;
   1.174 +	}
   1.175 +	p2m_size = p2m_table_size(max_gpfn + 1);
   1.176 +
   1.177 +	down_write(&mm->mmap_sem);
   1.178 +
   1.179 +	vma = find_vma(mm, vaddr);
   1.180 +	if (vma == NULL || vma->vm_ops != &xen_ia64_privcmd_vm_ops ||
   1.181 +	    vaddr != vma->vm_start ||
   1.182 +	    (vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_EXEC) ||
   1.183 +	    !privcmd_enforce_singleshot_mapping(vma))
   1.184 +		goto mmap_out;
   1.185 +
   1.186 +	privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
   1.187 +	res = privcmd_vma->range->res;
   1.188 +	if (p2m_size > (res->end - res->start + 1) ||
   1.189 +	    p2m_size > vma->vm_end - vma->vm_start) {
   1.190 +		ret = -EINVAL;
   1.191 +		goto mmap_out;
   1.192 +	}
   1.193 +	
   1.194 +	gpfn = res->start >> PAGE_SHIFT;
   1.195 +	// arg0: dest_gpfn
   1.196 +	// arg1: domid
   1.197 +	// arg2: XEN_GUEST_HANDLE(char) buffer: memmap_info
   1.198 +	// arg3: flags
   1.199 +	// The hypercall checks its intergirty/simplfies it and 
   1.200 +	// copy it back for us.
   1.201 +	ret = xencomm_arch_expose_foreign_p2m(gpfn, domid,
   1.202 +	      xencomm_map_no_alloc(k_memmap_info, memmap_size),
   1.203 +	      hypercall->arg[4]);
   1.204 +	if (ret)
   1.205 +		goto mmap_out;
   1.206 +
   1.207 +	privcmd_range = (struct xen_ia64_privcmd_range*)privcmd_vma->range;
   1.208 +	prev_src_gpfn_end = 0;
   1.209 +	for (p = k_memmap_info->memdesc;
   1.210 +	     p < (void*)&k_memmap_info->memdesc[0] +
   1.211 +		     k_memmap_info->efi_memmap_size;
   1.212 +	     p += k_memmap_info->efi_memdesc_size) {
   1.213 +		efi_memory_desc_t* md = p;
   1.214 +		unsigned long src_gpfn = md->phys_addr >> PAGE_SHIFT;
   1.215 +		unsigned long src_gpfn_end =
   1.216 +			(md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >>
   1.217 +			PAGE_SHIFT;
   1.218 +		unsigned long num_src_gpfn;
   1.219 +		unsigned long gpfn_offset;
   1.220 +		unsigned long size;
   1.221 +		unsigned int i;
   1.222 +
   1.223 +		if (src_gpfn <= prev_src_gpfn_end)
   1.224 +			src_gpfn = prev_src_gpfn_end + 1;
   1.225 +		if (src_gpfn_end <= prev_src_gpfn_end)
   1.226 +			continue;
   1.227 +
   1.228 +		src_gpfn &= ~(PTRS_PER_PTE - 1);
   1.229 +		src_gpfn_end = (src_gpfn_end + PTRS_PER_PTE - 1) &
   1.230 +			~(PTRS_PER_PTE - 1);
   1.231 +		num_src_gpfn = src_gpfn_end - src_gpfn;
   1.232 +		gpfn_offset = src_gpfn / PTRS_PER_PTE;
   1.233 +		size = p2m_table_size(num_src_gpfn);
   1.234 +
   1.235 +		prev_src_gpfn_end = src_gpfn_end;
   1.236 +		ret = remap_pfn_range(vma,
   1.237 +				      vaddr + (gpfn_offset << PAGE_SHIFT), 
   1.238 +				      gpfn + gpfn_offset, size,
   1.239 +				      vma->vm_page_prot);
   1.240 +		if (ret) {
   1.241 +			for (i = 0; i < gpfn + gpfn_offset; i++) {
   1.242 +				struct xen_ia64_privcmd_entry* entry =
   1.243 +					&privcmd_range->entries[i];
   1.244 +				BUG_ON(atomic_read(&entry->map_count) != 1 &&
   1.245 +				       atomic_read(&entry->map_count) != 0);
   1.246 +				atomic_set(&entry->map_count, 0);
   1.247 +				entry->gpfn = INVALID_GPFN;
   1.248 +			}
   1.249 +			(void)HYPERVISOR_unexpose_foreign_p2m(gpfn, domid);
   1.250 +			goto mmap_out;
   1.251 +		}
   1.252 +
   1.253 +		for (i = gpfn_offset;
   1.254 +		     i < gpfn_offset + (size >> PAGE_SHIFT);
   1.255 +		     i++) {
   1.256 +			struct xen_ia64_privcmd_entry* entry =
   1.257 +				&privcmd_range->entries[i];
   1.258 +			BUG_ON(atomic_read(&entry->map_count) != 0);
   1.259 +			BUG_ON(entry->gpfn != INVALID_GPFN);
   1.260 +			atomic_inc(&entry->map_count);
   1.261 +			entry->gpfn = gpfn + i;
   1.262 +		}
   1.263 +	}
   1.264 +
   1.265 +	private->gpfn = gpfn;
   1.266 +	private->domid = domid;
   1.267 +
   1.268 +	privcmd_range->callback = &xen_foreign_p2m_unexpose;
   1.269 +	privcmd_range->private = private;
   1.270 +
   1.271 +mmap_out:
   1.272 +	up_write(&mm->mmap_sem);
   1.273 +kfree_out:
   1.274 +	kfree(k_memmap_info);
   1.275 +	if (ret != 0)
   1.276 +		kfree(private);
   1.277 +	return ret;
   1.278 +}
   1.279  #endif
   1.280  
   1.281  ///////////////////////////////////////////////////////////////////////////
     2.1 --- a/arch/ia64/xen/xcom_hcall.c	Thu Sep 06 12:05:58 2007 -0600
     2.2 +++ b/arch/ia64/xen/xcom_hcall.c	Thu Sep 06 14:33:25 2007 -0600
     2.3 @@ -381,7 +381,11 @@ xencomm_hypercall_memory_op(unsigned int
     2.4  			return rc;
     2.5  		xc_area++;
     2.6  		break;
     2.7 -		
     2.8 +
     2.9 +	case XENMEM_maximum_gpfn:
    2.10 +		argsize = 0;
    2.11 +		break;
    2.12 +
    2.13  	case XENMEM_maximum_ram_page:
    2.14  		argsize = 0;
    2.15  		break;
     3.1 --- a/arch/ia64/xen/xcom_privcmd.c	Thu Sep 06 12:05:58 2007 -0600
     3.2 +++ b/arch/ia64/xen/xcom_privcmd.c	Thu Sep 06 14:33:25 2007 -0600
     3.3 @@ -732,6 +732,9 @@ xencomm_privcmd_ia64_dom0vp_op(privcmd_h
     3.4  			ret = -EFAULT;
     3.5  		break;
     3.6  	}
     3.7 +	case IA64_DOM0VP_expose_foreign_p2m:
     3.8 +		ret = xen_foreign_p2m_expose(hypercall);
     3.9 +		break;
    3.10  	default:
    3.11  		printk("%s: unknown IA64 DOM0VP op %d\n", __func__, cmd);
    3.12  		ret = -EINVAL;
     4.1 --- a/include/asm-ia64/hypercall.h	Thu Sep 06 12:05:58 2007 -0600
     4.2 +++ b/include/asm-ia64/hypercall.h	Thu Sep 06 14:33:25 2007 -0600
     4.3 @@ -374,6 +374,23 @@ HYPERVISOR_expose_p2m(unsigned long conv
     4.4  	                   IA64_DOM0VP_expose_p2m, conv_start_gpfn,
     4.5  	                   assign_start_gpfn, expose_size, granule_pfn);
     4.6  }
     4.7 +
     4.8 +static inline int
     4.9 +xencomm_arch_expose_foreign_p2m(unsigned long gpfn,
    4.10 +				domid_t domid, struct xencomm_handle *arg,
    4.11 +				unsigned long flags)
    4.12 +{
    4.13 +	return _hypercall5(int, ia64_dom0vp_op,
    4.14 +			   IA64_DOM0VP_expose_foreign_p2m,
    4.15 +			   gpfn, domid, arg, flags);
    4.16 +}
    4.17 +
    4.18 +static inline int
    4.19 +HYPERVISOR_unexpose_foreign_p2m(unsigned long gpfn, domid_t domid)
    4.20 +{
    4.21 +	return _hypercall3(int, ia64_dom0vp_op,
    4.22 +			   IA64_DOM0VP_unexpose_foreign_p2m, gpfn, domid);
    4.23 +}
    4.24  #endif
    4.25  
    4.26  static inline int
     5.1 --- a/include/asm-ia64/xen/xcom_hcall.h	Thu Sep 06 12:05:58 2007 -0600
     5.2 +++ b/include/asm-ia64/xen/xcom_hcall.h	Thu Sep 06 14:33:25 2007 -0600
     5.3 @@ -60,4 +60,6 @@ extern long xencomm_hypercall_opt_featur
     5.4  struct privcmd_hypercall;
     5.5  extern int privcmd_hypercall(struct privcmd_hypercall *hypercall);
     5.6  
     5.7 +extern int xen_foreign_p2m_expose(struct privcmd_hypercall *hypercall);
     5.8 +
     5.9  #endif /* _LINUX_XENCOMM_HCALL_H_ */
     6.1 --- a/include/xen/interface/arch-ia64.h	Thu Sep 06 12:05:58 2007 -0600
     6.2 +++ b/include/xen/interface/arch-ia64.h	Thu Sep 06 14:33:25 2007 -0600
     6.3 @@ -470,6 +470,13 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_conte
     6.4  /* Add an I/O port space range */
     6.5  #define IA64_DOM0VP_add_io_space        11
     6.6  
     6.7 +/* expose the foreign domain's p2m table into privileged domain */
     6.8 +#define IA64_DOM0VP_expose_foreign_p2m  12
     6.9 +#define         IA64_DOM0VP_EFP_ALLOC_PTE       0x1 /* allocate p2m table */
    6.10 +
    6.11 +/* unexpose the foreign domain's p2m table into privileged domain */
    6.12 +#define IA64_DOM0VP_unexpose_foreign_p2m        13
    6.13 +
    6.14  // flags for page assignement to pseudo physical address space
    6.15  #define _ASSIGN_readonly                0
    6.16  #define ASSIGN_readonly                 (1UL << _ASSIGN_readonly)