]>
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); | |
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 | ||
62 | static 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 | ||
7393b599 | 68 | if ((kvm_vcpu_get_hsr(vcpu) >> 8) & 1) { |
45e96ea6 | 69 | /* cache operation on I/O addr, tell guest unsupported */ |
7393b599 | 70 | kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); |
45e96ea6 CD |
71 | return 1; |
72 | } | |
73 | ||
7393b599 | 74 | if ((kvm_vcpu_get_hsr(vcpu) >> 7) & 1) { |
45e96ea6 | 75 | /* page table accesses IO mem: tell guest to fix its TTBR */ |
7393b599 | 76 | kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); |
45e96ea6 CD |
77 | return 1; |
78 | } | |
79 | ||
7393b599 | 80 | switch ((kvm_vcpu_get_hsr(vcpu) >> 22) & 0x3) { |
45e96ea6 CD |
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 | ||
7393b599 MZ |
95 | is_write = kvm_vcpu_get_hsr(vcpu) & HSR_WNR; |
96 | sign_extend = kvm_vcpu_get_hsr(vcpu) & HSR_SSE; | |
97 | rt = (kvm_vcpu_get_hsr(vcpu) & HSR_SRT_MASK) >> HSR_SRT_SHIFT; | |
45e96ea6 CD |
98 | |
99 | if (kvm_vcpu_reg_is_pc(vcpu, rt)) { | |
100 | /* IO memory trying to read/write pc */ | |
7393b599 | 101 | kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu)); |
45e96ea6 CD |
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 | */ | |
7393b599 | 115 | kvm_skip_instr(vcpu, (kvm_vcpu_get_hsr(vcpu) >> 25) & 1); |
45e96ea6 CD |
116 | return 0; |
117 | } | |
118 | ||
119 | int 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 | ||
4a1df28a | 133 | if (kvm_vcpu_dabt_isvalid(vcpu)) { |
45e96ea6 CD |
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 | ||
1a89dd91 MZ |
151 | if (vgic_handle_mmio(vcpu, run, &mmio)) |
152 | return 1; | |
153 | ||
45e96ea6 CD |
154 | kvm_prepare_mmio(run, &mmio); |
155 | return 0; | |
156 | } |