diff options
Diffstat (limited to 'arch/powerpc/kvm/booke.c')
-rw-r--r-- | arch/powerpc/kvm/booke.c | 175 |
1 files changed, 55 insertions, 120 deletions
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 0f064719162c..ec59a6768ec3 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -55,64 +55,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
55 | { NULL } | 55 | { NULL } |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static const u32 interrupt_msr_mask[16] = { | ||
59 | [BOOKE_INTERRUPT_CRITICAL] = MSR_ME, | ||
60 | [BOOKE_INTERRUPT_MACHINE_CHECK] = 0, | ||
61 | [BOOKE_INTERRUPT_DATA_STORAGE] = MSR_CE|MSR_ME|MSR_DE, | ||
62 | [BOOKE_INTERRUPT_INST_STORAGE] = MSR_CE|MSR_ME|MSR_DE, | ||
63 | [BOOKE_INTERRUPT_EXTERNAL] = MSR_CE|MSR_ME|MSR_DE, | ||
64 | [BOOKE_INTERRUPT_ALIGNMENT] = MSR_CE|MSR_ME|MSR_DE, | ||
65 | [BOOKE_INTERRUPT_PROGRAM] = MSR_CE|MSR_ME|MSR_DE, | ||
66 | [BOOKE_INTERRUPT_FP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE, | ||
67 | [BOOKE_INTERRUPT_SYSCALL] = MSR_CE|MSR_ME|MSR_DE, | ||
68 | [BOOKE_INTERRUPT_AP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE, | ||
69 | [BOOKE_INTERRUPT_DECREMENTER] = MSR_CE|MSR_ME|MSR_DE, | ||
70 | [BOOKE_INTERRUPT_FIT] = MSR_CE|MSR_ME|MSR_DE, | ||
71 | [BOOKE_INTERRUPT_WATCHDOG] = MSR_ME, | ||
72 | [BOOKE_INTERRUPT_DTLB_MISS] = MSR_CE|MSR_ME|MSR_DE, | ||
73 | [BOOKE_INTERRUPT_ITLB_MISS] = MSR_CE|MSR_ME|MSR_DE, | ||
74 | [BOOKE_INTERRUPT_DEBUG] = MSR_ME, | ||
75 | }; | ||
76 | |||
77 | const unsigned char exception_priority[] = { | ||
78 | [BOOKE_INTERRUPT_DATA_STORAGE] = 0, | ||
79 | [BOOKE_INTERRUPT_INST_STORAGE] = 1, | ||
80 | [BOOKE_INTERRUPT_ALIGNMENT] = 2, | ||
81 | [BOOKE_INTERRUPT_PROGRAM] = 3, | ||
82 | [BOOKE_INTERRUPT_FP_UNAVAIL] = 4, | ||
83 | [BOOKE_INTERRUPT_SYSCALL] = 5, | ||
84 | [BOOKE_INTERRUPT_AP_UNAVAIL] = 6, | ||
85 | [BOOKE_INTERRUPT_DTLB_MISS] = 7, | ||
86 | [BOOKE_INTERRUPT_ITLB_MISS] = 8, | ||
87 | [BOOKE_INTERRUPT_MACHINE_CHECK] = 9, | ||
88 | [BOOKE_INTERRUPT_DEBUG] = 10, | ||
89 | [BOOKE_INTERRUPT_CRITICAL] = 11, | ||
90 | [BOOKE_INTERRUPT_WATCHDOG] = 12, | ||
91 | [BOOKE_INTERRUPT_EXTERNAL] = 13, | ||
92 | [BOOKE_INTERRUPT_FIT] = 14, | ||
93 | [BOOKE_INTERRUPT_DECREMENTER] = 15, | ||
94 | }; | ||
95 | |||
96 | const unsigned char priority_exception[] = { | ||
97 | BOOKE_INTERRUPT_DATA_STORAGE, | ||
98 | BOOKE_INTERRUPT_INST_STORAGE, | ||
99 | BOOKE_INTERRUPT_ALIGNMENT, | ||
100 | BOOKE_INTERRUPT_PROGRAM, | ||
101 | BOOKE_INTERRUPT_FP_UNAVAIL, | ||
102 | BOOKE_INTERRUPT_SYSCALL, | ||
103 | BOOKE_INTERRUPT_AP_UNAVAIL, | ||
104 | BOOKE_INTERRUPT_DTLB_MISS, | ||
105 | BOOKE_INTERRUPT_ITLB_MISS, | ||
106 | BOOKE_INTERRUPT_MACHINE_CHECK, | ||
107 | BOOKE_INTERRUPT_DEBUG, | ||
108 | BOOKE_INTERRUPT_CRITICAL, | ||
109 | BOOKE_INTERRUPT_WATCHDOG, | ||
110 | BOOKE_INTERRUPT_EXTERNAL, | ||
111 | BOOKE_INTERRUPT_FIT, | ||
112 | BOOKE_INTERRUPT_DECREMENTER, | ||
113 | }; | ||
114 | |||
115 | |||
116 | /* TODO: use vcpu_printf() */ | 58 | /* TODO: use vcpu_printf() */ |
117 | void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) | 59 | void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) |
118 | { | 60 | { |
@@ -133,103 +75,96 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) | |||
133 | } | 75 | } |
134 | } | 76 | } |
135 | 77 | ||
136 | static void kvmppc_booke_queue_exception(struct kvm_vcpu *vcpu, int exception) | 78 | static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, |
79 | unsigned int priority) | ||
137 | { | 80 | { |
138 | unsigned int priority = exception_priority[exception]; | ||
139 | set_bit(priority, &vcpu->arch.pending_exceptions); | 81 | set_bit(priority, &vcpu->arch.pending_exceptions); |
140 | } | 82 | } |
141 | 83 | ||
142 | static void kvmppc_booke_clear_exception(struct kvm_vcpu *vcpu, int exception) | ||
143 | { | ||
144 | unsigned int priority = exception_priority[exception]; | ||
145 | clear_bit(priority, &vcpu->arch.pending_exceptions); | ||
146 | } | ||
147 | |||
148 | void kvmppc_core_queue_program(struct kvm_vcpu *vcpu) | 84 | void kvmppc_core_queue_program(struct kvm_vcpu *vcpu) |
149 | { | 85 | { |
150 | kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM); | 86 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM); |
151 | } | 87 | } |
152 | 88 | ||
153 | void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) | 89 | void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) |
154 | { | 90 | { |
155 | kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_DECREMENTER); | 91 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DECREMENTER); |
156 | } | 92 | } |
157 | 93 | ||
158 | int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) | 94 | int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) |
159 | { | 95 | { |
160 | unsigned int priority = exception_priority[BOOKE_INTERRUPT_DECREMENTER]; | 96 | return test_bit(BOOKE_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions); |
161 | return test_bit(priority, &vcpu->arch.pending_exceptions); | ||
162 | } | 97 | } |
163 | 98 | ||
164 | void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | 99 | void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, |
165 | struct kvm_interrupt *irq) | 100 | struct kvm_interrupt *irq) |
166 | { | 101 | { |
167 | kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_EXTERNAL); | 102 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL); |
168 | } | 103 | } |
169 | 104 | ||
170 | /* Check if we are ready to deliver the interrupt */ | 105 | /* Deliver the interrupt of the corresponding priority, if possible. */ |
171 | static int kvmppc_can_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt) | 106 | static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, |
107 | unsigned int priority) | ||
172 | { | 108 | { |
173 | int r; | 109 | int allowed = 0; |
174 | 110 | ulong msr_mask; | |
175 | switch (interrupt) { | 111 | |
176 | case BOOKE_INTERRUPT_CRITICAL: | 112 | switch (priority) { |
177 | r = vcpu->arch.msr & MSR_CE; | 113 | case BOOKE_IRQPRIO_PROGRAM: |
114 | case BOOKE_IRQPRIO_DTLB_MISS: | ||
115 | case BOOKE_IRQPRIO_ITLB_MISS: | ||
116 | case BOOKE_IRQPRIO_SYSCALL: | ||
117 | case BOOKE_IRQPRIO_DATA_STORAGE: | ||
118 | case BOOKE_IRQPRIO_INST_STORAGE: | ||
119 | case BOOKE_IRQPRIO_FP_UNAVAIL: | ||
120 | case BOOKE_IRQPRIO_AP_UNAVAIL: | ||
121 | case BOOKE_IRQPRIO_ALIGNMENT: | ||
122 | allowed = 1; | ||
123 | msr_mask = MSR_CE|MSR_ME|MSR_DE; | ||
178 | break; | 124 | break; |
179 | case BOOKE_INTERRUPT_MACHINE_CHECK: | 125 | case BOOKE_IRQPRIO_CRITICAL: |
180 | r = vcpu->arch.msr & MSR_ME; | 126 | case BOOKE_IRQPRIO_WATCHDOG: |
127 | allowed = vcpu->arch.msr & MSR_CE; | ||
128 | msr_mask = MSR_ME; | ||
181 | break; | 129 | break; |
182 | case BOOKE_INTERRUPT_EXTERNAL: | 130 | case BOOKE_IRQPRIO_MACHINE_CHECK: |
183 | r = vcpu->arch.msr & MSR_EE; | 131 | allowed = vcpu->arch.msr & MSR_ME; |
184 | break; | 132 | msr_mask = 0; |
185 | case BOOKE_INTERRUPT_DECREMENTER: | ||
186 | r = vcpu->arch.msr & MSR_EE; | ||
187 | break; | 133 | break; |
188 | case BOOKE_INTERRUPT_FIT: | 134 | case BOOKE_IRQPRIO_EXTERNAL: |
189 | r = vcpu->arch.msr & MSR_EE; | 135 | case BOOKE_IRQPRIO_DECREMENTER: |
136 | case BOOKE_IRQPRIO_FIT: | ||
137 | allowed = vcpu->arch.msr & MSR_EE; | ||
138 | msr_mask = MSR_CE|MSR_ME|MSR_DE; | ||
190 | break; | 139 | break; |
191 | case BOOKE_INTERRUPT_WATCHDOG: | 140 | case BOOKE_IRQPRIO_DEBUG: |
192 | r = vcpu->arch.msr & MSR_CE; | 141 | allowed = vcpu->arch.msr & MSR_DE; |
142 | msr_mask = MSR_ME; | ||
193 | break; | 143 | break; |
194 | case BOOKE_INTERRUPT_DEBUG: | ||
195 | r = vcpu->arch.msr & MSR_DE; | ||
196 | break; | ||
197 | default: | ||
198 | r = 1; | ||
199 | } | 144 | } |
200 | 145 | ||
201 | return r; | 146 | if (allowed) { |
202 | } | 147 | vcpu->arch.srr0 = vcpu->arch.pc; |
148 | vcpu->arch.srr1 = vcpu->arch.msr; | ||
149 | vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority]; | ||
150 | kvmppc_set_msr(vcpu, vcpu->arch.msr & msr_mask); | ||
203 | 151 | ||
204 | static void kvmppc_booke_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt) | 152 | clear_bit(priority, &vcpu->arch.pending_exceptions); |
205 | { | ||
206 | switch (interrupt) { | ||
207 | case BOOKE_INTERRUPT_DECREMENTER: | ||
208 | vcpu->arch.tsr |= TSR_DIS; | ||
209 | break; | ||
210 | } | 153 | } |
211 | 154 | ||
212 | vcpu->arch.srr0 = vcpu->arch.pc; | 155 | return allowed; |
213 | vcpu->arch.srr1 = vcpu->arch.msr; | ||
214 | vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[interrupt]; | ||
215 | kvmppc_set_msr(vcpu, vcpu->arch.msr & interrupt_msr_mask[interrupt]); | ||
216 | } | 156 | } |
217 | 157 | ||
218 | /* Check pending exceptions and deliver one, if possible. */ | 158 | /* Check pending exceptions and deliver one, if possible. */ |
219 | void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | 159 | void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) |
220 | { | 160 | { |
221 | unsigned long *pending = &vcpu->arch.pending_exceptions; | 161 | unsigned long *pending = &vcpu->arch.pending_exceptions; |
222 | unsigned int exception; | ||
223 | unsigned int priority; | 162 | unsigned int priority; |
224 | 163 | ||
225 | priority = __ffs(*pending); | 164 | priority = __ffs(*pending); |
226 | while (priority <= BOOKE_MAX_INTERRUPT) { | 165 | while (priority <= BOOKE_MAX_INTERRUPT) { |
227 | exception = priority_exception[priority]; | 166 | if (kvmppc_booke_irqprio_deliver(vcpu, priority)) |
228 | if (kvmppc_can_deliver_interrupt(vcpu, exception)) { | ||
229 | kvmppc_booke_clear_exception(vcpu, exception); | ||
230 | kvmppc_booke_deliver_interrupt(vcpu, exception); | ||
231 | break; | 167 | break; |
232 | } | ||
233 | 168 | ||
234 | priority = find_next_bit(pending, | 169 | priority = find_next_bit(pending, |
235 | BITS_PER_BYTE * sizeof(*pending), | 170 | BITS_PER_BYTE * sizeof(*pending), |
@@ -287,7 +222,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
287 | /* Program traps generated by user-level software must be handled | 222 | /* Program traps generated by user-level software must be handled |
288 | * by the guest kernel. */ | 223 | * by the guest kernel. */ |
289 | vcpu->arch.esr = vcpu->arch.fault_esr; | 224 | vcpu->arch.esr = vcpu->arch.fault_esr; |
290 | kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM); | 225 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM); |
291 | r = RESUME_GUEST; | 226 | r = RESUME_GUEST; |
292 | break; | 227 | break; |
293 | } | 228 | } |
@@ -321,27 +256,27 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
321 | break; | 256 | break; |
322 | 257 | ||
323 | case BOOKE_INTERRUPT_FP_UNAVAIL: | 258 | case BOOKE_INTERRUPT_FP_UNAVAIL: |
324 | kvmppc_booke_queue_exception(vcpu, exit_nr); | 259 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_FP_UNAVAIL); |
325 | r = RESUME_GUEST; | 260 | r = RESUME_GUEST; |
326 | break; | 261 | break; |
327 | 262 | ||
328 | case BOOKE_INTERRUPT_DATA_STORAGE: | 263 | case BOOKE_INTERRUPT_DATA_STORAGE: |
329 | vcpu->arch.dear = vcpu->arch.fault_dear; | 264 | vcpu->arch.dear = vcpu->arch.fault_dear; |
330 | vcpu->arch.esr = vcpu->arch.fault_esr; | 265 | vcpu->arch.esr = vcpu->arch.fault_esr; |
331 | kvmppc_booke_queue_exception(vcpu, exit_nr); | 266 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DATA_STORAGE); |
332 | vcpu->stat.dsi_exits++; | 267 | vcpu->stat.dsi_exits++; |
333 | r = RESUME_GUEST; | 268 | r = RESUME_GUEST; |
334 | break; | 269 | break; |
335 | 270 | ||
336 | case BOOKE_INTERRUPT_INST_STORAGE: | 271 | case BOOKE_INTERRUPT_INST_STORAGE: |
337 | vcpu->arch.esr = vcpu->arch.fault_esr; | 272 | vcpu->arch.esr = vcpu->arch.fault_esr; |
338 | kvmppc_booke_queue_exception(vcpu, exit_nr); | 273 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_INST_STORAGE); |
339 | vcpu->stat.isi_exits++; | 274 | vcpu->stat.isi_exits++; |
340 | r = RESUME_GUEST; | 275 | r = RESUME_GUEST; |
341 | break; | 276 | break; |
342 | 277 | ||
343 | case BOOKE_INTERRUPT_SYSCALL: | 278 | case BOOKE_INTERRUPT_SYSCALL: |
344 | kvmppc_booke_queue_exception(vcpu, exit_nr); | 279 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL); |
345 | vcpu->stat.syscall_exits++; | 280 | vcpu->stat.syscall_exits++; |
346 | r = RESUME_GUEST; | 281 | r = RESUME_GUEST; |
347 | break; | 282 | break; |
@@ -355,7 +290,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
355 | gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr); | 290 | gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr); |
356 | if (!gtlbe) { | 291 | if (!gtlbe) { |
357 | /* The guest didn't have a mapping for it. */ | 292 | /* The guest didn't have a mapping for it. */ |
358 | kvmppc_booke_queue_exception(vcpu, exit_nr); | 293 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS); |
359 | vcpu->arch.dear = vcpu->arch.fault_dear; | 294 | vcpu->arch.dear = vcpu->arch.fault_dear; |
360 | vcpu->arch.esr = vcpu->arch.fault_esr; | 295 | vcpu->arch.esr = vcpu->arch.fault_esr; |
361 | vcpu->stat.dtlb_real_miss_exits++; | 296 | vcpu->stat.dtlb_real_miss_exits++; |
@@ -398,7 +333,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
398 | gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr); | 333 | gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr); |
399 | if (!gtlbe) { | 334 | if (!gtlbe) { |
400 | /* The guest didn't have a mapping for it. */ | 335 | /* The guest didn't have a mapping for it. */ |
401 | kvmppc_booke_queue_exception(vcpu, exit_nr); | 336 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS); |
402 | vcpu->stat.itlb_real_miss_exits++; | 337 | vcpu->stat.itlb_real_miss_exits++; |
403 | break; | 338 | break; |
404 | } | 339 | } |
@@ -418,7 +353,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
418 | gtlbe->word2); | 353 | gtlbe->word2); |
419 | } else { | 354 | } else { |
420 | /* Guest mapped and leaped at non-RAM! */ | 355 | /* Guest mapped and leaped at non-RAM! */ |
421 | kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_MACHINE_CHECK); | 356 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_MACHINE_CHECK); |
422 | } | 357 | } |
423 | 358 | ||
424 | break; | 359 | break; |