diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-04-04 06:39:28 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:57:01 -0400 |
commit | cfec82cb7d313ae5b2c2dbb974401d7c214c7b09 (patch) | |
tree | 63351befc6b9981127ac8dd2d22149d3ddf75806 /arch/x86/kvm/emulate.c | |
parent | 8a76d7f25f8f24fc5a328c8e15e4a7313cf141b9 (diff) |
KVM: SVM: Add intercept check for emulated cr accesses
This patch adds all necessary intercept checks for
instructions that access the crX registers.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 105 |
1 files changed, 94 insertions, 11 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e3e96eada6f3..d2e77755efe8 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2445,6 +2445,95 @@ static int em_movdqu(struct x86_emulate_ctxt *ctxt) | |||
2445 | return X86EMUL_CONTINUE; | 2445 | return X86EMUL_CONTINUE; |
2446 | } | 2446 | } |
2447 | 2447 | ||
2448 | static bool valid_cr(int nr) | ||
2449 | { | ||
2450 | switch (nr) { | ||
2451 | case 0: | ||
2452 | case 2 ... 4: | ||
2453 | case 8: | ||
2454 | return true; | ||
2455 | default: | ||
2456 | return false; | ||
2457 | } | ||
2458 | } | ||
2459 | |||
2460 | static int check_cr_read(struct x86_emulate_ctxt *ctxt) | ||
2461 | { | ||
2462 | struct decode_cache *c = &ctxt->decode; | ||
2463 | |||
2464 | if (!valid_cr(c->modrm_reg)) | ||
2465 | return emulate_ud(ctxt); | ||
2466 | |||
2467 | return X86EMUL_CONTINUE; | ||
2468 | } | ||
2469 | |||
2470 | static int check_cr_write(struct x86_emulate_ctxt *ctxt) | ||
2471 | { | ||
2472 | struct decode_cache *c = &ctxt->decode; | ||
2473 | u64 new_val = c->src.val64; | ||
2474 | int cr = c->modrm_reg; | ||
2475 | |||
2476 | static u64 cr_reserved_bits[] = { | ||
2477 | 0xffffffff00000000ULL, | ||
2478 | 0, 0, 0, /* CR3 checked later */ | ||
2479 | CR4_RESERVED_BITS, | ||
2480 | 0, 0, 0, | ||
2481 | CR8_RESERVED_BITS, | ||
2482 | }; | ||
2483 | |||
2484 | if (!valid_cr(cr)) | ||
2485 | return emulate_ud(ctxt); | ||
2486 | |||
2487 | if (new_val & cr_reserved_bits[cr]) | ||
2488 | return emulate_gp(ctxt, 0); | ||
2489 | |||
2490 | switch (cr) { | ||
2491 | case 0: { | ||
2492 | u64 cr4, efer; | ||
2493 | if (((new_val & X86_CR0_PG) && !(new_val & X86_CR0_PE)) || | ||
2494 | ((new_val & X86_CR0_NW) && !(new_val & X86_CR0_CD))) | ||
2495 | return emulate_gp(ctxt, 0); | ||
2496 | |||
2497 | cr4 = ctxt->ops->get_cr(4, ctxt->vcpu); | ||
2498 | ctxt->ops->get_msr(ctxt->vcpu, MSR_EFER, &efer); | ||
2499 | |||
2500 | if ((new_val & X86_CR0_PG) && (efer & EFER_LME) && | ||
2501 | !(cr4 & X86_CR4_PAE)) | ||
2502 | return emulate_gp(ctxt, 0); | ||
2503 | |||
2504 | break; | ||
2505 | } | ||
2506 | case 3: { | ||
2507 | u64 rsvd = 0; | ||
2508 | |||
2509 | if (is_long_mode(ctxt->vcpu)) | ||
2510 | rsvd = CR3_L_MODE_RESERVED_BITS; | ||
2511 | else if (is_pae(ctxt->vcpu)) | ||
2512 | rsvd = CR3_PAE_RESERVED_BITS; | ||
2513 | else if (is_paging(ctxt->vcpu)) | ||
2514 | rsvd = CR3_NONPAE_RESERVED_BITS; | ||
2515 | |||
2516 | if (new_val & rsvd) | ||
2517 | return emulate_gp(ctxt, 0); | ||
2518 | |||
2519 | break; | ||
2520 | } | ||
2521 | case 4: { | ||
2522 | u64 cr4, efer; | ||
2523 | |||
2524 | cr4 = ctxt->ops->get_cr(4, ctxt->vcpu); | ||
2525 | ctxt->ops->get_msr(ctxt->vcpu, MSR_EFER, &efer); | ||
2526 | |||
2527 | if ((efer & EFER_LMA) && !(new_val & X86_CR4_PAE)) | ||
2528 | return emulate_gp(ctxt, 0); | ||
2529 | |||
2530 | break; | ||
2531 | } | ||
2532 | } | ||
2533 | |||
2534 | return X86EMUL_CONTINUE; | ||
2535 | } | ||
2536 | |||
2448 | #define D(_y) { .flags = (_y) } | 2537 | #define D(_y) { .flags = (_y) } |
2449 | #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } | 2538 | #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } |
2450 | #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ | 2539 | #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ |
@@ -2632,14 +2721,16 @@ static struct opcode opcode_table[256] = { | |||
2632 | static struct opcode twobyte_table[256] = { | 2721 | static struct opcode twobyte_table[256] = { |
2633 | /* 0x00 - 0x0F */ | 2722 | /* 0x00 - 0x0F */ |
2634 | N, GD(0, &group7), N, N, | 2723 | N, GD(0, &group7), N, N, |
2635 | N, D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv), N, | 2724 | N, D(ImplicitOps | VendorSpecific), DI(ImplicitOps | Priv, clts), N, |
2636 | DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N, | 2725 | DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N, |
2637 | N, D(ImplicitOps | ModRM), N, N, | 2726 | N, D(ImplicitOps | ModRM), N, N, |
2638 | /* 0x10 - 0x1F */ | 2727 | /* 0x10 - 0x1F */ |
2639 | N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N, | 2728 | N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N, |
2640 | /* 0x20 - 0x2F */ | 2729 | /* 0x20 - 0x2F */ |
2641 | D(ModRM | DstMem | Priv | Op3264), D(ModRM | DstMem | Priv | Op3264), | 2730 | DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read), |
2642 | D(ModRM | SrcMem | Priv | Op3264), D(ModRM | SrcMem | Priv | Op3264), | 2731 | D(ModRM | DstMem | Priv | Op3264), |
2732 | DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write), | ||
2733 | D(ModRM | SrcMem | Priv | Op3264), | ||
2643 | N, N, N, N, | 2734 | N, N, N, N, |
2644 | N, N, N, N, N, N, N, N, | 2735 | N, N, N, N, N, N, N, N, |
2645 | /* 0x30 - 0x3F */ | 2736 | /* 0x30 - 0x3F */ |
@@ -3724,14 +3815,6 @@ twobyte_insn: | |||
3724 | case 0x18: /* Grp16 (prefetch/nop) */ | 3815 | case 0x18: /* Grp16 (prefetch/nop) */ |
3725 | break; | 3816 | break; |
3726 | case 0x20: /* mov cr, reg */ | 3817 | case 0x20: /* mov cr, reg */ |
3727 | switch (c->modrm_reg) { | ||
3728 | case 1: | ||
3729 | case 5 ... 7: | ||
3730 | case 9 ... 15: | ||
3731 | emulate_ud(ctxt); | ||
3732 | rc = X86EMUL_PROPAGATE_FAULT; | ||
3733 | goto done; | ||
3734 | } | ||
3735 | c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu); | 3818 | c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu); |
3736 | break; | 3819 | break; |
3737 | case 0x21: /* mov from dr to reg */ | 3820 | case 0x21: /* mov from dr to reg */ |