hvm: Xen must take care to hold a reference to ioreq pages, to ensure

that domain runs only when it has valid mapped ioreq pages, and to
safely drop ioreq page references when a domain dies.
Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kfraser@localhost.localdomain committed 2007-04-13 12:29:06 +01:00
1 parent da12cd1e94
commit 20a553aca3
6 files changed
+111 -36

No files matched your search

+3 -1
View File
@@ -1540,8 +1540,10 @@ void domain_relinquish_resources(struct domain *d)
relinquish_memory(d, &d->xenpage_list, PGT_l2_page_table);
relinquish_memory(d, &d->page_list, PGT_l2_page_table);
/* Free page used by xen oprofile buffer */
/* Free page used by xen oprofile buffer. */
free_xenoprof_pages(d);
hvm_domain_relinquish_resources(d);
}
void arch_dump_domain_info(struct domain *d)
+74 -32
View File
@@ -146,6 +146,59 @@ void hvm_do_resume(struct vcpu *v)
}
}
static void hvm_clear_ioreq_pfn(
struct domain *d, unsigned long *pva)
{
unsigned long va, mfn;
BUG_ON(!d->is_dying);
if ( (va = xchg(pva, 0UL)) == 0UL )
return;
mfn = mfn_from_mapped_domain_page((void *)va);
unmap_domain_page_global((void *)va);
put_page_and_type(mfn_to_page(mfn));
}
static int hvm_set_ioreq_pfn(
struct domain *d, unsigned long *pva, unsigned long gmfn)
{
unsigned long mfn;
void *va;
mfn = gmfn_to_mfn(d, gmfn);
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
return -EINVAL;
va = map_domain_page_global(mfn);
if ( va == NULL )
{
put_page_and_type(mfn_to_page(mfn));
return -ENOMEM;
}
if ( cmpxchg(pva, 0UL, (unsigned long)va) != 0UL )
{
unmap_domain_page_global(va);
put_page_and_type(mfn_to_page(mfn));
return -EINVAL;
}
/*
* Check dying status /after/ setting *pva. cmpxchg() is a barrier.
* We race against hvm_domain_relinquish_resources().
*/
if ( d->is_dying )
hvm_clear_ioreq_pfn(d, pva);
/* Balance the domain_pause() in hvm_domain_initialise(). */
domain_unpause(d);
return 0;
}
int hvm_domain_initialise(struct domain *d)
{
int rc;
@@ -161,7 +214,6 @@ int hvm_domain_initialise(struct domain *d)
spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
spin_lock_init(&d->arch.hvm_domain.irq_lock);
/* paging support will be determined inside paging.c */
rc = paging_enable(d, PG_refcounts|PG_translate|PG_external);
if ( rc != 0 )
return rc;
@@ -169,22 +221,25 @@ int hvm_domain_initialise(struct domain *d)
vpic_init(d);
vioapic_init(d);
/* Do not allow domain to run until it has ioreq shared pages. */
domain_pause(d); /* HVM_PARAM_IOREQ_PFN */
domain_pause(d); /* HVM_PARAM_BUFIOREQ_PFN */
return 0;
}
void hvm_domain_relinquish_resources(struct domain *d)
{
hvm_clear_ioreq_pfn(d, &d->arch.hvm_domain.shared_page_va);
hvm_clear_ioreq_pfn(d, &d->arch.hvm_domain.buffered_io_va);
}
void hvm_domain_destroy(struct domain *d)
{
pit_deinit(d);
rtc_deinit(d);
pmtimer_deinit(d);
hpet_deinit(d);
if ( d->arch.hvm_domain.shared_page_va )
unmap_domain_page_global(
(void *)d->arch.hvm_domain.shared_page_va);
if ( d->arch.hvm_domain.buffered_io_va )
unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
}
static int hvm_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
@@ -928,8 +983,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
struct xen_hvm_param a;
struct domain *d;
struct vcpu *v;
unsigned long mfn;
void *p;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
@@ -956,30 +1009,19 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
switch ( a.index )
{
case HVM_PARAM_IOREQ_PFN:
if ( d->arch.hvm_domain.shared_page_va )
goto param_fail;
mfn = gmfn_to_mfn(d, a.value);
if ( mfn == INVALID_MFN )
goto param_fail;
p = map_domain_page_global(mfn);
if ( p == NULL )
goto param_fail;
d->arch.hvm_domain.shared_page_va = (unsigned long)p;
/* Initialise evtchn port info if VCPUs already created. */
for_each_vcpu ( d, v )
get_vio(d, v->vcpu_id)->vp_eport =
v->arch.hvm_vcpu.xen_port;
rc = hvm_set_ioreq_pfn(
d, &d->arch.hvm_domain.shared_page_va, a.value);
if ( rc == 0 )
{
/* Initialise evtchn port info if VCPUs already created. */
for_each_vcpu ( d, v )
get_vio(d, v->vcpu_id)->vp_eport =
v->arch.hvm_vcpu.xen_port;
}
break;
case HVM_PARAM_BUFIOREQ_PFN:
if ( d->arch.hvm_domain.buffered_io_va )
goto param_fail;
mfn = gmfn_to_mfn(d, a.value);
if ( mfn == INVALID_MFN )
goto param_fail;
p = map_domain_page_global(mfn);
if ( p == NULL )
goto param_fail;
d->arch.hvm_domain.buffered_io_va = (unsigned long)p;
rc = hvm_set_ioreq_pfn(
d, &d->arch.hvm_domain.buffered_io_va, a.value);
break;
case HVM_PARAM_CALLBACK_IRQ:
hvm_set_callback_via(d, a.value);
+21
View File
@@ -251,3 +251,24 @@ void unmap_domain_page_global(void *va)
idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT;
set_bit(idx, garbage);
}
unsigned long mfn_from_mapped_domain_page(void *va)
{
unsigned long __va = (unsigned long)va;
l2_pgentry_t *pl2e;
l1_pgentry_t *pl1e;
unsigned int idx;
struct mapcache *cache;
if ( (__va >= MAPCACHE_VIRT_START) && (__va < MAPCACHE_VIRT_END) )
{
cache = &mapcache_current_vcpu()->domain->arch.mapcache;
idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
return l1e_get_pfn(cache->l1tab[idx]);
}
ASSERT(__va >= IOREMAP_VIRT_START);
pl2e = virt_to_xen_l2e(__va);
pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va);
return l1e_get_pfn(*pl1e);
}
+1 -1
View File
@@ -314,7 +314,7 @@ void domain_kill(struct domain *d)
}
/* Tear down state /after/ setting the dying flag. */
smp_wmb();
smp_mb();
gnttab_release_mappings(d);
domain_relinquish_resources(d);
+1
View File
@@ -145,6 +145,7 @@ struct hvm_function_table {
extern struct hvm_function_table hvm_funcs;
int hvm_domain_initialise(struct domain *d);
void hvm_domain_relinquish_resources(struct domain *d);
void hvm_domain_destroy(struct domain *d);
int hvm_vcpu_initialise(struct vcpu *v);
+11 -2
View File
@@ -34,6 +34,13 @@ void unmap_domain_page(void *va);
void *map_domain_page_global(unsigned long mfn);
void unmap_domain_page_global(void *va);
/*
* Convert a VA (within a page previously mapped in the context of the
* currently-executing VCPU via a call to map_domain_page(), or via a
* previous call to map_domain_page_global()) to the mapped page frame.
*/
unsigned long mfn_from_mapped_domain_page(void *va);
#define DMCACHE_ENTRY_VALID 1U
#define DMCACHE_ENTRY_HELD 2U
@@ -96,12 +103,14 @@ domain_mmap_cache_destroy(struct domain_mmap_cache *cache)
#else /* !CONFIG_DOMAIN_PAGE */
#define map_domain_page(mfn) maddr_to_virt((mfn)<<PAGE_SHIFT)
#define map_domain_page(mfn) mfn_to_virt(mfn)
#define unmap_domain_page(va) ((void)(va))
#define map_domain_page_global(mfn) maddr_to_virt((mfn)<<PAGE_SHIFT)
#define map_domain_page_global(mfn) mfn_to_virt(mfn)
#define unmap_domain_page_global(va) ((void)(va))
#define mfn_from_mapped_domain_page(va) virt_to_mfn(va)
struct domain_mmap_cache {
};
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.