|
@@ -237,6 +237,93 @@ static void vmcs_set_bits(unsigned long field, u32 mask)
|
|
|
vmcs_writel(field, vmcs_readl(field) | mask);
|
|
|
}
|
|
|
|
|
|
+static void reload_tss(void)
|
|
|
+{
|
|
|
+#ifndef CONFIG_X86_64
|
|
|
+
|
|
|
+ /*
|
|
|
+ * VT restores TR but not its size. Useless.
|
|
|
+ */
|
|
|
+ struct descriptor_table gdt;
|
|
|
+ struct segment_descriptor *descs;
|
|
|
+
|
|
|
+ get_gdt(&gdt);
|
|
|
+ descs = (void *)gdt.base;
|
|
|
+ descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
|
|
|
+ load_TR_desc();
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+static void vmx_save_host_state(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ struct vmx_host_state *hs = &vcpu->vmx_host_state;
|
|
|
+
|
|
|
+ if (hs->loaded)
|
|
|
+ return;
|
|
|
+
|
|
|
+ hs->loaded = 1;
|
|
|
+ /*
|
|
|
+ * Set host fs and gs selectors. Unfortunately, 22.2.3 does not
|
|
|
+ * allow segment selectors with cpl > 0 or ti == 1.
|
|
|
+ */
|
|
|
+ hs->ldt_sel = read_ldt();
|
|
|
+ hs->fs_gs_ldt_reload_needed = hs->ldt_sel;
|
|
|
+ hs->fs_sel = read_fs();
|
|
|
+ if (!(hs->fs_sel & 7))
|
|
|
+ vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel);
|
|
|
+ else {
|
|
|
+ vmcs_write16(HOST_FS_SELECTOR, 0);
|
|
|
+ hs->fs_gs_ldt_reload_needed = 1;
|
|
|
+ }
|
|
|
+ hs->gs_sel = read_gs();
|
|
|
+ if (!(hs->gs_sel & 7))
|
|
|
+ vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel);
|
|
|
+ else {
|
|
|
+ vmcs_write16(HOST_GS_SELECTOR, 0);
|
|
|
+ hs->fs_gs_ldt_reload_needed = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
|
|
|
+ vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
|
|
|
+#else
|
|
|
+ vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel));
|
|
|
+ vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel));
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+static void vmx_load_host_state(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ struct vmx_host_state *hs = &vcpu->vmx_host_state;
|
|
|
+
|
|
|
+ if (!hs->loaded)
|
|
|
+ return;
|
|
|
+
|
|
|
+ hs->loaded = 0;
|
|
|
+ if (hs->fs_gs_ldt_reload_needed) {
|
|
|
+ load_ldt(hs->ldt_sel);
|
|
|
+ load_fs(hs->fs_sel);
|
|
|
+ /*
|
|
|
+ * If we have to reload gs, we must take care to
|
|
|
+ * preserve our gs base.
|
|
|
+ */
|
|
|
+ local_irq_disable();
|
|
|
+ load_gs(hs->gs_sel);
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
|
|
|
+#endif
|
|
|
+ local_irq_enable();
|
|
|
+
|
|
|
+ reload_tss();
|
|
|
+ }
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ if (is_long_mode(vcpu)) {
|
|
|
+ save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
|
|
|
+ load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
|
|
|
* vcpu mutex is already taken.
|
|
@@ -283,6 +370,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
+ vmx_load_host_state(vcpu);
|
|
|
kvm_put_guest_fpu(vcpu);
|
|
|
put_cpu();
|
|
|
}
|
|
@@ -397,23 +485,6 @@ static void guest_write_tsc(u64 guest_tsc)
|
|
|
vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
|
|
|
}
|
|
|
|
|
|
-static void reload_tss(void)
|
|
|
-{
|
|
|
-#ifndef CONFIG_X86_64
|
|
|
-
|
|
|
- /*
|
|
|
- * VT restores TR but not its size. Useless.
|
|
|
- */
|
|
|
- struct descriptor_table gdt;
|
|
|
- struct segment_descriptor *descs;
|
|
|
-
|
|
|
- get_gdt(&gdt);
|
|
|
- descs = (void *)gdt.base;
|
|
|
- descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
|
|
|
- load_TR_desc();
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Reads an msr value (of 'msr_index') into 'pdata'.
|
|
|
* Returns 0 on success, non-0 otherwise.
|
|
@@ -1823,40 +1894,9 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
|
|
|
static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
|
|
{
|
|
|
u8 fail;
|
|
|
- u16 fs_sel, gs_sel, ldt_sel;
|
|
|
- int fs_gs_ldt_reload_needed;
|
|
|
int r;
|
|
|
|
|
|
preempted:
|
|
|
- /*
|
|
|
- * Set host fs and gs selectors. Unfortunately, 22.2.3 does not
|
|
|
- * allow segment selectors with cpl > 0 or ti == 1.
|
|
|
- */
|
|
|
- ldt_sel = read_ldt();
|
|
|
- fs_gs_ldt_reload_needed = ldt_sel;
|
|
|
- fs_sel = read_fs();
|
|
|
- if (!(fs_sel & 7))
|
|
|
- vmcs_write16(HOST_FS_SELECTOR, fs_sel);
|
|
|
- else {
|
|
|
- vmcs_write16(HOST_FS_SELECTOR, 0);
|
|
|
- fs_gs_ldt_reload_needed = 1;
|
|
|
- }
|
|
|
- gs_sel = read_gs();
|
|
|
- if (!(gs_sel & 7))
|
|
|
- vmcs_write16(HOST_GS_SELECTOR, gs_sel);
|
|
|
- else {
|
|
|
- vmcs_write16(HOST_GS_SELECTOR, 0);
|
|
|
- fs_gs_ldt_reload_needed = 1;
|
|
|
- }
|
|
|
-
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
- vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
|
|
|
- vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
|
|
|
-#else
|
|
|
- vmcs_writel(HOST_FS_BASE, segment_base(fs_sel));
|
|
|
- vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
|
|
|
-#endif
|
|
|
-
|
|
|
if (!vcpu->mmio_read_completed)
|
|
|
do_interrupt_requests(vcpu, kvm_run);
|
|
|
|
|
@@ -1871,6 +1911,7 @@ preempted:
|
|
|
#endif
|
|
|
|
|
|
again:
|
|
|
+ vmx_save_host_state(vcpu);
|
|
|
kvm_load_guest_fpu(vcpu);
|
|
|
|
|
|
/*
|
|
@@ -2040,29 +2081,6 @@ again:
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- if (fs_gs_ldt_reload_needed) {
|
|
|
- load_ldt(ldt_sel);
|
|
|
- load_fs(fs_sel);
|
|
|
- /*
|
|
|
- * If we have to reload gs, we must take care to
|
|
|
- * preserve our gs base.
|
|
|
- */
|
|
|
- local_irq_disable();
|
|
|
- load_gs(gs_sel);
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
- wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
|
|
|
-#endif
|
|
|
- local_irq_enable();
|
|
|
-
|
|
|
- reload_tss();
|
|
|
- }
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
- if (is_long_mode(vcpu)) {
|
|
|
- save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
|
|
|
- load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
if (r > 0) {
|
|
|
kvm_resched(vcpu);
|
|
|
goto preempted;
|