diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 3 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 30 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 177 |
3 files changed, 151 insertions, 59 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f9a2f66530cf..06d9e79ca37d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -614,8 +614,7 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, | |||
614 | unsigned long value); | 614 | unsigned long value); |
615 | 615 | ||
616 | void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); | 616 | void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); |
617 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, | 617 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); |
618 | int type_bits, int seg); | ||
619 | 618 | ||
620 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason); | 619 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason); |
621 | 620 | ||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 2db760ff887c..a1a7b27adf41 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -1309,7 +1309,7 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, | |||
1309 | if (rc != 0) | 1309 | if (rc != 0) |
1310 | return rc; | 1310 | return rc; |
1311 | 1311 | ||
1312 | rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, 1, seg); | 1312 | rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, seg); |
1313 | return rc; | 1313 | return rc; |
1314 | } | 1314 | } |
1315 | 1315 | ||
@@ -1491,7 +1491,7 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt, | |||
1491 | rc = emulate_pop(ctxt, ops, &cs, c->op_bytes); | 1491 | rc = emulate_pop(ctxt, ops, &cs, c->op_bytes); |
1492 | if (rc) | 1492 | if (rc) |
1493 | return rc; | 1493 | return rc; |
1494 | rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, 1, VCPU_SREG_CS); | 1494 | rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, VCPU_SREG_CS); |
1495 | return rc; | 1495 | return rc; |
1496 | } | 1496 | } |
1497 | 1497 | ||
@@ -2122,12 +2122,11 @@ special_insn: | |||
2122 | break; | 2122 | break; |
2123 | case 0x8e: { /* mov seg, r/m16 */ | 2123 | case 0x8e: { /* mov seg, r/m16 */ |
2124 | uint16_t sel; | 2124 | uint16_t sel; |
2125 | int type_bits; | ||
2126 | int err; | ||
2127 | 2125 | ||
2128 | sel = c->src.val; | 2126 | sel = c->src.val; |
2129 | 2127 | ||
2130 | if (c->modrm_reg == VCPU_SREG_CS) { | 2128 | if (c->modrm_reg == VCPU_SREG_CS || |
2129 | c->modrm_reg > VCPU_SREG_GS) { | ||
2131 | kvm_queue_exception(ctxt->vcpu, UD_VECTOR); | 2130 | kvm_queue_exception(ctxt->vcpu, UD_VECTOR); |
2132 | goto done; | 2131 | goto done; |
2133 | } | 2132 | } |
@@ -2135,18 +2134,7 @@ special_insn: | |||
2135 | if (c->modrm_reg == VCPU_SREG_SS) | 2134 | if (c->modrm_reg == VCPU_SREG_SS) |
2136 | toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS); | 2135 | toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS); |
2137 | 2136 | ||
2138 | if (c->modrm_reg <= 5) { | 2137 | rc = kvm_load_segment_descriptor(ctxt->vcpu, sel, c->modrm_reg); |
2139 | type_bits = (c->modrm_reg == 1) ? 9 : 1; | ||
2140 | err = kvm_load_segment_descriptor(ctxt->vcpu, sel, | ||
2141 | type_bits, c->modrm_reg); | ||
2142 | } else { | ||
2143 | printk(KERN_INFO "Invalid segreg in modrm byte 0x%02x\n", | ||
2144 | c->modrm); | ||
2145 | goto cannot_emulate; | ||
2146 | } | ||
2147 | |||
2148 | if (err < 0) | ||
2149 | goto cannot_emulate; | ||
2150 | 2138 | ||
2151 | c->dst.type = OP_NONE; /* Disable writeback. */ | 2139 | c->dst.type = OP_NONE; /* Disable writeback. */ |
2152 | break; | 2140 | break; |
@@ -2320,11 +2308,9 @@ special_insn: | |||
2320 | case 0xe9: /* jmp rel */ | 2308 | case 0xe9: /* jmp rel */ |
2321 | goto jmp; | 2309 | goto jmp; |
2322 | case 0xea: /* jmp far */ | 2310 | case 0xea: /* jmp far */ |
2323 | if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val, 9, | 2311 | if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val, |
2324 | VCPU_SREG_CS) < 0) { | 2312 | VCPU_SREG_CS)) |
2325 | DPRINTF("jmp far: Failed to load CS descriptor\n"); | 2313 | goto done; |
2326 | goto cannot_emulate; | ||
2327 | } | ||
2328 | 2314 | ||
2329 | c->eip = c->src.val; | 2315 | c->eip = c->src.val; |
2330 | break; | 2316 | break; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 203ee7d0ed58..c3d2acbbb91b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4787,7 +4787,7 @@ static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int se | |||
4787 | .unusable = 0, | 4787 | .unusable = 0, |
4788 | }; | 4788 | }; |
4789 | kvm_x86_ops->set_segment(vcpu, &segvar, seg); | 4789 | kvm_x86_ops->set_segment(vcpu, &segvar, seg); |
4790 | return 0; | 4790 | return X86EMUL_CONTINUE; |
4791 | } | 4791 | } |
4792 | 4792 | ||
4793 | static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg) | 4793 | static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg) |
@@ -4797,43 +4797,112 @@ static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg) | |||
4797 | (kvm_get_rflags(vcpu) & X86_EFLAGS_VM); | 4797 | (kvm_get_rflags(vcpu) & X86_EFLAGS_VM); |
4798 | } | 4798 | } |
4799 | 4799 | ||
4800 | static void kvm_check_segment_descriptor(struct kvm_vcpu *vcpu, int seg, | 4800 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg) |
4801 | u16 selector) | ||
4802 | { | ||
4803 | /* NULL selector is not valid for CS and SS */ | ||
4804 | if (seg == VCPU_SREG_CS || seg == VCPU_SREG_SS) | ||
4805 | if (!selector) | ||
4806 | kvm_queue_exception_e(vcpu, TS_VECTOR, selector >> 3); | ||
4807 | } | ||
4808 | |||
4809 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, | ||
4810 | int type_bits, int seg) | ||
4811 | { | 4801 | { |
4812 | struct kvm_segment kvm_seg; | 4802 | struct kvm_segment kvm_seg; |
4813 | struct desc_struct seg_desc; | 4803 | struct desc_struct seg_desc; |
4804 | u8 dpl, rpl, cpl; | ||
4805 | unsigned err_vec = GP_VECTOR; | ||
4806 | u32 err_code = 0; | ||
4807 | bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */ | ||
4808 | int ret; | ||
4814 | 4809 | ||
4815 | if (is_vm86_segment(vcpu, seg) || !is_protmode(vcpu)) | 4810 | if (is_vm86_segment(vcpu, seg) || !is_protmode(vcpu)) |
4816 | return kvm_load_realmode_segment(vcpu, selector, seg); | 4811 | return kvm_load_realmode_segment(vcpu, selector, seg); |
4817 | 4812 | ||
4818 | if (load_guest_segment_descriptor(vcpu, selector, &seg_desc)) | 4813 | /* NULL selector is not valid for TR, CS and SS */ |
4819 | return 1; | 4814 | if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR) |
4815 | && null_selector) | ||
4816 | goto exception; | ||
4817 | |||
4818 | /* TR should be in GDT only */ | ||
4819 | if (seg == VCPU_SREG_TR && (selector & (1 << 2))) | ||
4820 | goto exception; | ||
4821 | |||
4822 | ret = load_guest_segment_descriptor(vcpu, selector, &seg_desc); | ||
4823 | if (ret) | ||
4824 | return ret; | ||
4825 | |||
4820 | seg_desct_to_kvm_desct(&seg_desc, selector, &kvm_seg); | 4826 | seg_desct_to_kvm_desct(&seg_desc, selector, &kvm_seg); |
4821 | 4827 | ||
4822 | kvm_check_segment_descriptor(vcpu, seg, selector); | 4828 | if (null_selector) { /* for NULL selector skip all following checks */ |
4823 | kvm_seg.type |= type_bits; | 4829 | kvm_seg.unusable = 1; |
4830 | goto load; | ||
4831 | } | ||
4824 | 4832 | ||
4825 | if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS && | 4833 | err_code = selector & 0xfffc; |
4826 | seg != VCPU_SREG_LDTR) | 4834 | err_vec = GP_VECTOR; |
4827 | if (!kvm_seg.s) | ||
4828 | kvm_seg.unusable = 1; | ||
4829 | 4835 | ||
4830 | kvm_set_segment(vcpu, &kvm_seg, seg); | 4836 | /* can't load system descriptor into segment selecor */ |
4831 | if (selector && !kvm_seg.unusable && kvm_seg.s) { | 4837 | if (seg <= VCPU_SREG_GS && !kvm_seg.s) |
4838 | goto exception; | ||
4839 | |||
4840 | if (!kvm_seg.present) { | ||
4841 | err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; | ||
4842 | goto exception; | ||
4843 | } | ||
4844 | |||
4845 | rpl = selector & 3; | ||
4846 | dpl = kvm_seg.dpl; | ||
4847 | cpl = kvm_x86_ops->get_cpl(vcpu); | ||
4848 | |||
4849 | switch (seg) { | ||
4850 | case VCPU_SREG_SS: | ||
4851 | /* | ||
4852 | * segment is not a writable data segment or segment | ||
4853 | * selector's RPL != CPL or segment selector's RPL != CPL | ||
4854 | */ | ||
4855 | if (rpl != cpl || (kvm_seg.type & 0xa) != 0x2 || dpl != cpl) | ||
4856 | goto exception; | ||
4857 | break; | ||
4858 | case VCPU_SREG_CS: | ||
4859 | if (!(kvm_seg.type & 8)) | ||
4860 | goto exception; | ||
4861 | |||
4862 | if (kvm_seg.type & 4) { | ||
4863 | /* conforming */ | ||
4864 | if (dpl > cpl) | ||
4865 | goto exception; | ||
4866 | } else { | ||
4867 | /* nonconforming */ | ||
4868 | if (rpl > cpl || dpl != cpl) | ||
4869 | goto exception; | ||
4870 | } | ||
4871 | /* CS(RPL) <- CPL */ | ||
4872 | selector = (selector & 0xfffc) | cpl; | ||
4873 | break; | ||
4874 | case VCPU_SREG_TR: | ||
4875 | if (kvm_seg.s || (kvm_seg.type != 1 && kvm_seg.type != 9)) | ||
4876 | goto exception; | ||
4877 | break; | ||
4878 | case VCPU_SREG_LDTR: | ||
4879 | if (kvm_seg.s || kvm_seg.type != 2) | ||
4880 | goto exception; | ||
4881 | break; | ||
4882 | default: /* DS, ES, FS, or GS */ | ||
4883 | /* | ||
4884 | * segment is not a data or readable code segment or | ||
4885 | * ((segment is a data or nonconforming code segment) | ||
4886 | * and (both RPL and CPL > DPL)) | ||
4887 | */ | ||
4888 | if ((kvm_seg.type & 0xa) == 0x8 || | ||
4889 | (((kvm_seg.type & 0xc) != 0xc) && (rpl > dpl && cpl > dpl))) | ||
4890 | goto exception; | ||
4891 | break; | ||
4892 | } | ||
4893 | |||
4894 | if (!kvm_seg.unusable && kvm_seg.s) { | ||
4832 | /* mark segment as accessed */ | 4895 | /* mark segment as accessed */ |
4896 | kvm_seg.type |= 1; | ||
4833 | seg_desc.type |= 1; | 4897 | seg_desc.type |= 1; |
4834 | save_guest_segment_descriptor(vcpu, selector, &seg_desc); | 4898 | save_guest_segment_descriptor(vcpu, selector, &seg_desc); |
4835 | } | 4899 | } |
4836 | return 0; | 4900 | load: |
4901 | kvm_set_segment(vcpu, &kvm_seg, seg); | ||
4902 | return X86EMUL_CONTINUE; | ||
4903 | exception: | ||
4904 | kvm_queue_exception_e(vcpu, err_vec, err_code); | ||
4905 | return X86EMUL_PROPAGATE_FAULT; | ||
4837 | } | 4906 | } |
4838 | 4907 | ||
4839 | static void save_state_to_tss32(struct kvm_vcpu *vcpu, | 4908 | static void save_state_to_tss32(struct kvm_vcpu *vcpu, |
@@ -4859,6 +4928,14 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu, | |||
4859 | tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR); | 4928 | tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR); |
4860 | } | 4929 | } |
4861 | 4930 | ||
4931 | static void kvm_load_segment_selector(struct kvm_vcpu *vcpu, u16 sel, int seg) | ||
4932 | { | ||
4933 | struct kvm_segment kvm_seg; | ||
4934 | kvm_get_segment(vcpu, &kvm_seg, seg); | ||
4935 | kvm_seg.selector = sel; | ||
4936 | kvm_set_segment(vcpu, &kvm_seg, seg); | ||
4937 | } | ||
4938 | |||
4862 | static int load_state_from_tss32(struct kvm_vcpu *vcpu, | 4939 | static int load_state_from_tss32(struct kvm_vcpu *vcpu, |
4863 | struct tss_segment_32 *tss) | 4940 | struct tss_segment_32 *tss) |
4864 | { | 4941 | { |
@@ -4876,25 +4953,41 @@ static int load_state_from_tss32(struct kvm_vcpu *vcpu, | |||
4876 | kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi); | 4953 | kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi); |
4877 | kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi); | 4954 | kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi); |
4878 | 4955 | ||
4879 | if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR)) | 4956 | /* |
4957 | * SDM says that segment selectors are loaded before segment | ||
4958 | * descriptors | ||
4959 | */ | ||
4960 | kvm_load_segment_selector(vcpu, tss->ldt_selector, VCPU_SREG_LDTR); | ||
4961 | kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES); | ||
4962 | kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS); | ||
4963 | kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS); | ||
4964 | kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS); | ||
4965 | kvm_load_segment_selector(vcpu, tss->fs, VCPU_SREG_FS); | ||
4966 | kvm_load_segment_selector(vcpu, tss->gs, VCPU_SREG_GS); | ||
4967 | |||
4968 | /* | ||
4969 | * Now load segment descriptors. If fault happenes at this stage | ||
4970 | * it is handled in a context of new task | ||
4971 | */ | ||
4972 | if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, VCPU_SREG_LDTR)) | ||
4880 | return 1; | 4973 | return 1; |
4881 | 4974 | ||
4882 | if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) | 4975 | if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES)) |
4883 | return 1; | 4976 | return 1; |
4884 | 4977 | ||
4885 | if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) | 4978 | if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS)) |
4886 | return 1; | 4979 | return 1; |
4887 | 4980 | ||
4888 | if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) | 4981 | if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS)) |
4889 | return 1; | 4982 | return 1; |
4890 | 4983 | ||
4891 | if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) | 4984 | if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS)) |
4892 | return 1; | 4985 | return 1; |
4893 | 4986 | ||
4894 | if (kvm_load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS)) | 4987 | if (kvm_load_segment_descriptor(vcpu, tss->fs, VCPU_SREG_FS)) |
4895 | return 1; | 4988 | return 1; |
4896 | 4989 | ||
4897 | if (kvm_load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS)) | 4990 | if (kvm_load_segment_descriptor(vcpu, tss->gs, VCPU_SREG_GS)) |
4898 | return 1; | 4991 | return 1; |
4899 | return 0; | 4992 | return 0; |
4900 | } | 4993 | } |
@@ -4934,19 +5027,33 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu, | |||
4934 | kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si); | 5027 | kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si); |
4935 | kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di); | 5028 | kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di); |
4936 | 5029 | ||
4937 | if (kvm_load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR)) | 5030 | /* |
5031 | * SDM says that segment selectors are loaded before segment | ||
5032 | * descriptors | ||
5033 | */ | ||
5034 | kvm_load_segment_selector(vcpu, tss->ldt, VCPU_SREG_LDTR); | ||
5035 | kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES); | ||
5036 | kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS); | ||
5037 | kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS); | ||
5038 | kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS); | ||
5039 | |||
5040 | /* | ||
5041 | * Now load segment descriptors. If fault happenes at this stage | ||
5042 | * it is handled in a context of new task | ||
5043 | */ | ||
5044 | if (kvm_load_segment_descriptor(vcpu, tss->ldt, VCPU_SREG_LDTR)) | ||
4938 | return 1; | 5045 | return 1; |
4939 | 5046 | ||
4940 | if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) | 5047 | if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES)) |
4941 | return 1; | 5048 | return 1; |
4942 | 5049 | ||
4943 | if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) | 5050 | if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS)) |
4944 | return 1; | 5051 | return 1; |
4945 | 5052 | ||
4946 | if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) | 5053 | if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS)) |
4947 | return 1; | 5054 | return 1; |
4948 | 5055 | ||
4949 | if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) | 5056 | if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS)) |
4950 | return 1; | 5057 | return 1; |
4951 | return 0; | 5058 | return 0; |
4952 | } | 5059 | } |