The function will be used outside of the emulator.
Signed-off-by: Gleb Natapov <[email protected]>
---
arch/x86/include/asm/kvm_emulate.h | 16 +++++
arch/x86/kvm/emulate.c | 114 ++++++++++++++++++++----------------
2 files changed, 79 insertions(+), 51 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index 7c276ca..9ce651b 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -374,6 +374,21 @@ enum x86_intercept {
nr_x86_intercepts
};
+struct x86_linearize_params
+{
+ enum x86emul_mode mode;
+ ulong ea;
+ unsigned size;
+ unsigned seg;
+ struct desc_struct desc;
+ u16 sel;
+ bool usable;
+ bool write;
+ bool fetch;
+ u8 ad_bytes;
+ unsigned cpl;
+};
+
/* Host execution mode. */
#if defined(CONFIG_X86_32)
#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
@@ -392,4 +407,5 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
u16 tss_selector, int idt_index, int reason,
bool has_error_code, u32 error_code);
int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq);
+int x86_linearize(struct x86_linearize_params *p, ulong *linear);
#endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index e317588..79368d2 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);
@@ -573,79 +560,104 @@ static bool insn_aligned(struct x86_emulate_ctxt *ctxt,
unsigned size)
return true;
}
-static int __linearize(struct x86_emulate_ctxt *ctxt,
- struct segmented_address addr,
- unsigned size, bool write, bool fetch,
- ulong *linear)
+int x86_linearize(struct x86_linearize_params *p, ulong *linear)
{
- struct desc_struct desc;
- bool usable;
ulong la;
u32 lim;
- u16 sel;
unsigned cpl, rpl;
- la = seg_base(ctxt, addr.seg) + addr.ea;
- switch (ctxt->mode) {
+ la = get_desc_base(&p->desc) + p->ea;
+ switch (p->mode) {
case X86EMUL_MODE_REAL:
break;
case X86EMUL_MODE_PROT64:
- if (((signed long)la << 16) >> 16 != la)
- return emulate_gp(ctxt, 0);
+ if (((signed long)la << 16) >> 16 != la) {
+ *linear = 0;
+ return GP_VECTOR;
+ }
break;
default:
- usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL,
- addr.seg);
- if (!usable)
+ if (!p->usable)
goto bad;
/* code segment or read-only data segment */
- if (((desc.type & 8) || !(desc.type & 2)) && write)
+ if (((p->desc.type & 8) || !(p->desc.type & 2)) && p->write)
goto bad;
/* unreadable code segment */
- if (!fetch && (desc.type & 8) && !(desc.type & 2))
+ if (!p->fetch && (p->desc.type & 8) && !(p->desc.type & 2))
goto bad;
- lim = desc_limit_scaled(&desc);
- if ((desc.type & 8) || !(desc.type & 4)) {
+ lim = desc_limit_scaled(&p->desc);
+ if ((p->desc.type & 8) || !(p->desc.type & 4)) {
/* expand-up segment */
- if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
+ if (p->ea > lim || (u32)(p->ea + p->size - 1) > lim)
goto bad;
} else {
/* exapand-down segment */
- if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
+ if (p->ea <= lim || (u32)(p->ea + p->size - 1) <= lim)
goto bad;
- lim = desc.d ? 0xffffffff : 0xffff;
- if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
+ lim = p->desc.d ? 0xffffffff : 0xffff;
+ if (p->ea > lim || (u32)(p->ea + p->size - 1) > lim)
goto bad;
}
- cpl = ctxt->ops->cpl(ctxt);
- rpl = sel & 3;
- cpl = max(cpl, rpl);
- if (!(desc.type & 8)) {
+ rpl = p->sel & 3;
+ cpl = max(p->cpl, rpl);
+ if (!(p->desc.type & 8)) {
/* data segment */
- if (cpl > desc.dpl)
+ if (cpl > p->desc.dpl)
goto bad;
- } else if ((desc.type & 8) && !(desc.type & 4)) {
+ } else if ((p->desc.type & 8) && !(p->desc.type & 4)) {
/* nonconforming code segment */
- if (cpl != desc.dpl)
+ if (cpl != p->desc.dpl)
goto bad;
- } else if ((desc.type & 8) && (desc.type & 4)) {
+ } else if ((p->desc.type & 8) && (p->desc.type & 4)) {
/* conforming code segment */
- if (cpl < desc.dpl)
+ if (cpl < p->desc.dpl)
goto bad;
}
break;
}
- if (fetch ? ctxt->mode != X86EMUL_MODE_PROT64 : ctxt->ad_bytes != 8)
+ if (p->fetch ? p->mode != X86EMUL_MODE_PROT64 : p->ad_bytes != 8)
la &= (u32)-1;
- if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0))
- return emulate_gp(ctxt, 0);
*linear = la;
- return X86EMUL_CONTINUE;
+ return -1;
bad:
- if (addr.seg == VCPU_SREG_SS)
- return emulate_ss(ctxt, addr.seg);
+ *linear = (ulong)p->seg;
+ if (p->seg == VCPU_SREG_SS)
+ return SS_VECTOR;
else
- return emulate_gp(ctxt, addr.seg);
+ return GP_VECTOR;
+}
+
+static int __linearize(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ unsigned size, bool write, bool fetch,
+ ulong *linear)
+{
+ int err;
+
+ struct x86_linearize_params param = {
+ .mode = ctxt->mode,
+ .ea = addr.ea,
+ .size = size,
+ .seg = addr.seg,
+ .write = write,
+ .fetch = fetch,
+ .ad_bytes = ctxt->ad_bytes,
+ .cpl = ctxt->ops->cpl(ctxt)
+ };
+
+ param.usable = ctxt->ops->get_segment(ctxt, ¶m.sel, ¶m.desc,
+ NULL, addr.seg);
+
+
+ err = x86_linearize(¶m, linear);
+
+ 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);
+
+ return X86EMUL_CONTINUE;
}
static int linearize(struct x86_emulate_ctxt *ctxt,
--
1.7.10
--
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