diff options
author | Eddie Dong <eddie.dong@intel.com> | 2009-11-19 10:54:07 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-01 10:35:38 -0500 |
commit | 3fd28fce765632d0fe46b31f63c0e7a7ec6c6b79 (patch) | |
tree | 0f73abea5061ce2d0c9a7fe744ac0cf4e882d687 | |
parent | 30ff056c42c665b9ea535d8515890857ae382540 (diff) |
KVM: x86: make double/triple fault promotion generic to all exceptions
Move Double-Fault generation logic out of page fault
exception generating function to cover more generic case.
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | arch/x86/kvm/x86.c | 89 |
1 files changed, 61 insertions, 28 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a1e1bc9d412d..8d860e0301a0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -257,12 +257,68 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) | |||
257 | } | 257 | } |
258 | EXPORT_SYMBOL_GPL(kvm_set_apic_base); | 258 | EXPORT_SYMBOL_GPL(kvm_set_apic_base); |
259 | 259 | ||
260 | #define EXCPT_BENIGN 0 | ||
261 | #define EXCPT_CONTRIBUTORY 1 | ||
262 | #define EXCPT_PF 2 | ||
263 | |||
264 | static int exception_class(int vector) | ||
265 | { | ||
266 | switch (vector) { | ||
267 | case PF_VECTOR: | ||
268 | return EXCPT_PF; | ||
269 | case DE_VECTOR: | ||
270 | case TS_VECTOR: | ||
271 | case NP_VECTOR: | ||
272 | case SS_VECTOR: | ||
273 | case GP_VECTOR: | ||
274 | return EXCPT_CONTRIBUTORY; | ||
275 | default: | ||
276 | break; | ||
277 | } | ||
278 | return EXCPT_BENIGN; | ||
279 | } | ||
280 | |||
281 | static void kvm_multiple_exception(struct kvm_vcpu *vcpu, | ||
282 | unsigned nr, bool has_error, u32 error_code) | ||
283 | { | ||
284 | u32 prev_nr; | ||
285 | int class1, class2; | ||
286 | |||
287 | if (!vcpu->arch.exception.pending) { | ||
288 | queue: | ||
289 | vcpu->arch.exception.pending = true; | ||
290 | vcpu->arch.exception.has_error_code = has_error; | ||
291 | vcpu->arch.exception.nr = nr; | ||
292 | vcpu->arch.exception.error_code = error_code; | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | /* to check exception */ | ||
297 | prev_nr = vcpu->arch.exception.nr; | ||
298 | if (prev_nr == DF_VECTOR) { | ||
299 | /* triple fault -> shutdown */ | ||
300 | set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); | ||
301 | return; | ||
302 | } | ||
303 | class1 = exception_class(prev_nr); | ||
304 | class2 = exception_class(nr); | ||
305 | if ((class1 == EXCPT_CONTRIBUTORY && class2 == EXCPT_CONTRIBUTORY) | ||
306 | || (class1 == EXCPT_PF && class2 != EXCPT_BENIGN)) { | ||
307 | /* generate double fault per SDM Table 5-5 */ | ||
308 | vcpu->arch.exception.pending = true; | ||
309 | vcpu->arch.exception.has_error_code = true; | ||
310 | vcpu->arch.exception.nr = DF_VECTOR; | ||
311 | vcpu->arch.exception.error_code = 0; | ||
312 | } else | ||
313 | /* replace previous exception with a new one in a hope | ||
314 | that instruction re-execution will regenerate lost | ||
315 | exception */ | ||
316 | goto queue; | ||
317 | } | ||
318 | |||
260 | void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr) | 319 | void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr) |
261 | { | 320 | { |
262 | WARN_ON(vcpu->arch.exception.pending); | 321 | kvm_multiple_exception(vcpu, nr, false, 0); |
263 | vcpu->arch.exception.pending = true; | ||
264 | vcpu->arch.exception.has_error_code = false; | ||
265 | vcpu->arch.exception.nr = nr; | ||
266 | } | 322 | } |
267 | EXPORT_SYMBOL_GPL(kvm_queue_exception); | 323 | EXPORT_SYMBOL_GPL(kvm_queue_exception); |
268 | 324 | ||
@@ -270,25 +326,6 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, | |||
270 | u32 error_code) | 326 | u32 error_code) |
271 | { | 327 | { |
272 | ++vcpu->stat.pf_guest; | 328 | ++vcpu->stat.pf_guest; |
273 | |||
274 | if (vcpu->arch.exception.pending) { | ||
275 | switch(vcpu->arch.exception.nr) { | ||
276 | case DF_VECTOR: | ||
277 | /* triple fault -> shutdown */ | ||
278 | set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); | ||
279 | return; | ||
280 | case PF_VECTOR: | ||
281 | vcpu->arch.exception.nr = DF_VECTOR; | ||
282 | vcpu->arch.exception.error_code = 0; | ||
283 | return; | ||
284 | default: | ||
285 | /* replace previous exception with a new one in a hope | ||
286 | that instruction re-execution will regenerate lost | ||
287 | exception */ | ||
288 | vcpu->arch.exception.pending = false; | ||
289 | break; | ||
290 | } | ||
291 | } | ||
292 | vcpu->arch.cr2 = addr; | 329 | vcpu->arch.cr2 = addr; |
293 | kvm_queue_exception_e(vcpu, PF_VECTOR, error_code); | 330 | kvm_queue_exception_e(vcpu, PF_VECTOR, error_code); |
294 | } | 331 | } |
@@ -301,11 +338,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_nmi); | |||
301 | 338 | ||
302 | void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) | 339 | void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) |
303 | { | 340 | { |
304 | WARN_ON(vcpu->arch.exception.pending); | 341 | kvm_multiple_exception(vcpu, nr, true, error_code); |
305 | vcpu->arch.exception.pending = true; | ||
306 | vcpu->arch.exception.has_error_code = true; | ||
307 | vcpu->arch.exception.nr = nr; | ||
308 | vcpu->arch.exception.error_code = error_code; | ||
309 | } | 342 | } |
310 | EXPORT_SYMBOL_GPL(kvm_queue_exception_e); | 343 | EXPORT_SYMBOL_GPL(kvm_queue_exception_e); |
311 | 344 | ||