Author: tychon
Date: Fri Jun 26 18:00:29 2015
New Revision: 284877
URL: https://svnweb.freebsd.org/changeset/base/284877

Log:
  verify_gla() needs to account for non-zero segment base addresses.
  
  Reviewed by:  neel

Modified:
  head/sys/amd64/vmm/vmm_instruction_emul.c

Modified: head/sys/amd64/vmm/vmm_instruction_emul.c
==============================================================================
--- head/sys/amd64/vmm/vmm_instruction_emul.c   Fri Jun 26 17:13:23 2015        
(r284876)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c   Fri Jun 26 18:00:29 2015        
(r284877)
@@ -2321,10 +2321,13 @@ decode_moffset(struct vie *vie)
  * page table fault matches with our instruction decoding.
  */
 static int
-verify_gla(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie)
+verify_gla(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie,
+    enum vm_cpu_mode cpu_mode)
 {
        int error;
-       uint64_t base, idx, gla2;
+       uint64_t base, segbase, idx, gla2;
+       enum vm_reg_name seg;
+       struct seg_desc desc;
 
        /* Skip 'gla' verification */
        if (gla == VIE_INVALID_GLA)
@@ -2357,14 +2360,48 @@ verify_gla(struct vm *vm, int cpuid, uin
                }
        }
 
-       /* XXX assuming that the base address of the segment is 0 */
-       gla2 = base + vie->scale * idx + vie->displacement;
+       /*
+        * From "Specifying a Segment Selector", Intel SDM, Vol 1
+        *
+        * In 64-bit mode, segmentation is generally (but not
+        * completely) disabled.  The exceptions are the FS and GS
+        * segments.
+        *
+        * In legacy IA-32 mode, when the ESP or EBP register is used
+        * as the base, the SS segment is the default segment.  For
+        * other data references, except when relative to stack or
+        * string destination the DS segment is the default.  These
+        * can be overridden to allow other segments to be accessed.
+        */
+       if (vie->segment_override)
+               seg = vie->segment_register;
+       else if (vie->base_register == VM_REG_GUEST_RSP ||
+           vie->base_register == VM_REG_GUEST_RBP)
+               seg = VM_REG_GUEST_SS;
+       else
+               seg = VM_REG_GUEST_DS;
+       if (cpu_mode == CPU_MODE_64BIT && seg != VM_REG_GUEST_FS &&
+           seg != VM_REG_GUEST_GS) {
+               segbase = 0;
+       } else {
+               error = vm_get_seg_desc(vm, cpuid, seg, &desc);
+               if (error) {
+                       printf("verify_gla: error %d getting segment"
+                              " descriptor %d", error,
+                              vie->segment_register);
+                       return (-1);
+               }
+               segbase = desc.base;
+       }
+
+       gla2 = segbase + base + vie->scale * idx + vie->displacement;
        gla2 &= size2mask[vie->addrsize];
        if (gla != gla2) {
-               printf("verify_gla mismatch: "
+               printf("verify_gla mismatch: segbase(0x%0lx)"
                       "base(0x%0lx), scale(%d), index(0x%0lx), "
                       "disp(0x%0lx), gla(0x%0lx), gla2(0x%0lx)\n",
-                      base, vie->scale, idx, vie->displacement, gla, gla2);
+                      segbase, base, vie->scale, idx, vie->displacement,
+                      gla, gla2);
                return (-1);
        }
 
@@ -2398,7 +2435,7 @@ vmm_decode_instruction(struct vm *vm, in
                return (-1);
 
        if ((vie->op.op_flags & VIE_OP_F_NO_GLA_VERIFICATION) == 0) {
-               if (verify_gla(vm, cpuid, gla, vie))
+               if (verify_gla(vm, cpuid, gla, vie, cpu_mode))
                        return (-1);
        }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to