# HG changeset patch # User Tristan Gingold # Date 1202795731 -3600 # Node ID 6ba0c3a71fe1e3579e4d07bfa54a26fd8648a7ad # Parent 8bbc0b7b1759314d7c640874e71556479f95b532 Implements Self IO-EMUlator. Hypervisor part. Signed-off-by: Tristan Gingold diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/vmx/Makefile --- a/xen/arch/ia64/vmx/Makefile Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/vmx/Makefile Tue Feb 12 06:55:31 2008 +0100 @@ -21,3 +21,4 @@ obj-y += vacpi.o obj-y += vacpi.o obj-y += vmx_vcpu_save.o obj-y += save.o +obj-y += sioemu.o diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/vmx/mmio.c --- a/xen/arch/ia64/vmx/mmio.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/vmx/mmio.c Tue Feb 12 06:55:31 2008 +0100 @@ -39,6 +39,8 @@ #include #include #include +#include +#include #define HVM_BUFFERED_IO_RANGE_NR 1 @@ -388,6 +390,8 @@ static void mmio_access(VCPU *vcpu, u64 return; } +enum inst_type_en { SL_INTEGER, SL_FLOATING, SL_FLOATING_FP8 }; + /* dir 1: read 0:write */ @@ -396,11 +400,12 @@ void emulate_io_inst(VCPU *vcpu, u64 pad REGS *regs; IA64_BUNDLE bundle; int slot, dir=0; - enum { SL_INTEGER, SL_FLOATING, SL_FLOATING_FP8 } inst_type; + enum inst_type_en inst_type; size_t size; u64 data, data1, temp, update_reg; s32 imm; INST64 inst; + unsigned long update_word; regs = vcpu_regs(vcpu); if (IA64_RETRY == __vmx_get_domain_bundle(regs->cr_iip, &bundle)) { @@ -523,24 +528,54 @@ void emulate_io_inst(VCPU *vcpu, u64 pad inst.inst, regs->cr_iip); } + update_word = size | (dir << 7) | (ma << 8) | (inst_type << 12); + if (dir == IOREQ_READ) { + if (inst_type == SL_INTEGER) + update_word |= (inst.M1.r1 << 16); + else if (inst_type == SL_FLOATING_FP8) + update_word |= (inst.M12.f1 << 16) | (inst.M12.f2 << 24); + } + + if (vcpu->domain->arch.is_sioemu) { + unsigned long iot; + iot = __gpfn_is_io(vcpu->domain, padr >> PAGE_SHIFT); + + if (iot != GPFN_PIB && iot != GPFN_IOSAPIC) { + sioemu_io_emulate (padr, data, data1, update_word); + return; + } + } + if (size == 4) { mmio_access(vcpu, padr + 8, &data1, 1 << 3, ma, dir); size = 3; } mmio_access(vcpu, padr, &data, 1 << size, ma, dir); + emulate_io_update (vcpu, update_word, data, data1); +} + +void +emulate_io_update (VCPU *vcpu, u64 word, u64 data, u64 data1) +{ + int dir = (word >> 7) & 1; + if (dir == IOREQ_READ) { + int r1 = (word >> 16) & 0xff; + int r2 = (word >> 24) & 0xff; + enum inst_type_en inst_type = (word >> 12) & 0x0f; + if (inst_type == SL_INTEGER) { - vcpu_set_gr(vcpu, inst.M1.r1, data, 0); + vcpu_set_gr(vcpu, r1, data, 0); } else if (inst_type == SL_FLOATING_FP8) { struct ia64_fpreg v; v.u.bits[0] = data; v.u.bits[1] = 0x1003E; - vcpu_set_fpreg(vcpu, inst.M12.f1, &v); + vcpu_set_fpreg(vcpu, r1, &v); v.u.bits[0] = data1; v.u.bits[1] = 0x1003E; - vcpu_set_fpreg(vcpu, inst.M12.f2, &v); + vcpu_set_fpreg(vcpu, r2, &v); } else { panic_domain(NULL, "Don't support ldfd now !"); } diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/vmx/sioemu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/vmx/sioemu.c Tue Feb 12 06:55:31 2008 +0100 @@ -0,0 +1,223 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * sioemu.c: Self IO emulation - hypercall and return. + * Copyright (c) 2008, Tristan Gingold + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include + +static REGS * +sioemu_deliver (void) +{ + VCPU *vcpu = current; + REGS *regs = vcpu_regs(vcpu); + unsigned long psr = vmx_vcpu_get_psr(vcpu); + + if (vcpu->vcpu_info->evtchn_upcall_mask) + panic_domain (NULL, "sioemu_deliver: aleady in stub mode\n"); + + /* All cleared, but keep BN. */ + vmx_vcpu_set_psr(vcpu, IA64_PSR_MC | (psr & IA64_PSR_BN)); + + /* Save registers. */ + vcpu->arch.arch_vmx.stub_saved[0] = regs->r16; + vcpu->arch.arch_vmx.stub_saved[1] = regs->r17; + vcpu->arch.arch_vmx.stub_saved[2] = regs->r18; + vcpu->arch.arch_vmx.stub_saved[3] = regs->r19; + vcpu->arch.arch_vmx.stub_saved[4] = regs->r20; + vcpu->arch.arch_vmx.stub_saved[5] = regs->r21; + vcpu->arch.arch_vmx.stub_saved[6] = regs->r22; + vcpu->arch.arch_vmx.stub_saved[7] = regs->r23; + vcpu->arch.arch_vmx.stub_saved[8] = regs->r24; + vcpu->arch.arch_vmx.stub_saved[9] = regs->r25; + vcpu->arch.arch_vmx.stub_saved[10] = regs->r26; + vcpu->arch.arch_vmx.stub_saved[11] = regs->r27; + vcpu->arch.arch_vmx.stub_saved[12] = regs->r28; + vcpu->arch.arch_vmx.stub_saved[13] = regs->r29; + vcpu->arch.arch_vmx.stub_saved[14] = regs->r30; + vcpu->arch.arch_vmx.stub_saved[15] = regs->r31; + vcpu->arch.arch_vmx.stub_nats = + (regs->eml_unat >> IA64_PT_REGS_R16_SLOT) & 0xffff; + + /* Context. */ + regs->r28 = regs->cr_iip; + regs->r29 = psr; + regs->r30 = regs->cr_ifs; + + regs->cr_ifs = 0; // pre-cover + + regs->cr_iip = vcpu->arch.event_callback_ip; + regs->eml_unat &= ~(0xffffUL << IA64_PT_REGS_R16_SLOT); + + /* Parameters. */ + regs->r16 = 0; + regs->r17 = vcpu->arch.arch_vmx.stub_buffer; + + /* Mask events. */ + vcpu->vcpu_info->evtchn_upcall_mask = 1; + + debugger_event(XEN_IA64_DEBUG_ON_EVENT); + + return regs; +} + +void +sioemu_callback_return (void) +{ + VCPU *vcpu = current; + REGS *regs = vcpu_regs(vcpu); + u64 cmd = regs->r16; + u64 arg1 = regs->r19; + u64 arg2 = regs->r20; + u64 arg3 = regs->r21; + + if ((cmd & ~0x1UL) != 0) + panic_domain (NULL, "sioemu_callback_return: bad operation (%lx)\n", cmd); + + /* First restore registers. */ + regs->cr_iip = regs->r28; + regs->cr_ifs = regs->r30; + vmx_vcpu_set_psr (vcpu, regs->r29); + + regs->eml_unat &= ~(0xffffUL << IA64_PT_REGS_R16_SLOT); + regs->eml_unat |= vcpu->arch.arch_vmx.stub_nats << IA64_PT_REGS_R16_SLOT; + + regs->r16 = vcpu->arch.arch_vmx.stub_saved[0]; + regs->r17 = vcpu->arch.arch_vmx.stub_saved[1]; + regs->r18 = vcpu->arch.arch_vmx.stub_saved[2]; + regs->r19 = vcpu->arch.arch_vmx.stub_saved[3]; + regs->r20 = vcpu->arch.arch_vmx.stub_saved[4]; + regs->r21 = vcpu->arch.arch_vmx.stub_saved[5]; + regs->r22 = vcpu->arch.arch_vmx.stub_saved[6]; + regs->r23 = vcpu->arch.arch_vmx.stub_saved[7]; + regs->r24 = vcpu->arch.arch_vmx.stub_saved[8]; + regs->r25 = vcpu->arch.arch_vmx.stub_saved[9]; + regs->r26 = vcpu->arch.arch_vmx.stub_saved[10]; + regs->r27 = vcpu->arch.arch_vmx.stub_saved[11]; + regs->r28 = vcpu->arch.arch_vmx.stub_saved[12]; + regs->r29 = vcpu->arch.arch_vmx.stub_saved[13]; + regs->r30 = vcpu->arch.arch_vmx.stub_saved[14]; + regs->r31 = vcpu->arch.arch_vmx.stub_saved[15]; + + /* Unmask events. */ + vcpu->vcpu_info->evtchn_upcall_mask = 0; + + /* Then apply commands. */ + if (cmd & 1) { + emulate_io_update (vcpu, arg1, arg2, arg3); + } + +} + +void +sioemu_deliver_event (void) +{ + REGS *regs; + + regs = sioemu_deliver (); + + regs->r16 = 0; +} + +void +sioemu_io_emulate (unsigned long padr, + unsigned long data, unsigned long data1, + unsigned long word) +{ + REGS *regs; + + regs = sioemu_deliver (); + regs->r16 = 1; + regs->r19 = padr; + regs->r20 = data; + regs->r21 = data1; + regs->r22 = word; +} + +static int +sioemu_add_io_physmap (struct domain *d, + unsigned long start, unsigned long size, + unsigned long type) +{ + unsigned long i; + int res; + + /* Check type. */ + if (type == 0 || (type & GPFN_IO_MASK) != type) + return -EINVAL; + if ((start & (PAGE_SIZE -1)) || (size & (PAGE_SIZE - 1))) + return -EINVAL; + + /* Check area is currently unassigned. */ + for (i = start; i < start + size; i += PAGE_SIZE) { + unsigned long mpa; + mpa = ____lookup_domain_mpa(d, i); + if (mpa != GPFN_INV_MASK && mpa != INVALID_MFN) + return -EBUSY; + } + + /* Set. */ + for (i = start; i < start + size; i += PAGE_SIZE) { + res = __assign_domain_page(d, i, type, ASSIGN_writable); + if (res != 0) + return res; + } + + return 0; +} + +void +sioemu_hypercall (struct pt_regs *regs) +{ + //printk ("sioemu_hypercall: r2=%lx r8=%lx r9=%lx\n", + //regs->r2, regs->r8, regs->r9); + + if (current->vcpu_info->evtchn_upcall_mask == 0) + panic_domain (NULL, "sioemu_hypercall: not in stub mode\n"); + + + switch (regs->r2 & FW_HYPERCALL_NUM_MASK_LOW) + { + case SIOEMU_HYPERCALL_SET_CALLBACK: + current->arch.event_callback_ip = regs->r8; + current->arch.arch_vmx.stub_buffer = regs->r9; + break; + case SIOEMU_HYPERCALL_START_FW: + regs->cr_iip = regs->r8; + vmx_vcpu_set_psr (current, regs->r9); + current->vcpu_info->evtchn_upcall_mask = 0; + break; + case SIOEMU_HYPERCALL_ADD_IO_PHYSMAP: + regs->r8 = sioemu_add_io_physmap (current->domain, + regs->r8, regs->r9, regs->r10); + break; + case SIOEMU_HYPERCALL_GET_TIME: + { + uint64_t sec, nsec; + get_wallclock (&sec, &nsec); + regs->r8 = (sec << 30) + nsec; + } + break; + default: + panic_domain (NULL, "bad sioemu hypercall %lx\n", regs->r2); + break; + } +} diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/vmx/vmx_fault.c --- a/xen/arch/ia64/vmx/vmx_fault.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/vmx/vmx_fault.c Tue Feb 12 06:55:31 2008 +0100 @@ -42,7 +42,6 @@ #include #include #include -//#include #include #include #include @@ -52,6 +51,9 @@ #include #include #include +#include +#include + /* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ #define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 @@ -182,34 +184,44 @@ vmx_ia64_handle_break (unsigned long ifa show_registers(regs); debugger_trap_fatal(0 /* don't care */, regs); regs_increment_iip(regs); - } else + return IA64_NO_FAULT; + } #endif - { - if (!vmx_user_mode(regs)) { - show_registers(regs); - gdprintk(XENLOG_DEBUG, "%s:%d imm %lx\n", __func__, __LINE__, iim); - ia64_fault(11 /* break fault */, isr, ifa, iim, - 0 /* cr.itir */, 0, 0, 0, (unsigned long)regs); - } - - if (ia64_psr(regs)->cpl == 0) { - /* Allow hypercalls only when cpl = 0. */ - - /* normal hypercalls are handled by vmx_break_fault */ - BUG_ON(iim == d->arch.breakimm); - - if (iim == DOMN_PAL_REQUEST) { - pal_emul(v); - vcpu_increment_iip(v); - return IA64_NO_FAULT; - } else if (iim == DOMN_SAL_REQUEST) { - sal_emul(v); - vcpu_increment_iip(v); - return IA64_NO_FAULT; - } - } - vmx_reflect_interruption(ifa, isr, iim, 11, regs); - } + if (!vmx_user_mode(regs)) { + show_registers(regs); + gdprintk(XENLOG_DEBUG, "%s:%d imm %lx\n", __func__, __LINE__, iim); + ia64_fault(11 /* break fault */, isr, ifa, iim, + 0 /* cr.itir */, 0, 0, 0, (unsigned long)regs); + } + + if (ia64_psr(regs)->cpl == 0) { + /* Allow hypercalls only when cpl = 0. */ + + /* Only common hypercalls are handled by vmx_break_fault. */ + if (iim == d->arch.breakimm) { + ia64_hypercall(regs); + vcpu_increment_iip(v); + return IA64_NO_FAULT; + } + + /* normal hypercalls are handled by vmx_break_fault */ + BUG_ON(iim == d->arch.breakimm); + + if (iim == DOMN_PAL_REQUEST) { + pal_emul(v); + vcpu_increment_iip(v); + return IA64_NO_FAULT; + } else if (iim == DOMN_SAL_REQUEST) { + sal_emul(v); + vcpu_increment_iip(v); + return IA64_NO_FAULT; + } else if (d->arch.is_sioemu + && iim == SIOEMU_HYPERPRIVOP_CALLBACK_RETURN) { + sioemu_callback_return (); + return IA64_NO_FAULT; + } + } + vmx_reflect_interruption(ifa, isr, iim, 11, regs); return IA64_NO_FAULT; } @@ -218,10 +230,11 @@ void save_banked_regs_to_vpd(VCPU *v, RE { unsigned long i=0UL, * src,* dst, *sunat, *dunat; IA64_PSR vpsr; - src=®s->r16; - sunat=®s->eml_unat; + + src = ®s->r16; + sunat = ®s->eml_unat; vpsr.val = VCPU(v, vpsr); - if(vpsr.bn){ + if (vpsr.bn) { dst = &VCPU(v, vgr[0]); dunat =&VCPU(v, vnat); __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; \ @@ -229,7 +242,8 @@ void save_banked_regs_to_vpd(VCPU *v, RE st8 [%3] = %2;;" ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); - }else{ + } + else { dst = &VCPU(v, vbgr[0]); // dunat =&VCPU(v, vbnat); // __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; @@ -238,7 +252,7 @@ void save_banked_regs_to_vpd(VCPU *v, RE // ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); } - for(i=0; i<16; i++) + for (i = 0; i < 16; i++) *dst++ = *src++; } @@ -251,58 +265,62 @@ void leave_hypervisor_tail(void) struct domain *d = current->domain; struct vcpu *v = current; + /* FIXME: can this happen ? */ + if (is_idle_domain(current->domain)) + return; + + // A softirq may generate an interrupt. So call softirq early. + local_irq_enable(); + do_softirq(); + local_irq_disable(); + // FIXME: Will this work properly if doing an RFI??? - if (!is_idle_domain(d) ) { // always comes from guest -// struct pt_regs *user_regs = vcpu_regs(current); - local_irq_enable(); - do_softirq(); - local_irq_disable(); - - if (v->vcpu_id == 0) { - unsigned long callback_irq = - d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; - - if ( v->arch.arch_vmx.pal_init_pending ) { - /*inject INIT interruption to guest pal*/ - v->arch.arch_vmx.pal_init_pending = 0; - deliver_pal_init(v); - return; - } - - /* - * val[63:56] == 1: val[55:0] is a delivery PCI INTx line: - * Domain = val[47:32], Bus = val[31:16], - * DevFn = val[15: 8], IntX = val[ 1: 0] - * val[63:56] == 0: val[55:0] is a delivery as GSI - */ - if (callback_irq != 0 && local_events_need_delivery()) { - /* change level for para-device callback irq */ - /* use level irq to send discrete event */ - if ((uint8_t)(callback_irq >> 56) == 1) { - /* case of using PCI INTx line as callback irq */ - int pdev = (callback_irq >> 11) & 0x1f; - int pintx = callback_irq & 3; - viosapic_set_pci_irq(d, pdev, pintx, 1); - viosapic_set_pci_irq(d, pdev, pintx, 0); - } else { - /* case of using GSI as callback irq */ - viosapic_set_irq(d, callback_irq, 1); - viosapic_set_irq(d, callback_irq, 0); - } - } - } - - rmb(); - if (xchg(&v->arch.irq_new_pending, 0)) { - v->arch.irq_new_condition = 0; - vmx_check_pending_irq(v); - return; - } - - if (v->arch.irq_new_condition) { - v->arch.irq_new_condition = 0; - vhpi_detection(v); - } + if (d->arch.is_sioemu) { + if (local_events_need_delivery()) { + sioemu_deliver_event (); + } + } else if (v->vcpu_id == 0) { + unsigned long callback_irq = + d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; + + if ( v->arch.arch_vmx.pal_init_pending ) { + /*inject INIT interruption to guest pal*/ + v->arch.arch_vmx.pal_init_pending = 0; + deliver_pal_init(v); + return; + } + + /* + * val[63:56] == 1: val[55:0] is a delivery PCI INTx line: + * Domain = val[47:32], Bus = val[31:16], + * DevFn = val[15: 8], IntX = val[ 1: 0] + * val[63:56] == 0: val[55:0] is a delivery as GSI + */ + if (callback_irq != 0 && local_events_need_delivery()) { + /* change level for para-device callback irq */ + /* use level irq to send discrete event */ + if ((uint8_t)(callback_irq >> 56) == 1) { + /* case of using PCI INTx line as callback irq */ + int pdev = (callback_irq >> 11) & 0x1f; + int pintx = callback_irq & 3; + viosapic_set_pci_irq(d, pdev, pintx, 1); + viosapic_set_pci_irq(d, pdev, pintx, 0); + } else { + /* case of using GSI as callback irq */ + viosapic_set_irq(d, callback_irq, 1); + viosapic_set_irq(d, callback_irq, 0); + } + } + } + + rmb(); + if (xchg(&v->arch.irq_new_pending, 0)) { + v->arch.irq_new_condition = 0; + vmx_check_pending_irq(v); + } + else if (v->arch.irq_new_condition) { + v->arch.irq_new_condition = 0; + vhpi_detection(v); } } diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/vmx/vmx_hypercall.c --- a/xen/arch/ia64/vmx/vmx_hypercall.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/vmx/vmx_hypercall.c Tue Feb 12 06:55:31 2008 +0100 @@ -50,12 +50,15 @@ static int hvmop_set_isa_irq_level( if ( op.isa_irq > 15 ) return -EINVAL; + if ( op.domid == DOMID_SELF ) + op.domid = current->domain->domain_id; + d = rcu_lock_domain_by_id(op.domid); if ( d == NULL ) return -ESRCH; rc = -EPERM; - if ( !IS_PRIV_FOR(current->domain, d) ) + if ( !IS_PRIV_FOR(current->domain, d) && d != current->domain) goto out; rc = -EINVAL; @@ -83,12 +86,15 @@ static int hvmop_set_pci_intx_level( if ( (op.domain > 0) || (op.bus > 0) || (op.device > 31) || (op.intx > 3) ) return -EINVAL; + if ( op.domid == DOMID_SELF ) + op.domid = current->domain->domain_id; + d = rcu_lock_domain_by_id(op.domid); if ( d == NULL ) return -ESRCH; rc = -EPERM; - if ( !IS_PRIV_FOR(current->domain, d) ) + if ( !IS_PRIV_FOR(current->domain, d) && d != current->domain) goto out; rc = -EINVAL; diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/vmx/vmx_init.c --- a/xen/arch/ia64/vmx/vmx_init.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/vmx/vmx_init.c Tue Feb 12 06:55:31 2008 +0100 @@ -494,9 +494,11 @@ vmx_final_setup_guest(struct vcpu *v) if (rc) return rc; - rc = vmx_create_event_channels(v); - if (rc) - return rc; + if (!v->domain->arch.is_sioemu) { + rc = vmx_create_event_channels(v); + if (rc) + return rc; + } /* v->arch.schedule_tail = arch_vmx_do_launch; */ vmx_create_vp(v); @@ -524,14 +526,16 @@ vmx_relinquish_guest_resources(struct do { struct vcpu *v; - for_each_vcpu(d, v) - 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); + if (!d->arch.is_sioemu) { + for_each_vcpu(d, v) + 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 @@ -579,12 +583,13 @@ int vmx_setup_platform(struct domain *d) { ASSERT(d != dom0); /* only for non-privileged vti domain */ - vmx_build_io_physmap_table(d); - - 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); - + if (!d->arch.is_sioemu) { + vmx_build_io_physmap_table(d); + + 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); + } /* TEMP */ d->arch.vmx_platform.pib_base = 0xfee00000UL; @@ -599,7 +604,14 @@ int vmx_setup_platform(struct domain *d) /* Initialize iosapic model within hypervisor */ viosapic_init(d); - vacpi_init(d); + if (!d->arch.is_sioemu) + vacpi_init(d); + + if (d->arch.is_sioemu) { + int i; + for ( i = 1; i < MAX_VIRT_CPUS; i++ ) + d->shared_info->vcpu_info[i].evtchn_upcall_mask = 1; + } return 0; } @@ -610,25 +622,27 @@ void vmx_do_resume(struct vcpu *v) vmx_load_state(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)->vp_ioreq; - while (p->state != STATE_IOREQ_NONE) { - switch (p->state) { - case STATE_IORESP_READY: /* IORESP_READY -> NONE */ - vmx_io_assist(v); - break; - case STATE_IOREQ_READY: - case STATE_IOREQ_INPROCESS: - /* IOREQ_{READY,INPROCESS} -> IORESP_READY */ - wait_on_xen_event_channel(v->arch.arch_vmx.xen_port, - (p->state != STATE_IOREQ_READY) && - (p->state != STATE_IOREQ_INPROCESS)); - break; - default: - gdprintk(XENLOG_ERR, - "Weird HVM iorequest state %d.\n", p->state); - domain_crash_synchronous(); - } - } -} + if (!v->domain->arch.is_sioemu) { + /* 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)->vp_ioreq; + while (p->state != STATE_IOREQ_NONE) { + switch (p->state) { + case STATE_IORESP_READY: /* IORESP_READY -> NONE */ + vmx_io_assist(v); + break; + case STATE_IOREQ_READY: + case STATE_IOREQ_INPROCESS: + /* IOREQ_{READY,INPROCESS} -> IORESP_READY */ + wait_on_xen_event_channel(v->arch.arch_vmx.xen_port, + (p->state != STATE_IOREQ_READY) && + (p->state != STATE_IOREQ_INPROCESS)); + break; + default: + gdprintk(XENLOG_ERR, + "Weird HVM iorequest state %d.\n", p->state); + domain_crash_synchronous(); + } + } + } +} diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/xen/dom0_ops.c --- a/xen/arch/ia64/xen/dom0_ops.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/xen/dom0_ops.c Tue Feb 12 06:55:31 2008 +0100 @@ -114,12 +114,16 @@ long arch_do_domctl(xen_domctl_t *op, XE ret = -EFAULT; } else { - if (is_hvm_domain(d) || (ds->flags & XEN_DOMAINSETUP_hvm_guest)) { + if (is_hvm_domain(d) + || (ds->flags & (XEN_DOMAINSETUP_hvm_guest + | XEN_DOMAINSETUP_sioemu_guest))) { if (!vmx_enabled) { printk("No VMX hardware feature for vmx domain.\n"); ret = -EINVAL; } else { d->is_hvm = 1; + if (ds->flags & XEN_DOMAINSETUP_sioemu_guest) + d->arch.is_sioemu = 1; xen_ia64_set_convmem_end(d, ds->maxmem); ret = vmx_setup_platform(d); } diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/xen/hypercall.c --- a/xen/arch/ia64/xen/hypercall.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/xen/hypercall.c Tue Feb 12 06:55:31 2008 +0100 @@ -33,6 +33,8 @@ #include #include #include +#include +#include static IA64FAULT xen_hypercall (struct pt_regs *regs) @@ -222,7 +224,8 @@ ia64_hypercall(struct pt_regs *regs) regs->r10 = fpswa_ret.err1; regs->r11 = fpswa_ret.err2; break; - case __HYPERVISOR_opt_feature: { + case __HYPERVISOR_opt_feature: + { XEN_GUEST_HANDLE(void) arg; struct xen_ia64_opt_feature optf; set_xen_guest_handle(arg, (void*)(vcpu_get_gr(v, 32))); @@ -232,6 +235,9 @@ ia64_hypercall(struct pt_regs *regs) regs->r8 = -EFAULT; break; } + case FW_HYPERCALL_SIOEMU: + sioemu_hypercall (regs); + break; default: printk("unknown ia64 fw hypercall %lx\n", regs->r2); regs->r8 = do_ni_hypercall(); diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/xen/xensetup.c --- a/xen/arch/ia64/xen/xensetup.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/xen/xensetup.c Tue Feb 12 06:55:31 2008 +0100 @@ -693,6 +693,9 @@ void arch_get_xen_caps(xen_capabilities_ { snprintf(s, sizeof(s), "hvm-%d.%d-ia64 ", major, minor); safe_strcat(*info, s); - } -} - + + snprintf(s, sizeof(s), "hvm-%d.%d-ia64-sioemu ", major, minor); + safe_strcat(*info, s); + } +} + diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/arch/ia64/xen/xentime.c --- a/xen/arch/ia64/xen/xentime.c Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/arch/ia64/xen/xentime.c Tue Feb 12 06:55:31 2008 +0100 @@ -252,3 +252,10 @@ struct tm wallclock_time(void) do_div(seconds, NSEC_PER_SEC); return gmtime(seconds); } + +void get_wallclock (uint64_t *sec, uint64_t *nsec) +{ + uint64_t nano = NOW () + wc_nsec; + *sec = wc_sec + nano / NSEC_PER_SEC; + *nsec = nano % NSEC_PER_SEC; +} diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/asm-ia64/dom_fw.h --- a/xen/include/asm-ia64/dom_fw.h Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/include/asm-ia64/dom_fw.h Tue Feb 12 06:55:31 2008 +0100 @@ -168,6 +168,9 @@ /* Set the shared_info base virtual address. */ #define FW_HYPERCALL_SET_SHARED_INFO_VA 0x600UL +/* Hvmstub hypercalls. See details in hvm_stub.h */ +#define FW_HYPERCALL_SIOEMU 0x800UL + /* Hypercalls index bellow _FIRST_ARCH are reserved by Xen, while those above are for the architecture. Note: this limit was defined by Xen/ia64 (and not by Xen). diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/asm-ia64/domain.h --- a/xen/include/asm-ia64/domain.h Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/include/asm-ia64/domain.h Tue Feb 12 06:55:31 2008 +0100 @@ -133,12 +133,13 @@ struct arch_domain { /* Flags. */ union { unsigned long flags; + struct { + unsigned int is_sioemu : 1; #ifdef CONFIG_XEN_IA64_PERVCPU_VHPT - struct { unsigned int has_pervcpu_vhpt : 1; unsigned int vhpt_size_log2 : 6; +#endif }; -#endif }; /* maximum metaphysical address of conventional memory */ diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/asm-ia64/sioemu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-ia64/sioemu.h Tue Feb 12 06:55:31 2008 +0100 @@ -0,0 +1,31 @@ +/****************************************************************************** + * sioemu.h + * + * Copyright (c) 2008 Tristan Gingold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_SIOEMU_H_ +#define __ASM_SIOEMU_H_ +extern void sioemu_hypercall (struct pt_regs *regs); +extern void sioemu_deliver_event (void); +extern void sioemu_callback_return (void); +extern void sioemu_io_emulate (unsigned long padr, unsigned long data, + unsigned long data1, unsigned long word); + +#endif /* __ASM_SIOEMU_H_ */ + diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/asm-ia64/time.h --- a/xen/include/asm-ia64/time.h Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/include/asm-ia64/time.h Tue Feb 12 06:55:31 2008 +0100 @@ -7,4 +7,6 @@ struct tm; struct tm; struct tm wallclock_time(void); +void get_wallclock (uint64_t *sec, uint64_t *nsec); + #endif /* _ASM_TIME_H_ */ diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/asm-ia64/vmmu.h --- a/xen/include/asm-ia64/vmmu.h Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/include/asm-ia64/vmmu.h Tue Feb 12 06:55:31 2008 +0100 @@ -215,6 +215,7 @@ extern void machine_tlb_purge(u64 va, u6 extern void machine_tlb_purge(u64 va, u64 ps); extern unsigned long fetch_code(struct vcpu *vcpu, u64 gip, IA64_BUNDLE *pbundle); extern void emulate_io_inst(struct vcpu *vcpu, u64 padr, u64 ma); +extern void emulate_io_update (struct vcpu *vcpu, u64 word, u64 d, u64 d1); extern int vhpt_enabled(struct vcpu *vcpu, uint64_t vadr, vhpt_ref_t ref); extern u64 translate_phy_pte(struct vcpu *v, u64 *pte, u64 itir, u64 va); extern void thash_vhpt_insert(struct vcpu *v, u64 pte, u64 itir, u64 ifa, diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/asm-ia64/vmx_vpd.h --- a/xen/include/asm-ia64/vmx_vpd.h Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/include/asm-ia64/vmx_vpd.h Tue Feb 12 06:55:31 2008 +0100 @@ -74,6 +74,9 @@ struct arch_vmx_struct { unsigned long ivt_current; struct ivt_debug ivt_debug[IVT_DEBUG_MAX]; #endif + unsigned long stub_saved[16]; + unsigned long stub_buffer; + unsigned int stub_nats; }; #define VMX_DOMAIN(v) v->arch.arch_vmx.flags diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/public/arch-ia64/sioemu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/arch-ia64/sioemu.h Tue Feb 12 06:55:31 2008 +0100 @@ -0,0 +1,43 @@ +/****************************************************************************** + * sioemu.h + * + * Copyright (c) 2008 Tristan Gingold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __XEN_PUBLIC_IA64_SIOEMU_H__ +#define __XEN_PUBLIC_IA64_SIOEMU_H__ + +/* Defines the callback entry point. r8=ip, r9=data. + Must be called per-vcpu. */ +#define SIOEMU_HYPERCALL_SET_CALLBACK 0x01 + +/* Finish sioemu fw initialization and start firmware. r8=ip. */ +#define SIOEMU_HYPERCALL_START_FW 0x02 + +/* Add IO pages in physmap. */ +#define SIOEMU_HYPERCALL_ADD_IO_PHYSMAP 0x03 + +/* Get wallclock time. */ +#define SIOEMU_HYPERCALL_GET_TIME 0x04 + + +/* Return from callback. r16=0. + Unmask vcpu events. */ +#define SIOEMU_HYPERPRIVOP_CALLBACK_RETURN 0x01 + +#endif /* __XEN_PUBLIC_IA64_SIOEMU_H__ */ diff -r 8bbc0b7b1759 -r 6ba0c3a71fe1 xen/include/public/domctl.h --- a/xen/include/public/domctl.h Tue Feb 12 06:43:56 2008 +0100 +++ b/xen/include/public/domctl.h Tue Feb 12 06:55:31 2008 +0100 @@ -376,6 +376,8 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_hyper #define XEN_DOMAINSETUP_hvm_guest (1UL<<_XEN_DOMAINSETUP_hvm_guest) #define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save) */ #define XEN_DOMAINSETUP_query (1UL<<_XEN_DOMAINSETUP_query) +#define _XEN_DOMAINSETUP_sioemu_guest 2 +#define XEN_DOMAINSETUP_sioemu_guest (1UL<<_XEN_DOMAINSETUP_sioemu_guest) typedef struct xen_domctl_arch_setup { uint64_aligned_t flags; /* XEN_DOMAINSETUP_* */ #ifdef __ia64__