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 v4.9-rc2 217 lines 5.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 26void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data) 27{ 28 void *datap = NULL; 29 union { 30 u8 byte; 31 u16 hword; 32 u32 word; 33 u64 dword; 34 } tmp; 35 36 switch (len) { 37 case 1: 38 tmp.byte = data; 39 datap = &tmp.byte; 40 break; 41 case 2: 42 tmp.hword = data; 43 datap = &tmp.hword; 44 break; 45 case 4: 46 tmp.word = data; 47 datap = &tmp.word; 48 break; 49 case 8: 50 tmp.dword = data; 51 datap = &tmp.dword; 52 break; 53 } 54 55 memcpy(buf, datap, len); 56} 57 58unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len) 59{ 60 unsigned long data = 0; 61 union { 62 u16 hword; 63 u32 word; 64 u64 dword; 65 } tmp; 66 67 switch (len) { 68 case 1: 69 data = *(u8 *)buf; 70 break; 71 case 2: 72 memcpy(&tmp.hword, buf, len); 73 data = tmp.hword; 74 break; 75 case 4: 76 memcpy(&tmp.word, buf, len); 77 data = tmp.word; 78 break; 79 case 8: 80 memcpy(&tmp.dword, buf, len); 81 data = tmp.dword; 82 break; 83 } 84 85 return data; 86} 87 88/** 89 * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation 90 * or in-kernel IO emulation 91 * 92 * @vcpu: The VCPU pointer 93 * @run: The VCPU run struct containing the mmio data 94 */ 95int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) 96{ 97 unsigned long data; 98 unsigned int len; 99 int mask; 100 101 if (!run->mmio.is_write) { 102 len = run->mmio.len; 103 if (len > sizeof(unsigned long)) 104 return -EINVAL; 105 106 data = kvm_mmio_read_buf(run->mmio.data, len); 107 108 if (vcpu->arch.mmio_decode.sign_extend && 109 len < sizeof(unsigned long)) { 110 mask = 1U << ((len * 8) - 1); 111 data = (data ^ mask) - mask; 112 } 113 114 trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, 115 data); 116 data = vcpu_data_host_to_guest(vcpu, data, len); 117 vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); 118 } 119 120 return 0; 121} 122 123static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len) 124{ 125 unsigned long rt; 126 int access_size; 127 bool sign_extend; 128 129 if (kvm_vcpu_dabt_iss1tw(vcpu)) { 130 /* page table accesses IO mem: tell guest to fix its TTBR */ 131 kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); 132 return 1; 133 } 134 135 access_size = kvm_vcpu_dabt_get_as(vcpu); 136 if (unlikely(access_size < 0)) 137 return access_size; 138 139 *is_write = kvm_vcpu_dabt_iswrite(vcpu); 140 sign_extend = kvm_vcpu_dabt_issext(vcpu); 141 rt = kvm_vcpu_dabt_get_rd(vcpu); 142 143 *len = access_size; 144 vcpu->arch.mmio_decode.sign_extend = sign_extend; 145 vcpu->arch.mmio_decode.rt = rt; 146 147 /* 148 * The MMIO instruction is emulated and should not be re-executed 149 * in the guest. 150 */ 151 kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); 152 return 0; 153} 154 155int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, 156 phys_addr_t fault_ipa) 157{ 158 unsigned long data; 159 unsigned long rt; 160 int ret; 161 bool is_write; 162 int len; 163 u8 data_buf[8]; 164 165 /* 166 * Prepare MMIO operation. First decode the syndrome data we get 167 * from the CPU. Then try if some in-kernel emulation feels 168 * responsible, otherwise let user space do its magic. 169 */ 170 if (kvm_vcpu_dabt_isvalid(vcpu)) { 171 ret = decode_hsr(vcpu, &is_write, &len); 172 if (ret) 173 return ret; 174 } else { 175 kvm_err("load/store instruction decoding not implemented\n"); 176 return -ENOSYS; 177 } 178 179 rt = vcpu->arch.mmio_decode.rt; 180 181 if (is_write) { 182 data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt), 183 len); 184 185 trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); 186 kvm_mmio_write_buf(data_buf, len, data); 187 188 ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len, 189 data_buf); 190 } else { 191 trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len, 192 fault_ipa, 0); 193 194 ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len, 195 data_buf); 196 } 197 198 /* Now prepare kvm_run for the potential return to userland. */ 199 run->mmio.is_write = is_write; 200 run->mmio.phys_addr = fault_ipa; 201 run->mmio.len = len; 202 203 if (!ret) { 204 /* We handled the access successfully in the kernel. */ 205 if (!is_write) 206 memcpy(run->mmio.data, data_buf, len); 207 vcpu->stat.mmio_exit_kernel++; 208 kvm_handle_mmio_return(vcpu, run); 209 return 1; 210 } 211 212 if (is_write) 213 memcpy(run->mmio.data, data_buf, len); 214 vcpu->stat.mmio_exit_user++; 215 run->exit_reason = KVM_EXIT_MMIO; 216 return 0; 217}