mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
[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:
1 parent
90c0baa8e8
commit
4b7a0cb986
6 files changed
+172
-48
No files matched your search
@@ -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 = ¤t->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");
|
||||
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
|
||||