From e6249d6e94711d2c76aeaebaf8dafbc668f5656f Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 3 Apr 2011 12:32:09 +0300 Subject: [PATCH] --- yaml --- r: 248037 b: refs/heads/master c: 618ff15de19109af126b33d90d7eaec27e61c691 h: refs/heads/master i: 248035: a2262631df6cb0b625014963ef7e20961e62f886 v: v3 --- [refs] | 2 +- trunk/arch/x86/kvm/emulate.c | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index f1f6e08a1c1d..cd4a97429618 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 56697687da592d0429c0c3ab80ee7e9d20a3b6e5 +refs/heads/master: 618ff15de19109af126b33d90d7eaec27e61c691 diff --git a/trunk/arch/x86/kvm/emulate.c b/trunk/arch/x86/kvm/emulate.c index 793aff52a4b8..2ec69bc85846 100644 --- a/trunk/arch/x86/kvm/emulate.c +++ b/trunk/arch/x86/kvm/emulate.c @@ -515,6 +515,11 @@ 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); @@ -541,13 +546,71 @@ static int linearize(struct x86_emulate_ctxt *ctxt, ulong *linear) { struct decode_cache *c = &ctxt->decode; + struct desc_struct desc; + bool usable; ulong la; + u32 lim; + unsigned cpl, rpl; la = seg_base(ctxt, ctxt->ops, 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_cached_descriptor(&desc, NULL, addr.seg, + ctxt->vcpu); + 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 ((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->vcpu); + rpl = ctxt->ops->get_segment_selector(addr.seg, ctxt->vcpu) & 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 (c->ad_bytes != 8) la &= (u32)-1; *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 segmented_read_std(struct x86_emulate_ctxt *ctxt,