aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kvm/emulate.c146
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
2592static 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
2611static 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
2628static 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
2645static 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
2663static 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
2672static 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
2592static bool valid_cr(int nr) 2681static 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;