The function will be used outside of the emulator.

Signed-off-by: Gleb Natapov <[email protected]>
---
 arch/x86/include/asm/kvm_emulate.h |   14 ++++--
 arch/x86/kvm/emulate.c             |   84 ++------------------------------
 arch/x86/kvm/x86.c                 |   92 ++++++++++++++++++++++++++++++++++--
 3 files changed, 103 insertions(+), 87 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h 
b/arch/x86/include/asm/kvm_emulate.h
index 7c276ca..bdf8a84 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -43,6 +43,11 @@ struct x86_instruction_info {
        u64 next_rip;           /* rip following the instruction        */
 };
 
+struct segmented_address {
+       ulong ea;
+       unsigned seg;
+};
+
 /*
  * x86_emulate_ops:
  *
@@ -194,6 +199,10 @@ struct x86_emulate_ops {
 
        bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt,
                         u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
+
+       int (*linearize)(struct x86_emulate_ctxt *ctxt,
+                       struct segmented_address addr, unsigned size,
+                       bool write, bool fetch, ulong *linear);
 };
 
 typedef u32 __attribute__((vector_size(16))) sse128_t;
@@ -208,10 +217,7 @@ struct operand {
        };
        union {
                unsigned long *reg;
-               struct segmented_address {
-                       ulong ea;
-                       unsigned seg;
-               } mem;
+               struct segmented_address mem;
                unsigned xmm;
                unsigned mm;
        } addr;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index e317588..24b1c70 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -470,14 +470,6 @@ static void set_seg_override(struct x86_emulate_ctxt 
*ctxt, int seg)
        ctxt->seg_override = seg;
 }
 
-static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
-{
-       if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
-               return 0;
-
-       return ctxt->ops->get_cached_segment_base(ctxt, seg);
-}
-
 static unsigned seg_override(struct x86_emulate_ctxt *ctxt)
 {
        if (!ctxt->has_seg_override)
@@ -505,11 +497,6 @@ static int emulate_gp(struct x86_emulate_ctxt *ctxt, int 
err)
        return emulate_exception(ctxt, GP_VECTOR, err, true);
 }
 
-static int emulate_ss(struct x86_emulate_ctxt *ctxt, int err)
-{
-       return emulate_exception(ctxt, SS_VECTOR, err, true);
-}
-
 static int emulate_ud(struct x86_emulate_ctxt *ctxt)
 {
        return emulate_exception(ctxt, UD_VECTOR, 0, false);
@@ -578,74 +565,15 @@ static int __linearize(struct x86_emulate_ctxt *ctxt,
                     unsigned size, bool write, bool fetch,
                     ulong *linear)
 {
-       struct desc_struct desc;
-       bool usable;
-       ulong la;
-       u32 lim;
-       u16 sel;
-       unsigned cpl, rpl;
+       int err = ctxt->ops->linearize(ctxt, addr, size, write, fetch, linear);
 
-       la = seg_base(ctxt, addr.seg) + addr.ea;
-       switch (ctxt->mode) {
-       case X86EMUL_MODE_REAL:
-               break;
-       case X86EMUL_MODE_PROT64:
-               if (((signed long)la << 16) >> 16 != la)
-                       return emulate_gp(ctxt, 0);
-               break;
-       default:
-               usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL,
-                                               addr.seg);
-               if (!usable)
-                       goto bad;
-               /* code segment or read-only data segment */
-               if (((desc.type & 8) || !(desc.type & 2)) && write)
-                       goto bad;
-               /* unreadable code segment */
-               if (!fetch && (desc.type & 8) && !(desc.type & 2))
-                       goto bad;
-               lim = desc_limit_scaled(&desc);
-               if ((desc.type & 8) || !(desc.type & 4)) {
-                       /* expand-up segment */
-                       if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
-                               goto bad;
-               } else {
-                       /* exapand-down segment */
-                       if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
-                               goto bad;
-                       lim = desc.d ? 0xffffffff : 0xffff;
-                       if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
-                               goto bad;
-               }
-               cpl = ctxt->ops->cpl(ctxt);
-               rpl = sel & 3;
-               cpl = max(cpl, rpl);
-               if (!(desc.type & 8)) {
-                       /* data segment */
-                       if (cpl > desc.dpl)
-                               goto bad;
-               } else if ((desc.type & 8) && !(desc.type & 4)) {
-                       /* nonconforming code segment */
-                       if (cpl != desc.dpl)
-                               goto bad;
-               } else if ((desc.type & 8) && (desc.type & 4)) {
-                       /* conforming code segment */
-                       if (cpl < desc.dpl)
-                               goto bad;
-               }
-               break;
-       }
-       if (fetch ? ctxt->mode != X86EMUL_MODE_PROT64 : ctxt->ad_bytes != 8)
-               la &= (u32)-1;
-       if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0))
+       if (err >= 0)
+               return emulate_exception(ctxt, err, (int)*linear, true);
+
+       if (insn_aligned(ctxt, size) && ((*linear & (size - 1)) != 0))
                return emulate_gp(ctxt, 0);
-       *linear = la;
+
        return X86EMUL_CONTINUE;
-bad:
-       if (addr.seg == VCPU_SREG_SS)
-               return emulate_ss(ctxt, addr.seg);
-       else
-               return emulate_gp(ctxt, addr.seg);
 }
 
 static int linearize(struct x86_emulate_ctxt *ctxt,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6fa0e21..5ce24a8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3656,6 +3656,84 @@ out:
 }
 EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
+static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+       return kvm_x86_ops->get_segment_base(vcpu, seg);
+}
+
+static int kvm_linearize_address(struct kvm_vcpu *vcpu, enum x86emul_mode mode,
+               ulong ea, unsigned seg, unsigned size, bool write, bool fetch,
+               u8 ad_bytes, ulong *linear)
+{
+       ulong la;
+       unsigned cpl, rpl;
+       struct kvm_segment desc;
+
+       la = get_segment_base(vcpu, seg) + ea;
+       switch (mode) {
+       case X86EMUL_MODE_REAL:
+               break;
+       case X86EMUL_MODE_PROT64:
+               if (((signed long)la << 16) >> 16 != la) {
+                       *linear = 0;
+                       return GP_VECTOR;
+               }
+               break;
+       default:
+               kvm_get_segment(vcpu, &desc, seg);
+               if (desc.unusable)
+                       goto bad;
+               /* code segment or read-only data segment */
+               if (((desc.type & 8) || !(desc.type & 2)) && write)
+                       goto bad;
+               /* unreadable code segment */
+               if (!fetch && (desc.type & 8) && !(desc.type & 2))
+                       goto bad;
+               if ((desc.type & 8) || !(desc.type & 4)) {
+                       /* expand-up segment */
+                       if (ea > desc.limit ||
+                                       (u32)(ea + size - 1) > desc.limit)
+                               goto bad;
+               } else {
+                       u32 lim;
+                       /* exapand-down segment */
+                       if (ea <= desc.limit ||
+                                       (u32)(ea + size - 1) <= desc.limit)
+                               goto bad;
+                       lim = desc.db ? 0xffffffff : 0xffff;
+                       if (ea > lim || (u32)(ea + size - 1) > lim)
+                               goto bad;
+               }
+               cpl = kvm_x86_ops->get_cpl(vcpu);
+               rpl = desc.selector & 3;
+               cpl = max(cpl, rpl);
+               if (!(desc.type & 8)) {
+                       /* data segment */
+                       if (cpl > desc.dpl)
+                               goto bad;
+               } else if ((desc.type & 8) && !(desc.type & 4)) {
+                       /* nonconforming code segment */
+                       if (cpl != desc.dpl)
+                               goto bad;
+               } else if ((desc.type & 8) && (desc.type & 4)) {
+                       /* conforming code segment */
+                       if (cpl < desc.dpl)
+                               goto bad;
+               }
+               break;
+       }
+       if (fetch ? mode != X86EMUL_MODE_PROT64 : ad_bytes != 8)
+               la &= (u32)-1;
+       *linear = la;
+       return -1;
+bad:
+       *linear = (ulong)seg;
+       if (seg == VCPU_SREG_SS)
+               return SS_VECTOR;
+       else
+               return GP_VECTOR;
+}
+
 static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
                                gpa_t *gpa, struct x86_exception *exception,
                                bool write)
@@ -4044,11 +4122,6 @@ static int emulator_pio_out_emulated(struct 
x86_emulate_ctxt *ctxt,
        return emulator_pio_in_out(vcpu, size, port, (void *)val, count, false);
 }
 
-static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
-{
-       return kvm_x86_ops->get_segment_base(vcpu, seg);
-}
-
 static void emulator_invlpg(struct x86_emulate_ctxt *ctxt, ulong address)
 {
        kvm_mmu_invlpg(emul_to_vcpu(ctxt), address);
@@ -4319,6 +4392,14 @@ static bool emulator_get_cpuid(struct x86_emulate_ctxt 
*ctxt,
        return false;
 }
 
+static int emulator_linearize_address(struct x86_emulate_ctxt *ctxt,
+               struct segmented_address addr, unsigned size,
+               bool write, bool fetch, ulong *linear)
+{
+       return kvm_linearize_address(emul_to_vcpu(ctxt), ctxt->mode, addr.ea,
+                       addr.seg, size, write, fetch, ctxt->ad_bytes, linear);
+}
+
 static struct x86_emulate_ops emulate_ops = {
        .read_std            = kvm_read_guest_virt_system,
        .write_std           = kvm_write_guest_virt_system,
@@ -4352,6 +4433,7 @@ static struct x86_emulate_ops emulate_ops = {
        .put_fpu             = emulator_put_fpu,
        .intercept           = emulator_intercept,
        .get_cpuid           = emulator_get_cpuid,
+       .linearize           = emulator_linearize_address,
 };
 
 static void cache_all_regs(struct kvm_vcpu *vcpu)
-- 
1.7.7.3

--
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