[IA64] vti save-restore: hvm domain io page clean up.

- set_hvm_param hypercall clean up.
- The reference counts of the io pages must be incremented.
- Buffered pio wasn't SMP safe.
- Clean up get_vio() parameter.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
This commit is contained in:
Alex Williamson committed 2007-11-07 10:31:09 -07:00
1 parent 90c0baa8e8
commit 4b7a0cb986
6 files changed
+172 -48

No files matched your search

+18 -9
View File
@@ -56,7 +56,7 @@ static int hvm_buffered_io_intercept(ioreq_t *p)
{
struct vcpu *v = current;
buffered_iopage_t *pg =
(buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va);
(buffered_iopage_t *)(v->domain->arch.hvm_domain.buf_ioreq.va);
buf_ioreq_t bp;
int i, qw = 0;
@@ -101,7 +101,7 @@ static int hvm_buffered_io_intercept(ioreq_t *p)
bp.data = p->data;
bp.addr = p->addr;
spin_lock(&v->domain->arch.hvm_domain.buffered_io_lock);
spin_lock(&v->domain->arch.hvm_domain.buf_ioreq.lock);
if (pg->write_pointer - pg->read_pointer >= IOREQ_BUFFER_SLOT_NUM - qw) {
/* the queue is full.
@@ -109,7 +109,7 @@ static int hvm_buffered_io_intercept(ioreq_t *p)
* NOTE: The arithimetic operation could handle the situation for
* write_pointer overflow.
*/
spin_unlock(&v->domain->arch.hvm_domain.buffered_io_lock);
spin_unlock(&v->domain->arch.hvm_domain.buf_ioreq.lock);
return 0;
}
@@ -126,7 +126,7 @@ static int hvm_buffered_io_intercept(ioreq_t *p)
wmb();
pg->write_pointer += qw ? 2 : 1;
spin_unlock(&v->domain->arch.hvm_domain.buffered_io_lock);
spin_unlock(&v->domain->arch.hvm_domain.buf_ioreq.lock);
return 1;
}
@@ -137,7 +137,7 @@ static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
vcpu_iodata_t *vio;
ioreq_t *p;
vio = get_vio(v->domain, v->vcpu_id);
vio = get_vio(v);
if (!vio)
panic_domain(NULL, "bad shared page");
@@ -174,7 +174,8 @@ static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
static int vmx_ide_pio_intercept(ioreq_t *p, u64 *val)
{
struct buffered_piopage *pio_page =
(void *)(current->domain->arch.hvm_domain.buffered_pio_va);
(void *)(current->domain->arch.hvm_domain.buf_pioreq.va);
spinlock_t *pio_lock;
struct pio_buffer *piobuf;
uint32_t pointer, page_offset;
@@ -188,14 +189,17 @@ static int vmx_ide_pio_intercept(ioreq_t *p, u64 *val)
if (p->size != 2 && p->size != 4)
return 0;
pio_lock = &current->domain->arch.hvm_domain.buf_pioreq.lock;
spin_lock(pio_lock);
pointer = piobuf->pointer;
page_offset = piobuf->page_offset;
/* sanity check */
if (page_offset + pointer < offsetof(struct buffered_piopage, buffer))
return 0;
goto unlock_out;
if (page_offset + piobuf->data_end > PAGE_SIZE)
return 0;
goto unlock_out;
if (pointer + p->size < piobuf->data_end) {
uint8_t *bufp = (uint8_t *)pio_page + page_offset + pointer;
@@ -213,10 +217,15 @@ static int vmx_ide_pio_intercept(ioreq_t *p, u64 *val)
}
}
piobuf->pointer += p->size;
spin_unlock(pio_lock);
p->state = STATE_IORESP_READY;
vmx_io_assist(current);
return 1;
}
unlock_out:
spin_unlock(pio_lock);
return 0;
}
@@ -258,7 +267,7 @@ static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
vcpu_iodata_t *vio;
ioreq_t *p;
vio = get_vio(v->domain, v->vcpu_id);
vio = get_vio(v);
if (!vio)
panic_domain(NULL, "bad shared page\n");
+28 -2
View File
@@ -133,8 +133,34 @@ do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
return -EPERM;
if (op == HVMOP_set_param) {
d->arch.hvm_domain.params[a.index] = a.value;
rc = 0;
struct vmx_ioreq_page *iorp;
struct vcpu *v;
switch (a.index) {
case HVM_PARAM_IOREQ_PFN:
iorp = &d->arch.hvm_domain.ioreq;
rc = vmx_set_ioreq_page(d, iorp, a.value);
spin_lock(&iorp->lock);
if (rc == 0 && iorp->va != NULL)
/* Initialise evtchn port info if VCPUs already created. */
for_each_vcpu(d, v)
get_vio(v)->vp_eport = v->arch.arch_vmx.xen_port;
spin_unlock(&iorp->lock);
break;
case HVM_PARAM_BUFIOREQ_PFN:
iorp = &d->arch.hvm_domain.buf_ioreq;
rc = vmx_set_ioreq_page(d, iorp, a.value);
break;
case HVM_PARAM_BUFPIOREQ_PFN:
iorp = &d->arch.hvm_domain.buf_pioreq;
rc = vmx_set_ioreq_page(d, iorp, a.value);
break;
default:
/* nothing */
break;
}
if (rc == 0)
d->arch.hvm_domain.params[a.index] = a.value;
}
else {
a.value = d->arch.hvm_domain.params[a.index];
+102 -24
View File
@@ -267,22 +267,44 @@ vmx_load_state(struct vcpu *v)
* anchored in vcpu */
}
static void vmx_create_event_channels(struct vcpu *v)
static int
vmx_vcpu_initialise(struct vcpu *v)
{
struct vmx_ioreq_page *iorp = &v->domain->arch.hvm_domain.ioreq;
int rc = alloc_unbound_xen_event_channel(v, 0);
if (rc < 0)
return rc;
v->arch.arch_vmx.xen_port = rc;
spin_lock(&iorp->lock);
if (v->domain->arch.vmx_platform.ioreq.va != 0) {
vcpu_iodata_t *p = get_vio(v);
p->vp_eport = v->arch.arch_vmx.xen_port;
}
spin_unlock(&iorp->lock);
gdprintk(XENLOG_INFO, "Allocated port %ld for hvm %d vcpu %d.\n",
v->arch.arch_vmx.xen_port, v->domain->domain_id, v->vcpu_id);
return 0;
}
static int vmx_create_event_channels(struct vcpu *v)
{
vcpu_iodata_t *p;
struct vcpu *o;
if (v->vcpu_id == 0) {
/* Ugly: create event channels for every vcpu when vcpu 0
starts, so that they're available for ioemu to bind to. */
for_each_vcpu(v->domain, o) {
p = get_vio(v->domain, o->vcpu_id);
o->arch.arch_vmx.xen_port = p->vp_eport =
alloc_unbound_xen_event_channel(o, 0);
gdprintk(XENLOG_INFO, "Allocated port %ld for hvm.\n",
o->arch.arch_vmx.xen_port);
int rc = vmx_vcpu_initialise(o);
if (rc < 0) //XXX error recovery
return rc;
}
}
return 0;
}
/*
@@ -294,6 +316,67 @@ static void vmx_release_assist_channel(struct vcpu *v)
return;
}
/* following three functions are based from hvm_xxx_ioreq_page()
* in xen/arch/x86/hvm/hvm.c */
static void vmx_init_ioreq_page(
struct domain *d, struct vmx_ioreq_page *iorp)
{
memset(iorp, 0, sizeof(*iorp));
spin_lock_init(&iorp->lock);
domain_pause(d);
}
static void vmx_destroy_ioreq_page(
struct domain *d, struct vmx_ioreq_page *iorp)
{
spin_lock(&iorp->lock);
ASSERT(d->is_dying);
if (iorp->va != NULL) {
put_page(iorp->page);
iorp->page = NULL;
iorp->va = NULL;
}
spin_unlock(&iorp->lock);
}
int vmx_set_ioreq_page(
struct domain *d, struct vmx_ioreq_page *iorp, unsigned long gpfn)
{
struct page_info *page;
unsigned long mfn;
pte_t pte;
pte = *lookup_noalloc_domain_pte(d, gpfn << PAGE_SHIFT);
if (!pte_present(pte) || !pte_mem(pte))
return -EINVAL;
mfn = (pte_val(pte) & _PFN_MASK) >> PAGE_SHIFT;
ASSERT(mfn_valid(mfn));
page = mfn_to_page(mfn);
if (get_page(page, d) == 0)
return -EINVAL;
spin_lock(&iorp->lock);
if ((iorp->va != NULL) || d->is_dying) {
spin_unlock(&iorp->lock);
put_page(page);
return -EINVAL;
}
iorp->va = mfn_to_virt(mfn);
iorp->page = page;
spin_unlock(&iorp->lock);
domain_unpause(d);
return 0;
}
/*
* Initialize VMX envirenment for guest. Only the 1st vp/vcpu
* is registered here.
@@ -320,7 +403,10 @@ vmx_final_setup_guest(struct vcpu *v)
rc = init_domain_tlb(v);
if (rc)
return rc;
vmx_create_event_channels(v);
rc = vmx_create_event_channels(v);
if (rc)
return rc;
/* v->arch.schedule_tail = arch_vmx_do_launch; */
vmx_create_vp(v);
@@ -352,6 +438,10 @@ vmx_relinquish_guest_resources(struct domain *d)
vmx_release_assist_channel(v);
vacpi_relinquish_resources(d);
vmx_destroy_ioreq_page(d, &d->arch.vmx_platform.ioreq);
vmx_destroy_ioreq_page(d, &d->arch.vmx_platform.buf_ioreq);
vmx_destroy_ioreq_page(d, &d->arch.vmx_platform.buf_pioreq);
}
void
@@ -397,26 +487,14 @@ static void vmx_build_io_physmap_table(struct domain *d)
int vmx_setup_platform(struct domain *d)
{
unsigned long mpa;
ASSERT(d != dom0); /* only for non-privileged vti domain */
vmx_build_io_physmap_table(d);
mpa = __gpa_to_mpa(d, IO_PAGE_START);
if (mpa == 0)
return -EINVAL;
d->arch.vmx_platform.shared_page_va = (unsigned long)__va(mpa);
/* For buffered IO requests. */
spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
vmx_init_ioreq_page(d, &d->arch.vmx_platform.ioreq);
vmx_init_ioreq_page(d, &d->arch.vmx_platform.buf_ioreq);
vmx_init_ioreq_page(d, &d->arch.vmx_platform.buf_pioreq);
mpa = __gpa_to_mpa(d, BUFFER_IO_PAGE_START);
if (mpa == 0)
return -EINVAL;
d->arch.hvm_domain.buffered_io_va = (unsigned long)__va(mpa);
mpa = __gpa_to_mpa(d, BUFFER_PIO_PAGE_START);
if (mpa == 0)
return -EINVAL;
d->arch.hvm_domain.buffered_pio_va = (unsigned long)__va(mpa);
/* TEMP */
d->arch.vmx_platform.pib_base = 0xfee00000UL;
@@ -445,7 +523,7 @@ void vmx_do_resume(struct vcpu *v)
/* stolen from hvm_do_resume() in arch/x86/hvm/hvm.c */
/* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
p = &get_vio(v)->vp_ioreq;
while (p->state != STATE_IOREQ_NONE) {
switch (p->state) {
case STATE_IORESP_READY: /* IORESP_READY -> NONE */
+2 -2
View File
@@ -42,7 +42,7 @@ void vmx_io_assist(struct vcpu *v)
* This shared page contains I/O request between emulation code
* and device model.
*/
vio = get_vio(v->domain, v->vcpu_id);
vio = get_vio(v);
if (!vio)
panic_domain(vcpu_regs(v),"Corruption: bad shared page: %lx\n",
(unsigned long)vio);
@@ -65,7 +65,7 @@ void vmx_send_assist_req(struct vcpu *v)
{
ioreq_t *p;
p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
p = &get_vio(v)->vp_ioreq;
if (unlikely(p->state != STATE_IOREQ_NONE)) {
/* This indicates a bug in the device model. Crash the
domain. */
+6 -2
View File
@@ -57,8 +57,12 @@ extern void vmx_send_assist_req(struct vcpu *v);
extern void deliver_pal_init(struct vcpu *vcpu);
extern void vmx_pend_pal_init(struct domain *d);
static inline vcpu_iodata_t *get_vio(struct domain *d, unsigned long cpu)
static inline vcpu_iodata_t *get_vio(struct vcpu *v)
{
return &((shared_iopage_t *)d->arch.vmx_platform.shared_page_va)->vcpu_iodata[cpu];
struct domain *d = v->domain;
shared_iopage_t *p = (shared_iopage_t *)d->arch.vmx_platform.ioreq.va;
ASSERT((v == current) || spin_is_locked(&d->arch.vmx_platform.ioreq.lock));
ASSERT(d->arch.vmx_platform.ioreq.va != NULL);
return &p->vcpu_iodata[v->vcpu_id];
}
#endif /* _ASM_IA64_VT_H */
+16 -9
View File
@@ -43,17 +43,24 @@
* it is not used on ia64 */
#define OS_TYPE_PORT 0xB2
struct vmx_ioreq_page {
spinlock_t lock;
struct page_info *page;
void *va;
};
int vmx_set_ioreq_page(struct domain *d,
struct vmx_ioreq_page *iorp, unsigned long gmfn);
typedef struct virtual_platform_def {
unsigned long gos_type;
unsigned long buffered_io_va;
spinlock_t buffered_io_lock;
unsigned long buffered_pio_va;
unsigned long shared_page_va;
unsigned long pib_base;
unsigned long params[HVM_NR_PARAMS];
unsigned long gos_type;
struct vmx_ioreq_page ioreq;
struct vmx_ioreq_page buf_ioreq;
struct vmx_ioreq_page buf_pioreq;
unsigned long pib_base;
unsigned long params[HVM_NR_PARAMS];
/* One IOSAPIC now... */
struct viosapic viosapic;
struct vacpi vacpi;
struct viosapic viosapic;
struct vacpi vacpi;
} vir_plat_t;
static inline int __fls(uint32_t word)
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.