From: Zhang, X. <xia...@in...> - 2008-01-31 10:30:14
|
From: Xiantao Zhang <xia...@in...> Date: Thu, 31 Jan 2008 15:45:48 +0800 Subject: [PATCH] kvm/ia64: Add mmio decoder for kvm/ia64. mmio.c includes mmio decoder routines. Signed-off-by: Anthony Xu <Ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/mmio.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 349 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/mmio.c diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c new file mode 100644 index 0000000..3f8027a --- /dev/null +++ b/arch/ia64/kvm/mmio.c @@ -0,0 +1,349 @@ +/* + * mmio.c: MMIO emulation components. + * Copyright (c) 2004, Intel Corporation. + * Yaozu Dong (Eddie Dong) (Edd...@in...) + * Kun Tian (Kevin Tian) (Kev...@in...) + * + * Copyright (c) 2007 Intel Corporation KVM support. + * Xuefei Xu (Anthony Xu) (ant...@in...) + * Xiantao Zhang (xia...@in...) + * + * 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 <linux/kvm_host.h> + +#include "vcpu.h" + +static void vlsapic_write_xtp(VCPU *v, uint8_t val) +{ + VLSAPIC_XTP(v) =3D val; +} + +/* + * LSAPIC OFFSET + */ +#define PIB_LOW_HALF(ofst) !(ofst & (1 << 20)) +#define PIB_OFST_INTA 0x1E0000 +#define PIB_OFST_XTP 0x1E0008 + +/* + * execute write IPI op. + */ +static void vlsapic_write_ipi(VCPU *vcpu, uint64_t addr, uint64_t data) +{ + struct exit_ctl_data *p =3D ¤t_vcpu->arch.exit_data; + unsigned long psr; + + local_irq_save(psr); + + p->exit_reason =3D EXIT_REASON_IPI; + p->u.ipi_data.addr.val =3D addr; + p->u.ipi_data.data.val =3D data; + vmm_transition(current_vcpu); + + local_irq_restore(psr); + +} + +void lsapic_write(VCPU *v, unsigned long addr, unsigned long length, + unsigned long val) +{ + addr &=3D (PIB_SIZE - 1); + + switch (addr) { + case PIB_OFST_INTA: + /*panic_domain(NULL, "Undefined write on PIB INTA\n");*/ + panic_vm(v); + break; + case PIB_OFST_XTP: + if (length =3D=3D 1) { + vlsapic_write_xtp(v, val); + } else { + /*panic_domain(NULL, + "Undefined write on PIB XTP\n");*/ + panic_vm(v); + } + break; + default: + if (PIB_LOW_HALF(addr)) { + /*lower half */ + if (length !=3D 8) + /*panic_domain(NULL, + "Can't LHF write with size %ld!\n", + length);*/ + panic_vm(v); + else + vlsapic_write_ipi(v, addr, val); + } else { /* upper half + printk("IPI-UHF write %lx\n",addr);*/ + panic_vm(v); + } + break; + } +} + +unsigned long lsapic_read(VCPU *v, unsigned long addr, + unsigned long length) +{ + uint64_t result =3D 0; + + addr &=3D (PIB_SIZE - 1); + + switch (addr) { + case PIB_OFST_INTA: + if (length =3D=3D 1) /* 1 byte load */ + ; /* There is no i8259, there is no INTA access*/ + else + /*panic_domain(NULL,"Undefined read on PIB INTA\n"); */ + panic_vm(v); + + break; + case PIB_OFST_XTP: + if (length =3D=3D 1) { + result =3D VLSAPIC_XTP(v); + /* printk("read xtp %lx\n", result); */ + } else { + /*panic_domain(NULL, + "Undefined read on PIB XTP\n");*/ + panic_vm(v); + } + break; + default: + panic_vm(v); + break; + } + return result; +} + +static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, + u16 s, int ma, int dir) +{ + unsigned long iot; + struct exit_ctl_data *p =3D &vcpu->arch.exit_data; + unsigned long psr; + + iot =3D __gpfn_is_io(src_pa >> PAGE_SHIFT); + + local_irq_save(psr); + + /*Intercept the acces for PIB range*/ + if (iot =3D=3D GPFN_PIB) { + if (!dir) + lsapic_write(vcpu, src_pa, s, *dest); + else + *dest =3D lsapic_read(vcpu, src_pa, s); + goto out; + } + p->exit_reason =3D EXIT_REASON_MMIO_INSTRUCTION; + p->u.ioreq.addr =3D src_pa; + p->u.ioreq.size =3D s; + p->u.ioreq.dir =3D dir; + if (dir =3D=3D IOREQ_WRITE) + p->u.ioreq.data =3D *dest; + p->u.ioreq.state =3D STATE_IOREQ_READY; + vmm_transition(vcpu); + + if (p->u.ioreq.state =3D=3D STATE_IORESP_READY) { + if (dir =3D=3D IOREQ_READ) + *dest =3D p->u.ioreq.data; + } else + panic_vm(vcpu); +out: + local_irq_restore(psr); + return ; +} + +/* + dir 1: read 0:write + inst_type 0:integer 1:floating point + */ +#define SL_INTEGER 0 /* store/load interger*/ +#define SL_FLOATING 1 /* store/load floating*/ + +void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) +{ + REGS *regs; + IA64_BUNDLE bundle; + int slot, dir =3D 0; + int inst_type =3D -1; + u16 size =3D 0; + u64 data, post_update, slot1a, slot1b, temp; + INST64 inst; + + regs =3D vcpu_regs(vcpu); + + if (fetch_code(vcpu, regs->cr_iip, &bundle)) { + /* if fetch code fail, return and try again */ + return; + } + slot =3D ((ia64_psr *)&(regs->cr_ipsr))->ri; + if (!slot) + inst.inst =3D bundle.slot0; + else if (slot =3D=3D 1) { + slot1a =3D bundle.slot1a; + slot1b =3D bundle.slot1b; + inst.inst =3D slot1a + (slot1b << 18); + } else if (slot =3D=3D 2) + inst.inst =3D bundle.slot2; + + /* Integer Load/Store */ + if (inst.M1.major =3D=3D 4 && inst.M1.m =3D=3D 0 && inst.M1.x =3D=3D = 0) { + inst_type =3D SL_INTEGER; + size =3D (inst.M1.x6 & 0x3); + if ((inst.M1.x6 >> 2) > 0xb) { + /*write*/ + dir =3D IOREQ_WRITE; + data =3D vcpu_get_gr(vcpu, inst.M4.r2); + } else if ((inst.M1.x6 >> 2) < 0xb) { + /*read*/ + dir =3D IOREQ_READ; + } + } else if (inst.M2.major =3D=3D 4 && inst.M2.m =3D=3D 1 && inst.M2.x = =3D=3D 0) { + /* Integer Load + Reg update */ + inst_type =3D SL_INTEGER; + dir =3D IOREQ_READ; + size =3D (inst.M2.x6 & 0x3); + temp =3D vcpu_get_gr(vcpu, inst.M2.r3); + post_update =3D vcpu_get_gr(vcpu, inst.M2.r2); + temp +=3D post_update; + vcpu_set_gr(vcpu, inst.M2.r3, temp, 0); + } else if (inst.M3.major =3D=3D 5) { + /*Integer Load/Store + Imm update*/ + inst_type =3D SL_INTEGER; + size =3D (inst.M3.x6&0x3); + if ((inst.M5.x6 >> 2) > 0xb) { + /*write*/ + dir =3D IOREQ_WRITE; + data =3D vcpu_get_gr(vcpu, inst.M5.r2); + temp =3D vcpu_get_gr(vcpu, inst.M5.r3); + post_update =3D (inst.M5.i << 7) + inst.M5.imm7; + if (inst.M5.s) + temp -=3D post_update; + else + temp +=3D post_update; + vcpu_set_gr(vcpu, inst.M5.r3, temp, 0); + + } else if ((inst.M3.x6 >> 2) < 0xb) { + /*read*/ + dir =3D IOREQ_READ; + temp =3D vcpu_get_gr(vcpu, inst.M3.r3); + post_update =3D (inst.M3.i << 7) + inst.M3.imm7; + if (inst.M3.s) + temp -=3D post_update; + else + temp +=3D post_update; + vcpu_set_gr(vcpu, inst.M3.r3, temp, 0); + + } + } else if (inst.M9.major =3D=3D 6 && inst.M9.x6 =3D=3D 0x3B + && inst.M9.m =3D=3D 0 && inst.M9.x =3D=3D 0) { + /* Floating-point spill*/ + struct ia64_fpreg v; + + inst_type =3D SL_FLOATING; + dir =3D IOREQ_WRITE; + vcpu_get_fpreg(vcpu, inst.M9.f2, &v); + /* Write high word. FIXME: this is a kludge! */ + v.u.bits[1] &=3D 0x3ffff; + mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE); + data =3D v.u.bits[0]; + size =3D 3; + } else if (inst.M10.major =3D=3D 7 && inst.M10.x6 =3D=3D 0x3B) { + /* Floating-point spill + Imm update */ + struct ia64_fpreg v; + + inst_type =3D SL_FLOATING; + dir =3D IOREQ_WRITE; + vcpu_get_fpreg(vcpu, inst.M10.f2, &v); + temp =3D vcpu_get_gr(vcpu, inst.M10.r3); + post_update =3D (inst.M10.i << 7) + inst.M10.imm7; + if (inst.M10.s) + temp -=3D post_update; + else + temp +=3D post_update; + vcpu_set_gr(vcpu, inst.M10.r3, temp, 0); + + /* Write high word.FIXME: this is a kludge! */ + v.u.bits[1] &=3D 0x3ffff; + mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE); + data =3D v.u.bits[0]; + size =3D 3; + } else if (inst.M10.major =3D=3D 7 && inst.M10.x6 =3D=3D 0x31) { + /* Floating-point stf8 + Imm update */ + struct ia64_fpreg v; + inst_type =3D SL_FLOATING; + dir =3D IOREQ_WRITE; + size =3D 3; + vcpu_get_fpreg(vcpu, inst.M10.f2, &v); + data =3D v.u.bits[0]; /* Significand. */ + temp =3D vcpu_get_gr(vcpu, inst.M10.r3); + post_update =3D (inst.M10.i << 7) + inst.M10.imm7; + if (inst.M10.s) + temp -=3D post_update; + else + temp +=3D post_update; + vcpu_set_gr(vcpu, inst.M10.r3, temp, 0); + } else if (inst.M15.major =3D=3D 7 && inst.M15.x6 >=3D 0x2c + && inst.M15.x6 <=3D 0x2f) { + temp =3D vcpu_get_gr(vcpu, inst.M15.r3); + post_update =3D (inst.M15.i << 7) + inst.M15.imm7; + if (inst.M15.s) + temp -=3D post_update; + else + temp +=3D post_update; + vcpu_set_gr(vcpu, inst.M15.r3, temp, 0); + + vcpu_increment_iip(vcpu); + return; + } else if (inst.M12.major =3D=3D 6 && inst.M12.m =3D=3D 1 + && inst.M12.x =3D=3D 1 && inst.M12.x6 =3D=3D 1) { + /* Floating-point Load Pair + Imm ldfp8 M12*/ + struct ia64_fpreg v; + + inst_type =3D SL_FLOATING; + dir =3D IOREQ_READ; + size =3D 8; /*ldfd*/ + mmio_access(vcpu, padr, &data, size, ma, dir); + v.u.bits[0] =3D data; + v.u.bits[1] =3D 0x1003E; + vcpu_set_fpreg(vcpu, inst.M12.f1, &v); + padr +=3D 8; + mmio_access(vcpu, padr, &data, size, ma, dir); + v.u.bits[0] =3D data; + v.u.bits[1] =3D 0x1003E; + vcpu_set_fpreg(vcpu, inst.M12.f2, &v); + padr +=3D 8; + vcpu_set_gr(vcpu, inst.M12.r3, padr, 0); + vcpu_increment_iip(vcpu); + return; + } else { + inst_type =3D -1; + panic_vm(vcpu); + } + + size =3D 1 << size; + if (dir =3D=3D IOREQ_WRITE) { + mmio_access(vcpu, padr, &data, size, ma, dir); + } else { + mmio_access(vcpu, padr, &data, size, ma, dir); + if (inst_type =3D=3D SL_INTEGER) { + vcpu_set_gr(vcpu, inst.M1.r1, data, 0); + } else { + panic_vm(vcpu); + } + } + vcpu_increment_iip(vcpu); +} --=20 1.5.1 |