linux/arch/arm/kvm/mmio.c
<<
>>
Prefs
   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
  26static void mmio_write_buf(char *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
  58static unsigned long mmio_read_buf(char *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 = buf[0];
  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 * @vcpu: The VCPU pointer
  91 * @run:  The VCPU run struct containing the mmio data
  92 *
  93 * This should only be called after returning from userspace for MMIO load
  94 * emulation.
  95 */
  96int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
  97{
  98        unsigned long data;
  99        unsigned int len;
 100        int mask;
 101
 102        if (!run->mmio.is_write) {
 103                len = run->mmio.len;
 104                if (len > sizeof(unsigned long))
 105                        return -EINVAL;
 106
 107                data = mmio_read_buf(run->mmio.data, len);
 108
 109                if (vcpu->arch.mmio_decode.sign_extend &&
 110                    len < sizeof(unsigned long)) {
 111                        mask = 1U << ((len * 8) - 1);
 112                        data = (data ^ mask) - mask;
 113                }
 114
 115                trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
 116                               data);
 117                data = vcpu_data_host_to_guest(vcpu, data, len);
 118                vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
 119        }
 120
 121        return 0;
 122}
 123
 124static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len)
 125{
 126        unsigned long rt;
 127        int access_size;
 128        bool sign_extend;
 129
 130        if (kvm_vcpu_dabt_isextabt(vcpu)) {
 131                /* cache operation on I/O addr, tell guest unsupported */
 132                kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
 133                return 1;
 134        }
 135
 136        if (kvm_vcpu_dabt_iss1tw(vcpu)) {
 137                /* page table accesses IO mem: tell guest to fix its TTBR */
 138                kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
 139                return 1;
 140        }
 141
 142        access_size = kvm_vcpu_dabt_get_as(vcpu);
 143        if (unlikely(access_size < 0))
 144                return access_size;
 145
 146        *is_write = kvm_vcpu_dabt_iswrite(vcpu);
 147        sign_extend = kvm_vcpu_dabt_issext(vcpu);
 148        rt = kvm_vcpu_dabt_get_rd(vcpu);
 149
 150        *len = access_size;
 151        vcpu->arch.mmio_decode.sign_extend = sign_extend;
 152        vcpu->arch.mmio_decode.rt = rt;
 153
 154        /*
 155         * The MMIO instruction is emulated and should not be re-executed
 156         * in the guest.
 157         */
 158        kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 159        return 0;
 160}
 161
 162int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 163                 phys_addr_t fault_ipa)
 164{
 165        unsigned long data;
 166        unsigned long rt;
 167        int ret;
 168        bool is_write;
 169        int len;
 170        u8 data_buf[8];
 171
 172        /*
 173         * Prepare MMIO operation. First decode the syndrome data we get
 174         * from the CPU. Then try if some in-kernel emulation feels
 175         * responsible, otherwise let user space do its magic.
 176         */
 177        if (kvm_vcpu_dabt_isvalid(vcpu)) {
 178                ret = decode_hsr(vcpu, &is_write, &len);
 179                if (ret)
 180                        return ret;
 181        } else {
 182                kvm_err("load/store instruction decoding not implemented\n");
 183                return -ENOSYS;
 184        }
 185
 186        rt = vcpu->arch.mmio_decode.rt;
 187
 188        if (is_write) {
 189                data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
 190                                               len);
 191
 192                trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
 193                mmio_write_buf(data_buf, len, data);
 194
 195                ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
 196                                       data_buf);
 197        } else {
 198                trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
 199                               fault_ipa, 0);
 200
 201                ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
 202                                      data_buf);
 203        }
 204
 205        /* Now prepare kvm_run for the potential return to userland. */
 206        run->mmio.is_write      = is_write;
 207        run->mmio.phys_addr     = fault_ipa;
 208        run->mmio.len           = len;
 209        if (is_write)
 210                memcpy(run->mmio.data, data_buf, len);
 211
 212        if (!ret) {
 213                /* We handled the access successfully in the kernel. */
 214                vcpu->stat.mmio_exit_kernel++;
 215                kvm_handle_mmio_return(vcpu, run);
 216                return 1;
 217        } else {
 218                vcpu->stat.mmio_exit_user++;
 219        }
 220
 221        run->exit_reason        = KVM_EXIT_MMIO;
 222        return 0;
 223}
 224