diff options
-rw-r--r-- | arch/x86/kvm/emulate.c | 146 |
1 files changed, 99 insertions, 47 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 77a5f54f151f..8e1d0c8196bd 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2589,6 +2589,95 @@ static int em_clts(struct x86_emulate_ctxt *ctxt) | |||
2589 | return X86EMUL_CONTINUE; | 2589 | return X86EMUL_CONTINUE; |
2590 | } | 2590 | } |
2591 | 2591 | ||
2592 | static int em_vmcall(struct x86_emulate_ctxt *ctxt) | ||
2593 | { | ||
2594 | struct decode_cache *c = &ctxt->decode; | ||
2595 | int rc; | ||
2596 | |||
2597 | if (c->modrm_mod != 3 || c->modrm_rm != 1) | ||
2598 | return X86EMUL_UNHANDLEABLE; | ||
2599 | |||
2600 | rc = ctxt->ops->fix_hypercall(ctxt); | ||
2601 | if (rc != X86EMUL_CONTINUE) | ||
2602 | return rc; | ||
2603 | |||
2604 | /* Let the processor re-execute the fixed hypercall */ | ||
2605 | c->eip = ctxt->eip; | ||
2606 | /* Disable writeback. */ | ||
2607 | c->dst.type = OP_NONE; | ||
2608 | return X86EMUL_CONTINUE; | ||
2609 | } | ||
2610 | |||
2611 | static int em_lgdt(struct x86_emulate_ctxt *ctxt) | ||
2612 | { | ||
2613 | struct decode_cache *c = &ctxt->decode; | ||
2614 | struct desc_ptr desc_ptr; | ||
2615 | int rc; | ||
2616 | |||
2617 | rc = read_descriptor(ctxt, ctxt->ops, c->src.addr.mem, | ||
2618 | &desc_ptr.size, &desc_ptr.address, | ||
2619 | c->op_bytes); | ||
2620 | if (rc != X86EMUL_CONTINUE) | ||
2621 | return rc; | ||
2622 | ctxt->ops->set_gdt(ctxt, &desc_ptr); | ||
2623 | /* Disable writeback. */ | ||
2624 | c->dst.type = OP_NONE; | ||
2625 | return X86EMUL_CONTINUE; | ||
2626 | } | ||
2627 | |||
2628 | static int em_svm(struct x86_emulate_ctxt *ctxt) | ||
2629 | { | ||
2630 | struct decode_cache *c = &ctxt->decode; | ||
2631 | int rc; | ||
2632 | |||
2633 | switch (c->modrm_rm) { | ||
2634 | case 1: | ||
2635 | rc = ctxt->ops->fix_hypercall(ctxt); | ||
2636 | break; | ||
2637 | default: | ||
2638 | return X86EMUL_UNHANDLEABLE; | ||
2639 | } | ||
2640 | /* Disable writeback. */ | ||
2641 | c->dst.type = OP_NONE; | ||
2642 | return rc; | ||
2643 | } | ||
2644 | |||
2645 | static int em_lidt(struct x86_emulate_ctxt *ctxt) | ||
2646 | { | ||
2647 | struct decode_cache *c = &ctxt->decode; | ||
2648 | struct desc_ptr desc_ptr; | ||
2649 | int rc; | ||
2650 | |||
2651 | rc = read_descriptor(ctxt, ctxt->ops, c->src.addr.mem, | ||
2652 | &desc_ptr.size, | ||
2653 | &desc_ptr.address, | ||
2654 | c->op_bytes); | ||
2655 | if (rc != X86EMUL_CONTINUE) | ||
2656 | return rc; | ||
2657 | ctxt->ops->set_idt(ctxt, &desc_ptr); | ||
2658 | /* Disable writeback. */ | ||
2659 | c->dst.type = OP_NONE; | ||
2660 | return X86EMUL_CONTINUE; | ||
2661 | } | ||
2662 | |||
2663 | static int em_smsw(struct x86_emulate_ctxt *ctxt) | ||
2664 | { | ||
2665 | struct decode_cache *c = &ctxt->decode; | ||
2666 | |||
2667 | c->dst.bytes = 2; | ||
2668 | c->dst.val = ctxt->ops->get_cr(ctxt, 0); | ||
2669 | return X86EMUL_CONTINUE; | ||
2670 | } | ||
2671 | |||
2672 | static int em_lmsw(struct x86_emulate_ctxt *ctxt) | ||
2673 | { | ||
2674 | struct decode_cache *c = &ctxt->decode; | ||
2675 | ctxt->ops->set_cr(ctxt, 0, (ctxt->ops->get_cr(ctxt, 0) & ~0x0eul) | ||
2676 | | (c->src.val & 0x0f)); | ||
2677 | c->dst.type = OP_NONE; | ||
2678 | return X86EMUL_CONTINUE; | ||
2679 | } | ||
2680 | |||
2592 | static bool valid_cr(int nr) | 2681 | static bool valid_cr(int nr) |
2593 | { | 2682 | { |
2594 | switch (nr) { | 2683 | switch (nr) { |
@@ -3509,7 +3598,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) | |||
3509 | int rc = X86EMUL_CONTINUE; | 3598 | int rc = X86EMUL_CONTINUE; |
3510 | int saved_dst_type = c->dst.type; | 3599 | int saved_dst_type = c->dst.type; |
3511 | int irq; /* Used for int 3, int, and into */ | 3600 | int irq; /* Used for int 3, int, and into */ |
3512 | struct desc_ptr desc_ptr; | ||
3513 | 3601 | ||
3514 | ctxt->decode.mem_read.pos = 0; | 3602 | ctxt->decode.mem_read.pos = 0; |
3515 | 3603 | ||
@@ -4022,62 +4110,26 @@ twobyte_insn: | |||
4022 | case 0x01: /* lgdt, lidt, lmsw */ | 4110 | case 0x01: /* lgdt, lidt, lmsw */ |
4023 | switch (c->modrm_reg) { | 4111 | switch (c->modrm_reg) { |
4024 | case 0: /* vmcall */ | 4112 | case 0: /* vmcall */ |
4025 | if (c->modrm_mod != 3 || c->modrm_rm != 1) | 4113 | rc = em_vmcall(ctxt); |
4026 | goto cannot_emulate; | ||
4027 | |||
4028 | rc = ctxt->ops->fix_hypercall(ctxt); | ||
4029 | if (rc != X86EMUL_CONTINUE) | ||
4030 | goto done; | ||
4031 | |||
4032 | /* Let the processor re-execute the fixed hypercall */ | ||
4033 | c->eip = ctxt->eip; | ||
4034 | /* Disable writeback. */ | ||
4035 | c->dst.type = OP_NONE; | ||
4036 | break; | 4114 | break; |
4037 | case 2: /* lgdt */ | 4115 | case 2: /* lgdt */ |
4038 | rc = read_descriptor(ctxt, ops, c->src.addr.mem, | 4116 | rc = em_lgdt(ctxt); |
4039 | &desc_ptr.size, &desc_ptr.address, | ||
4040 | c->op_bytes); | ||
4041 | if (rc != X86EMUL_CONTINUE) | ||
4042 | goto done; | ||
4043 | ctxt->ops->set_gdt(ctxt, &desc_ptr); | ||
4044 | /* Disable writeback. */ | ||
4045 | c->dst.type = OP_NONE; | ||
4046 | break; | 4117 | break; |
4047 | case 3: /* lidt/vmmcall */ | 4118 | case 3: /* lidt/vmmcall */ |
4048 | if (c->modrm_mod == 3) { | 4119 | if (c->modrm_mod == 3) |
4049 | switch (c->modrm_rm) { | 4120 | return em_svm(ctxt); |
4050 | case 1: | 4121 | else |
4051 | rc = ctxt->ops->fix_hypercall(ctxt); | 4122 | return em_lidt(ctxt); |
4052 | break; | ||
4053 | default: | ||
4054 | goto cannot_emulate; | ||
4055 | } | ||
4056 | } else { | ||
4057 | rc = read_descriptor(ctxt, ops, c->src.addr.mem, | ||
4058 | &desc_ptr.size, | ||
4059 | &desc_ptr.address, | ||
4060 | c->op_bytes); | ||
4061 | if (rc != X86EMUL_CONTINUE) | ||
4062 | goto done; | ||
4063 | ctxt->ops->set_idt(ctxt, &desc_ptr); | ||
4064 | } | ||
4065 | /* Disable writeback. */ | ||
4066 | c->dst.type = OP_NONE; | ||
4067 | break; | 4123 | break; |
4068 | case 4: /* smsw */ | 4124 | case 4: /* smsw */ |
4069 | c->dst.bytes = 2; | 4125 | rc = em_smsw(ctxt); |
4070 | c->dst.val = ops->get_cr(ctxt, 0); | ||
4071 | break; | 4126 | break; |
4072 | case 6: /* lmsw */ | 4127 | case 6: /* lmsw */ |
4073 | ops->set_cr(ctxt, 0, (ops->get_cr(ctxt, 0) & ~0x0eul) | | 4128 | rc = em_lmsw(ctxt); |
4074 | (c->src.val & 0x0f)); | ||
4075 | c->dst.type = OP_NONE; | ||
4076 | break; | 4129 | break; |
4077 | case 5: /* not defined */ | 4130 | case 5: /* not defined */ |
4078 | emulate_ud(ctxt); | 4131 | rc = emulate_ud(ctxt); |
4079 | rc = X86EMUL_PROPAGATE_FAULT; | 4132 | break; |
4080 | goto done; | ||
4081 | case 7: /* invlpg*/ | 4133 | case 7: /* invlpg*/ |
4082 | rc = em_invlpg(ctxt); | 4134 | rc = em_invlpg(ctxt); |
4083 | break; | 4135 | break; |