|
@@ -634,6 +634,43 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static unsigned long segment_base(u16 selector)
|
|
|
+{
|
|
|
+ struct desc_ptr gdt;
|
|
|
+ struct desc_struct *d;
|
|
|
+ unsigned long table_base;
|
|
|
+ unsigned long v;
|
|
|
+
|
|
|
+ if (!(selector & ~3))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ native_store_gdt(&gdt);
|
|
|
+ table_base = gdt.address;
|
|
|
+
|
|
|
+ if (selector & 4) { /* from ldt */
|
|
|
+ u16 ldt_selector = kvm_read_ldt();
|
|
|
+
|
|
|
+ if (!(ldt_selector & ~3))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ table_base = segment_base(ldt_selector);
|
|
|
+ }
|
|
|
+ d = (struct desc_struct *)(table_base + (selector & ~7));
|
|
|
+ v = get_desc_base(d);
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11))
|
|
|
+ v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32;
|
|
|
+#endif
|
|
|
+ return v;
|
|
|
+}
|
|
|
+
|
|
|
+static inline unsigned long kvm_read_tr_base(void)
|
|
|
+{
|
|
|
+ u16 tr;
|
|
|
+ asm("str %0" : "=g"(tr));
|
|
|
+ return segment_base(tr);
|
|
|
+}
|
|
|
+
|
|
|
static void vmx_save_host_state(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|