aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-05-07 03:55:37 -0400
committerAvi Kivity <avi@qumranet.com>2007-07-16 05:05:41 -0400
commit653e3108b7d6097d25089d25ab4e99bc58b28962 (patch)
treeff92977a15ddf12807d3a9f32eb6f5446fb59a79 /drivers/kvm
parenteff708bc2bacd4f22cf844871341bef341bd096a (diff)
KVM: Avoid corrupting tr in real mode
The real mode tr needs to be set to a specific tss so that I/O instructions can function. Divert the new tr values to the real mode save area from where they will be restored on transition to protected mode. This fixes some crashes on reboot when the bios accesses an I/O instruction. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
-rw-r--r--drivers/kvm/vmx.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index b353eaa0a441..e39ebe0b6958 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1042,23 +1042,11 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
1042 var->unusable = (ar >> 16) & 1; 1042 var->unusable = (ar >> 16) & 1;
1043} 1043}
1044 1044
1045static void vmx_set_segment(struct kvm_vcpu *vcpu, 1045static u32 vmx_segment_access_rights(struct kvm_segment *var)
1046 struct kvm_segment *var, int seg)
1047{ 1046{
1048 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
1049 u32 ar; 1047 u32 ar;
1050 1048
1051 vmcs_writel(sf->base, var->base); 1049 if (var->unusable)
1052 vmcs_write32(sf->limit, var->limit);
1053 vmcs_write16(sf->selector, var->selector);
1054 if (vcpu->rmode.active && var->s) {
1055 /*
1056 * Hack real-mode segments into vm86 compatibility.
1057 */
1058 if (var->base == 0xffff0000 && var->selector == 0xf000)
1059 vmcs_writel(sf->base, 0xf0000);
1060 ar = 0xf3;
1061 } else if (var->unusable)
1062 ar = 1 << 16; 1050 ar = 1 << 16;
1063 else { 1051 else {
1064 ar = var->type & 15; 1052 ar = var->type & 15;
@@ -1072,6 +1060,35 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
1072 } 1060 }
1073 if (ar == 0) /* a 0 value means unusable */ 1061 if (ar == 0) /* a 0 value means unusable */
1074 ar = AR_UNUSABLE_MASK; 1062 ar = AR_UNUSABLE_MASK;
1063
1064 return ar;
1065}
1066
1067static void vmx_set_segment(struct kvm_vcpu *vcpu,
1068 struct kvm_segment *var, int seg)
1069{
1070 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
1071 u32 ar;
1072
1073 if (vcpu->rmode.active && seg == VCPU_SREG_TR) {
1074 vcpu->rmode.tr.selector = var->selector;
1075 vcpu->rmode.tr.base = var->base;
1076 vcpu->rmode.tr.limit = var->limit;
1077 vcpu->rmode.tr.ar = vmx_segment_access_rights(var);
1078 return;
1079 }
1080 vmcs_writel(sf->base, var->base);
1081 vmcs_write32(sf->limit, var->limit);
1082 vmcs_write16(sf->selector, var->selector);
1083 if (vcpu->rmode.active && var->s) {
1084 /*
1085 * Hack real-mode segments into vm86 compatibility.
1086 */
1087 if (var->base == 0xffff0000 && var->selector == 0xf000)
1088 vmcs_writel(sf->base, 0xf0000);
1089 ar = 0xf3;
1090 } else
1091 ar = vmx_segment_access_rights(var);
1075 vmcs_write32(sf->ar_bytes, ar); 1092 vmcs_write32(sf->ar_bytes, ar);
1076} 1093}
1077 1094