Commit | Line | Data |
---|---|---|
45e96ea6 CD |
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 | */ | |
34 | int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) | |
35 | { | |
db730d8d | 36 | unsigned long *dest; |
45e96ea6 CD |
37 | unsigned int len; |
38 | int mask; | |
39 | ||
40 | if (!run->mmio.is_write) { | |
41 | dest = vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt); | |
f42798c6 | 42 | *dest = 0; |
45e96ea6 CD |
43 | |
44 | len = run->mmio.len; | |
f42798c6 | 45 | if (len > sizeof(unsigned long)) |
45e96ea6 CD |
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 | ||
f42798c6 MZ |
53 | if (vcpu->arch.mmio_decode.sign_extend && |
54 | len < sizeof(unsigned long)) { | |
45e96ea6 CD |
55 | mask = 1U << ((len * 8) - 1); |
56 | *dest = (*dest ^ mask) - mask; | |
57 | } | |
58 | } | |
59 | ||
60 | return 0; | |
61 | } | |
62 | ||
63 | static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | |
64 | struct kvm_exit_mmio *mmio) | |
65 | { | |
2184a60d CD |
66 | unsigned long rt; |
67 | int len; | |
45e96ea6 CD |
68 | bool is_write, sign_extend; |
69 | ||
78abfcde | 70 | if (kvm_vcpu_dabt_isextabt(vcpu)) { |
45e96ea6 | 71 | /* cache operation on I/O addr, tell guest unsupported */ |
7393b599 | 72 | kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); |
45e96ea6 CD |
73 | return 1; |
74 | } | |
75 | ||
b37670b0 | 76 | if (kvm_vcpu_dabt_iss1tw(vcpu)) { |
45e96ea6 | 77 | /* page table accesses IO mem: tell guest to fix its TTBR */ |
7393b599 | 78 | kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); |
45e96ea6 CD |
79 | return 1; |
80 | } | |
81 | ||
a7123377 MZ |
82 | len = kvm_vcpu_dabt_get_as(vcpu); |
83 | if (unlikely(len < 0)) | |
84 | return len; | |
45e96ea6 | 85 | |
023cc964 | 86 | is_write = kvm_vcpu_dabt_iswrite(vcpu); |
7c511b88 | 87 | sign_extend = kvm_vcpu_dabt_issext(vcpu); |
d0adf747 | 88 | rt = kvm_vcpu_dabt_get_rd(vcpu); |
45e96ea6 | 89 | |
45e96ea6 CD |
90 | mmio->is_write = is_write; |
91 | mmio->phys_addr = fault_ipa; | |
92 | mmio->len = len; | |
93 | vcpu->arch.mmio_decode.sign_extend = sign_extend; | |
94 | vcpu->arch.mmio_decode.rt = rt; | |
95 | ||
96 | /* | |
97 | * The MMIO instruction is emulated and should not be re-executed | |
98 | * in the guest. | |
99 | */ | |
23b415d6 | 100 | kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); |
45e96ea6 CD |
101 | return 0; |
102 | } | |
103 | ||
104 | int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, | |
105 | phys_addr_t fault_ipa) | |
106 | { | |
107 | struct kvm_exit_mmio mmio; | |
108 | unsigned long rt; | |
109 | int ret; | |
110 | ||
111 | /* | |
112 | * Prepare MMIO operation. First stash it in a private | |
113 | * structure that we can use for in-kernel emulation. If the | |
114 | * kernel can't handle it, copy it into run->mmio and let user | |
115 | * space do its magic. | |
116 | */ | |
117 | ||
4a1df28a | 118 | if (kvm_vcpu_dabt_isvalid(vcpu)) { |
45e96ea6 CD |
119 | ret = decode_hsr(vcpu, fault_ipa, &mmio); |
120 | if (ret) | |
121 | return ret; | |
122 | } else { | |
123 | kvm_err("load/store instruction decoding not implemented\n"); | |
124 | return -ENOSYS; | |
125 | } | |
126 | ||
127 | rt = vcpu->arch.mmio_decode.rt; | |
128 | trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE : | |
129 | KVM_TRACE_MMIO_READ_UNSATISFIED, | |
130 | mmio.len, fault_ipa, | |
131 | (mmio.is_write) ? *vcpu_reg(vcpu, rt) : 0); | |
132 | ||
133 | if (mmio.is_write) | |
134 | memcpy(mmio.data, vcpu_reg(vcpu, rt), mmio.len); | |
135 | ||
1a89dd91 MZ |
136 | if (vgic_handle_mmio(vcpu, run, &mmio)) |
137 | return 1; | |
138 | ||
45e96ea6 CD |
139 | kvm_prepare_mmio(run, &mmio); |
140 | return 0; | |
141 | } |