Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.9-rc5 156 lines 4.0 kB view raw
1/* 2 * Copyright (C) 2012 - Virtual Open Systems and Columbia University 3 * Author: Christoffer Dall <c.dall@virtualopensystems.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License, version 2, as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19#include <linux/kvm_host.h> 20#include <asm/kvm_mmio.h> 21#include <asm/kvm_emulate.h> 22#include <trace/events/kvm.h> 23 24#include "trace.h" 25 26/** 27 * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation 28 * @vcpu: The VCPU pointer 29 * @run: The VCPU run struct containing the mmio data 30 * 31 * This should only be called after returning from userspace for MMIO load 32 * emulation. 33 */ 34int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) 35{ 36 __u32 *dest; 37 unsigned int len; 38 int mask; 39 40 if (!run->mmio.is_write) { 41 dest = vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt); 42 memset(dest, 0, sizeof(int)); 43 44 len = run->mmio.len; 45 if (len > 4) 46 return -EINVAL; 47 48 memcpy(dest, run->mmio.data, len); 49 50 trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, 51 *((u64 *)run->mmio.data)); 52 53 if (vcpu->arch.mmio_decode.sign_extend && len < 4) { 54 mask = 1U << ((len * 8) - 1); 55 *dest = (*dest ^ mask) - mask; 56 } 57 } 58 59 return 0; 60} 61 62static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, 63 struct kvm_exit_mmio *mmio) 64{ 65 unsigned long rt, len; 66 bool is_write, sign_extend; 67 68 if ((vcpu->arch.hsr >> 8) & 1) { 69 /* cache operation on I/O addr, tell guest unsupported */ 70 kvm_inject_dabt(vcpu, vcpu->arch.hxfar); 71 return 1; 72 } 73 74 if ((vcpu->arch.hsr >> 7) & 1) { 75 /* page table accesses IO mem: tell guest to fix its TTBR */ 76 kvm_inject_dabt(vcpu, vcpu->arch.hxfar); 77 return 1; 78 } 79 80 switch ((vcpu->arch.hsr >> 22) & 0x3) { 81 case 0: 82 len = 1; 83 break; 84 case 1: 85 len = 2; 86 break; 87 case 2: 88 len = 4; 89 break; 90 default: 91 kvm_err("Hardware is weird: SAS 0b11 is reserved\n"); 92 return -EFAULT; 93 } 94 95 is_write = vcpu->arch.hsr & HSR_WNR; 96 sign_extend = vcpu->arch.hsr & HSR_SSE; 97 rt = (vcpu->arch.hsr & HSR_SRT_MASK) >> HSR_SRT_SHIFT; 98 99 if (kvm_vcpu_reg_is_pc(vcpu, rt)) { 100 /* IO memory trying to read/write pc */ 101 kvm_inject_pabt(vcpu, vcpu->arch.hxfar); 102 return 1; 103 } 104 105 mmio->is_write = is_write; 106 mmio->phys_addr = fault_ipa; 107 mmio->len = len; 108 vcpu->arch.mmio_decode.sign_extend = sign_extend; 109 vcpu->arch.mmio_decode.rt = rt; 110 111 /* 112 * The MMIO instruction is emulated and should not be re-executed 113 * in the guest. 114 */ 115 kvm_skip_instr(vcpu, (vcpu->arch.hsr >> 25) & 1); 116 return 0; 117} 118 119int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, 120 phys_addr_t fault_ipa) 121{ 122 struct kvm_exit_mmio mmio; 123 unsigned long rt; 124 int ret; 125 126 /* 127 * Prepare MMIO operation. First stash it in a private 128 * structure that we can use for in-kernel emulation. If the 129 * kernel can't handle it, copy it into run->mmio and let user 130 * space do its magic. 131 */ 132 133 if (vcpu->arch.hsr & HSR_ISV) { 134 ret = decode_hsr(vcpu, fault_ipa, &mmio); 135 if (ret) 136 return ret; 137 } else { 138 kvm_err("load/store instruction decoding not implemented\n"); 139 return -ENOSYS; 140 } 141 142 rt = vcpu->arch.mmio_decode.rt; 143 trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE : 144 KVM_TRACE_MMIO_READ_UNSATISFIED, 145 mmio.len, fault_ipa, 146 (mmio.is_write) ? *vcpu_reg(vcpu, rt) : 0); 147 148 if (mmio.is_write) 149 memcpy(mmio.data, vcpu_reg(vcpu, rt), mmio.len); 150 151 if (vgic_handle_mmio(vcpu, run, &mmio)) 152 return 1; 153 154 kvm_prepare_mmio(run, &mmio); 155 return 0; 156}