diff options
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 177 |
1 files changed, 142 insertions, 35 deletions
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 | } |