# HG changeset patch # User Tristan Gingold # Date 1205993255 -3600 # Node ID 1c98957779ee1d8730d48f2c09e9ca35cc77441d # Parent ac30e3a6b9fccc9d0213dc0eed7c1545c4312b1f New SIOEmu interface: pass callback data in memory. This fixes lost data for callback while hypercall case. Signed-off-by: Tristan Gingold diff -r ac30e3a6b9fc -r 1c98957779ee xen/arch/ia64/asm-offsets.c --- a/xen/arch/ia64/asm-offsets.c Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/arch/ia64/asm-offsets.c Thu Mar 20 07:07:35 2008 +0100 @@ -150,6 +150,8 @@ void foo(void) DEFINE(IA64_VCPU_OPCODE_OFFSET, offsetof (struct vcpu, arch.arch_vmx.opcode)); DEFINE(SWITCH_MPTA_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.mpta)); DEFINE(IA64_PT_REGS_R16_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); + DEFINE(IA64_PT_REGS_R2_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); + DEFINE(IA64_PT_REGS_R8_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); DEFINE(IA64_VCPU_FLAGS_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.flags)); DEFINE(IA64_VCPU_MMU_MODE_OFFSET,offsetof(struct vcpu, arch.arch_vmx.mmu_mode)); diff -r ac30e3a6b9fc -r 1c98957779ee xen/arch/ia64/vmx/sioemu.c --- a/xen/arch/ia64/vmx/sioemu.c Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/arch/ia64/vmx/sioemu.c Thu Mar 20 07:07:35 2008 +0100 @@ -26,171 +26,137 @@ #include #include -static void -sioemu_save_regs (VCPU *vcpu) -{ - REGS *regs = vcpu_regs(vcpu); - - 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; -} - -static void -sioemu_restore_regs (VCPU *vcpu) -{ - REGS *regs = vcpu_regs(vcpu); - - /* 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]; - -} - -static REGS * +struct sioemu_callback_info * sioemu_deliver (void) { VCPU *vcpu = current; REGS *regs = vcpu_regs(vcpu); + struct sioemu_callback_info *info = vcpu->arch.arch_vmx.sioemu_info_mva; 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"); + if (info == NULL) + panic_domain (NULL, "sioemu_deliver: set_callback not called\n"); /* All cleared, but keep BN. */ vmx_vcpu_set_psr(vcpu, IA64_PSR_MC | (psr & IA64_PSR_BN)); - /* Save registers. */ - sioemu_save_regs (vcpu); - - /* Context. */ - regs->r28 = regs->cr_iip; - regs->r29 = psr; - regs->r30 = regs->cr_ifs; + /* Set info. */ + info->ip = regs->cr_iip; + info->psr = psr; + info->ifs = regs->cr_ifs; + info->nats = (((regs->eml_unat >> IA64_PT_REGS_R8_SLOT) & 0x0f) << 8) + | (((regs->eml_unat >> IA64_PT_REGS_R2_SLOT) & 1) << 2); + info->r8 = regs->r8; + info->r9 = regs->r9; + info->r10 = regs->r10; + info->r11 = regs->r11; + info->r2 = regs->r2; 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; + regs->eml_unat &= ~(1UL << IA64_PT_REGS_R8_SLOT); + regs->r8 = vcpu->arch.arch_vmx.sioemu_info_gpa; /* Mask events. */ vcpu->vcpu_info->evtchn_upcall_mask = 1; debugger_event(XEN_IA64_DEBUG_ON_EVENT); - return regs; -} - -void + return info; +} + +static 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) + struct sioemu_callback_info *info = vcpu->arch.arch_vmx.sioemu_info_mva; + + if (info == NULL) + panic_domain (NULL, "sioemu_deliver: set_callback not called\n"); + if ((info->cause & ~0x1UL) != 0) panic_domain (NULL, "sioemu_callback_return: bad operation (%lx)\n", - cmd); + info->cause); /* First restore registers. */ - regs->cr_iip = regs->r28; - regs->cr_ifs = regs->r30; - vmx_vcpu_set_psr (vcpu, regs->r29); - - sioemu_restore_regs (vcpu); + regs->cr_iip = info->ip; + regs->cr_ifs = info->ifs; + vmx_vcpu_set_psr (vcpu, info->psr); + regs->r8 = info->r8; + regs->r9 = info->r9; + regs->r10 = info->r10; + regs->r11 = info->r11; + regs->r2 = info->r2; + regs->eml_unat &= ~((0x0fUL << IA64_PT_REGS_R8_SLOT) + | (1UL << IA64_PT_REGS_R2_SLOT)); + regs->eml_unat |= (((info->nats >> 8) & 0x0f) << IA64_PT_REGS_R8_SLOT) + | (((info->nats >> 2) & 1) << IA64_PT_REGS_R2_SLOT); /* Unmask events. */ vcpu->vcpu_info->evtchn_upcall_mask = 0; /* Then apply commands. */ - if (cmd & 1) { - emulate_io_update (vcpu, arg1, arg2, arg3); + if (info->cause & 1) { + emulate_io_update (vcpu, info->arg0, info->arg1, info->arg2); } } void sioemu_deliver_event (void) { - REGS *regs; - - regs = sioemu_deliver (); - regs->r16 = SIOEMU_CB_EVENT; + struct sioemu_callback_info *info; + + info = sioemu_deliver (); + info->cause = SIOEMU_CB_EVENT; } void sioemu_io_emulate (unsigned long padr, unsigned long data, unsigned long data1, unsigned long word) { - REGS *regs; - - regs = sioemu_deliver (); - regs->r16 = SIOEMU_CB_IO_EMULATE; - regs->r19 = padr; - regs->r20 = data; - regs->r21 = data1; - regs->r22 = word; -} - -void -sioemu_wakeup_vcpu (int vcpu_id) -{ - REGS *regs; - - regs = sioemu_deliver(); - regs->r16 = SIOEMU_CB_WAKEUP_VCPU; - regs->r19 = vcpu_id; + struct sioemu_callback_info *info; + + info = sioemu_deliver (); + info->cause = SIOEMU_CB_IO_EMULATE; + info->arg0 = padr; + info->arg1 = data; + info->arg2 = data1; + info->arg3 = word; } void sioemu_sal_assist (struct vcpu *v) { - REGS *regs; - - regs = sioemu_deliver(); - regs->r16 = SIOEMU_CB_SAL_ASSIST; + struct sioemu_callback_info *info; + + info = sioemu_deliver (); + info->cause = SIOEMU_CB_SAL_ASSIST; +} + +static int +sioemu_set_callback (struct vcpu *v, unsigned long cb_ip, unsigned long paddr) +{ + struct page_info *page; + unsigned long mfn; + pte_t pte; + + v->arch.event_callback_ip = cb_ip; + if ((paddr & 0xfff) || v->arch.arch_vmx.sioemu_info_mva) + return -EINVAL; + pte = *lookup_noalloc_domain_pte(v->domain, paddr); + 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, v->domain) == 0) + return -EINVAL; + v->arch.arch_vmx.sioemu_info_gpa = paddr; + v->arch.arch_vmx.sioemu_info_mva = mfn_to_virt(mfn); + return 0; } static int @@ -234,8 +200,7 @@ sioemu_hypercall (struct pt_regs *regs) 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; + regs->r8 = sioemu_set_callback(current, regs->r8, regs->r9); break; case SIOEMU_HYPERCALL_START_FW: regs->cr_iip = regs->r8; @@ -254,12 +219,6 @@ sioemu_hypercall (struct pt_regs *regs) regs->r9 = now; break; } - case SIOEMU_HYPERCALL_GET_REGS: - sioemu_restore_regs(current); - break; - case SIOEMU_HYPERCALL_SET_REGS: - sioemu_save_regs(current); - break; case SIOEMU_HYPERCALL_FLUSH_CACHE: regs->r8 = ia64_sal_cache_flush(regs->r8); break; @@ -271,7 +230,6 @@ sioemu_hypercall (struct pt_regs *regs) regs->r8, regs->r9, regs->r10); break; case SIOEMU_HYPERCALL_CALLBACK_RETURN: - regs->r2 = regs->r27; sioemu_callback_return (); vcpu_decrement_iip(current); break; diff -r ac30e3a6b9fc -r 1c98957779ee xen/arch/ia64/vmx/vmx_fault.c --- a/xen/arch/ia64/vmx/vmx_fault.c Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/arch/ia64/vmx/vmx_fault.c Thu Mar 20 07:07:35 2008 +0100 @@ -215,10 +215,6 @@ vmx_ia64_handle_break (unsigned long ifa 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); diff -r ac30e3a6b9fc -r 1c98957779ee xen/arch/ia64/vmx/vmx_init.c --- a/xen/arch/ia64/vmx/vmx_init.c Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/arch/ia64/vmx/vmx_init.c Thu Mar 20 07:07:35 2008 +0100 @@ -546,6 +546,10 @@ vmx_relinquish_vcpu_resources(struct vcp kill_timer(&vtm->vtm_timer); + if (v->arch.arch_vmx.sioemu_info_mva) + put_page + (virt_to_page((unsigned long)v->arch.arch_vmx.sioemu_info_mva)); + free_domain_tlb(v); free_vpd(v); } diff -r ac30e3a6b9fc -r 1c98957779ee xen/include/asm-ia64/sioemu.h --- a/xen/include/asm-ia64/sioemu.h Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/include/asm-ia64/sioemu.h Thu Mar 20 07:07:35 2008 +0100 @@ -23,9 +23,7 @@ #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); -extern void sioemu_wakeup_vcpu (int vcpu_id); extern void sioemu_sal_assist (struct vcpu *v); #endif /* __ASM_SIOEMU_H_ */ diff -r ac30e3a6b9fc -r 1c98957779ee xen/include/asm-ia64/vmx_vpd.h --- a/xen/include/asm-ia64/vmx_vpd.h Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/include/asm-ia64/vmx_vpd.h Thu Mar 20 07:07:35 2008 +0100 @@ -40,6 +40,8 @@ #include #include +struct sioemu_callback_info; + #define VPD_SHIFT 16 #define VPD_SIZE (1 << VPD_SHIFT) @@ -74,9 +76,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; + /* sioemu info buffer. */ + unsigned long sioemu_info_gpa; + struct sioemu_callback_info *sioemu_info_mva; }; #define VMX_DOMAIN(v) v->arch.arch_vmx.flags diff -r ac30e3a6b9fc -r 1c98957779ee xen/include/public/arch-ia64/sioemu.h --- a/xen/include/public/arch-ia64/sioemu.h Thu Mar 13 05:29:24 2008 +0100 +++ b/xen/include/public/arch-ia64/sioemu.h Thu Mar 20 07:07:35 2008 +0100 @@ -38,10 +38,6 @@ /* Get wallclock time. */ #define SIOEMU_HYPERCALL_GET_TIME 0x04 -/* Get/Set shadow registers. */ -#define SIOEMU_HYPERCALL_GET_REGS 0x05 -#define SIOEMU_HYPERCALL_SET_REGS 0x06 - /* Flush cache. */ #define SIOEMU_HYPERCALL_FLUSH_CACHE 0x07 @@ -68,11 +64,26 @@ /* A SAL hypercall is executed. */ #define SIOEMU_CB_SAL_ASSIST 0x03 +#ifndef __ASSEMBLY__ +struct sioemu_callback_info { + /* Saved registers. */ + unsigned long ip; + unsigned long psr; + unsigned long ifs; + unsigned long nats; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; -/* SIOEMU firmware mode hypercalls. */ - -/* Return from callback. r16=0. - Unmask vcpu events. */ -#define SIOEMU_HYPERPRIVOP_CALLBACK_RETURN 0x01 - + /* Callback parameters. */ + unsigned long cause; + unsigned long arg0; + unsigned long arg1; + unsigned long arg2; + unsigned long arg3; + unsigned long _pad2[2]; + unsigned long r2; +}; +#endif /* __ASSEMBLY__ */ #endif /* __XEN_PUBLIC_IA64_SIOEMU_H__ */