From: Keir Fraser Date: Wed, 13 Apr 2011 15:10:26 +0000 (+0100) Subject: x86: make the pv-only e820 array be dynamic. X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=87e0dc6ea0a983ae1dbe1f10c300ac0b89b0f23b;p=xen.git x86: make the pv-only e820 array be dynamic. During creation of the PV domain we allocate the E820 structure to have the amount of E820 entries on the machine, plus the number three. This will allow the tool stack to fill the E820 with more than three entries. Specifically the use cases is , where the toolstack retrieves the E820, sanitizes it, and then sets it for the PV guest (for PCI passthrough), this dynamic number of E820 is just right. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 8d24dbccdc..37c9cd7a54 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -657,6 +657,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) /* 32-bit PV guest by default only if Xen is not 64-bit. */ d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = (CONFIG_PAGING_LEVELS != 4); + + spin_lock_init(&d->arch.pv_domain.e820_lock); } /* initialize default tsc behavior in case tools don't */ @@ -696,6 +698,8 @@ void arch_domain_destroy(struct domain *d) if ( is_hvm_domain(d) ) hvm_domain_destroy(d); + else + xfree(d->arch.pv_domain.e820); vmce_destroy_msr(d); pci_release_devices(d); diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 4ef5228c83..3ddbfaa515 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -4713,11 +4714,12 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) { struct xen_foreign_memory_map fmap; struct domain *d; + struct e820entry *e820; if ( copy_from_guest(&fmap, arg, 1) ) return -EFAULT; - if ( fmap.map.nr_entries > ARRAY_SIZE(d->arch.pv_domain.e820) ) + if ( fmap.map.nr_entries > E820MAX ) return -EINVAL; rc = rcu_lock_target_domain_by_id(fmap.domid, &d); @@ -4737,9 +4739,25 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) return -EPERM; } - rc = copy_from_guest(d->arch.pv_domain.e820, fmap.map.buffer, - fmap.map.nr_entries) ? -EFAULT : 0; + e820 = xmalloc_array(e820entry_t, fmap.map.nr_entries); + if ( e820 == NULL ) + { + rcu_unlock_domain(d); + return -ENOMEM; + } + + if ( copy_from_guest(e820, fmap.map.buffer, fmap.map.nr_entries) ) + { + xfree(e820); + rcu_unlock_domain(d); + return -EFAULT; + } + + spin_lock(&d->arch.pv_domain.e820_lock); + xfree(d->arch.pv_domain.e820); + d->arch.pv_domain.e820 = e820; d->arch.pv_domain.nr_e820 = fmap.map.nr_entries; + spin_unlock(&d->arch.pv_domain.e820_lock); rcu_unlock_domain(d); return rc; @@ -4750,19 +4768,29 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) struct xen_memory_map map; struct domain *d = current->domain; - /* Backwards compatibility. */ - if ( d->arch.pv_domain.nr_e820 == 0 ) - return -ENOSYS; - if ( copy_from_guest(&map, arg, 1) ) return -EFAULT; + spin_lock(&d->arch.pv_domain.e820_lock); + + /* Backwards compatibility. */ + if ( (d->arch.pv_domain.nr_e820 == 0) || + (d->arch.pv_domain.e820 == NULL) ) + { + spin_unlock(&d->arch.pv_domain.e820_lock); + return -ENOSYS; + } + map.nr_entries = min(map.nr_entries, d->arch.pv_domain.nr_e820); if ( copy_to_guest(map.buffer, d->arch.pv_domain.e820, map.nr_entries) || copy_to_guest(arg, &map, 1) ) + { + spin_unlock(&d->arch.pv_domain.e820_lock); return -EFAULT; + } + spin_unlock(&d->arch.pv_domain.e820_lock); return 0; } diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 0df43726f1..244338ac6b 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -241,7 +241,8 @@ struct pv_domain unsigned long pirq_eoi_map_mfn; /* Pseudophysical e820 map (XENMEM_memory_map). */ - struct e820entry e820[3]; + spinlock_t e820_lock; + struct e820entry *e820; unsigned int nr_e820; };