When access to descriptor in LDT/GDT wraparound outside long-mode, the address
of the descriptor should be truncated to 32-bit.  Citing Intel SDM 2.1.1.1
"Global and Local Descriptor Tables in IA-32e Mode": "GDTR and LDTR registers
are expanded to 64-bits wide in both IA-32e sub-modes (64-bit mode and
compatibility mode)."

So in other cases, we need to truncate. Creating new function to return a
pointer to descriptor table to avoid too much code duplication.

Signed-off-by: Nadav Amit <[email protected]>
---
 arch/x86/kvm/emulate.c | 45 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 4fcd9fd..cb6b8ef 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1446,10 +1446,8 @@ static void get_descriptor_table_ptr(struct 
x86_emulate_ctxt *ctxt,
                ops->get_gdt(ctxt, dt);
 }
 
-/* allowed just for 8 bytes segments */
-static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
-                                  u16 selector, struct desc_struct *desc,
-                                  ulong *desc_addr_p)
+static int get_descriptor_ptr(struct x86_emulate_ctxt *ctxt,
+                             u16 selector, ulong *desc_addr_p)
 {
        struct desc_ptr dt;
        u16 index = selector >> 3;
@@ -1460,8 +1458,32 @@ static int read_segment_descriptor(struct 
x86_emulate_ctxt *ctxt,
        if (dt.size < index * 8 + 7)
                return emulate_gp(ctxt, selector & 0xfffc);
 
-       *desc_addr_p = addr = dt.address + index * 8;
-       return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc,
+       addr = dt.address + index * 8;
+
+       if (addr >> 32 != 0) {
+               u64 efer = 0;
+
+               ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
+               if (!(efer & EFER_LMA))
+                       addr &= (u32)-1;
+       }
+
+       *desc_addr_p = addr;
+       return X86EMUL_CONTINUE;
+}
+
+/* allowed just for 8 bytes segments */
+static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                  u16 selector, struct desc_struct *desc,
+                                  ulong *desc_addr_p)
+{
+       int rc;
+
+       rc = get_descriptor_ptr(ctxt, selector, desc_addr_p);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
+       return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc),
                                   &ctxt->exception);
 }
 
@@ -1469,16 +1491,13 @@ static int read_segment_descriptor(struct 
x86_emulate_ctxt *ctxt,
 static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                                    u16 selector, struct desc_struct *desc)
 {
-       struct desc_ptr dt;
-       u16 index = selector >> 3;
+       int rc;
        ulong addr;
 
-       get_descriptor_table_ptr(ctxt, selector, &dt);
-
-       if (dt.size < index * 8 + 7)
-               return emulate_gp(ctxt, selector & 0xfffc);
+       rc = get_descriptor_ptr(ctxt, selector, &addr);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
 
-       addr = dt.address + index * 8;
        return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc,
                                    &ctxt->exception);
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to