| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- From d2c4fc069a073d621d2cbc97ffe9547754784639 Mon Sep 17 00:00:00 2001
- From: Maxim Levitsky <[email protected]>
- Date: Tue, 25 Oct 2022 15:47:29 +0300
- Subject: [PATCH] KVM: x86: emulator: introduce emulator_recalc_and_set_mode
- Some instructions update the cpu execution mode, which needs to update the
- emulation mode.
- Extract this code, and make assign_eip_far use it.
- assign_eip_far now reads CS, instead of getting it via a parameter,
- which is ok, because callers always assign CS to the same value
- before calling this function.
- No functional change is intended.
- Signed-off-by: Maxim Levitsky <[email protected]>
- ---
- arch/x86/kvm/emulate.c | 85 ++++++++++++++++++++++++++++--------------
- 1 file changed, 57 insertions(+), 28 deletions(-)
- diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
- index 5ee1998dd38e..d75d33d60cb8 100644
- --- a/arch/x86/kvm/emulate.c
- +++ b/arch/x86/kvm/emulate.c
- @@ -760,8 +760,7 @@ static int linearize(struct x86_emulate_ctxt *ctxt,
- ctxt->mode, linear);
- }
-
- -static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
- - enum x86emul_mode mode)
- +static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst)
- {
- ulong linear;
- int rc;
- @@ -771,41 +770,71 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
-
- if (ctxt->op_bytes != sizeof(unsigned long))
- addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1);
- - rc = __linearize(ctxt, addr, &max_size, 1, false, true, mode, &linear);
- + rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear);
- if (rc == X86EMUL_CONTINUE)
- ctxt->_eip = addr.ea;
- return rc;
- }
-
- +static inline int emulator_recalc_and_set_mode(struct x86_emulate_ctxt *ctxt)
- +{
- + u64 efer;
- + struct desc_struct cs;
- + u16 selector;
- + u32 base3;
- +
- + ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
- +
- + if (!(ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PE)) {
- + /* Real mode. cpu must not have long mode active */
- + if (efer & EFER_LMA)
- + return X86EMUL_UNHANDLEABLE;
- + ctxt->mode = X86EMUL_MODE_REAL;
- + return X86EMUL_CONTINUE;
- + }
- +
- + if (ctxt->eflags & X86_EFLAGS_VM) {
- + /* Protected/VM86 mode. cpu must not have long mode active */
- + if (efer & EFER_LMA)
- + return X86EMUL_UNHANDLEABLE;
- + ctxt->mode = X86EMUL_MODE_VM86;
- + return X86EMUL_CONTINUE;
- + }
- +
- + if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS))
- + return X86EMUL_UNHANDLEABLE;
- +
- + if (efer & EFER_LMA) {
- + if (cs.l) {
- + /* Proper long mode */
- + ctxt->mode = X86EMUL_MODE_PROT64;
- + } else if (cs.d) {
- + /* 32 bit compatibility mode*/
- + ctxt->mode = X86EMUL_MODE_PROT32;
- + } else {
- + ctxt->mode = X86EMUL_MODE_PROT16;
- + }
- + } else {
- + /* Legacy 32 bit / 16 bit mode */
- + ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
- + }
- +
- + return X86EMUL_CONTINUE;
- +}
- +
- static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst)
- {
- - return assign_eip(ctxt, dst, ctxt->mode);
- + return assign_eip(ctxt, dst);
- }
-
- -static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst,
- - const struct desc_struct *cs_desc)
- +static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst)
- {
- - enum x86emul_mode mode = ctxt->mode;
- - int rc;
- + int rc = emulator_recalc_and_set_mode(ctxt);
-
- -#ifdef CONFIG_X86_64
- - if (ctxt->mode >= X86EMUL_MODE_PROT16) {
- - if (cs_desc->l) {
- - u64 efer = 0;
- + if (rc != X86EMUL_CONTINUE)
- + return rc;
-
- - ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
- - if (efer & EFER_LMA)
- - mode = X86EMUL_MODE_PROT64;
- - } else
- - mode = X86EMUL_MODE_PROT32; /* temporary value */
- - }
- -#endif
- - if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32)
- - mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
- - rc = assign_eip(ctxt, dst, mode);
- - if (rc == X86EMUL_CONTINUE)
- - ctxt->mode = mode;
- - return rc;
- + return assign_eip(ctxt, dst);
- }
-
- static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
- @@ -2139,7 +2168,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
- if (rc != X86EMUL_CONTINUE)
- return rc;
-
- - rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
- + rc = assign_eip_far(ctxt, ctxt->src.val);
- /* Error handling is not implemented. */
- if (rc != X86EMUL_CONTINUE)
- return X86EMUL_UNHANDLEABLE;
- @@ -2217,7 +2246,7 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
- &new_desc);
- if (rc != X86EMUL_CONTINUE)
- return rc;
- - rc = assign_eip_far(ctxt, eip, &new_desc);
- + rc = assign_eip_far(ctxt, eip);
- /* Error handling is not implemented. */
- if (rc != X86EMUL_CONTINUE)
- return X86EMUL_UNHANDLEABLE;
- @@ -3117,7 +3146,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
- if (rc != X86EMUL_CONTINUE)
- return rc;
-
- - rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
- + rc = assign_eip_far(ctxt, ctxt->src.val);
- if (rc != X86EMUL_CONTINUE)
- goto fail;
-
- --
- 2.38.1
|