1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Maxim Levitsky <mlevitsk@redhat.com>
3 Date: Tue, 21 Jun 2022 18:08:53 +0300
4 Subject: [PATCH] KVM: x86: emulator: introduce update_emulation_mode
6 Some instructions update the cpu execution mode, which needs
7 to update the emulation mode.
9 Extract this code, and make assign_eip_far use it.
11 assign_eip_far now reads CS, instead of getting it via a parameter,
12 which is ok, because callers always assign CS to the
13 same value before calling it.
15 No functional change is intended.
17 Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
18 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
20 arch/x86/kvm/emulate.c | 85 ++++++++++++++++++++++++++++--------------
21 1 file changed, 57 insertions(+), 28 deletions(-)
23 diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
24 index 35b12692739c..1b5123a882a1 100644
25 --- a/arch/x86/kvm/emulate.c
26 +++ b/arch/x86/kvm/emulate.c
27 @@ -795,8 +795,7 @@ static int linearize(struct x86_emulate_ctxt *ctxt,
31 -static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
32 - enum x86emul_mode mode)
33 +static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst)
37 @@ -806,41 +805,71 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
39 if (ctxt->op_bytes != sizeof(unsigned long))
40 addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1);
41 - rc = __linearize(ctxt, addr, &max_size, 1, false, true, mode, &linear);
42 + rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear);
43 if (rc == X86EMUL_CONTINUE)
48 +static inline int update_emulation_mode(struct x86_emulate_ctxt *ctxt)
51 + struct desc_struct cs;
55 + ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
57 + if (!ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PE) {
58 + /* Real mode. cpu must not have long mode active */
59 + if (efer & EFER_LMA)
60 + return X86EMUL_UNHANDLEABLE;
61 + ctxt->mode = X86EMUL_MODE_REAL;
62 + return X86EMUL_CONTINUE;
65 + if (ctxt->eflags & X86_EFLAGS_VM) {
66 + /* Protected/VM86 mode. cpu must not have long mode active */
67 + if (efer & EFER_LMA)
68 + return X86EMUL_UNHANDLEABLE;
69 + ctxt->mode = X86EMUL_MODE_VM86;
70 + return X86EMUL_CONTINUE;
73 + if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS))
74 + return X86EMUL_UNHANDLEABLE;
76 + if (efer & EFER_LMA) {
78 + /* Proper long mode */
79 + ctxt->mode = X86EMUL_MODE_PROT64;
81 + /* 32 bit compatibility mode*/
82 + ctxt->mode = X86EMUL_MODE_PROT32;
84 + ctxt->mode = X86EMUL_MODE_PROT16;
87 + /* Legacy 32 bit / 16 bit mode */
88 + ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
91 + return X86EMUL_CONTINUE;
94 static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst)
96 - return assign_eip(ctxt, dst, ctxt->mode);
97 + return assign_eip(ctxt, dst);
100 -static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst,
101 - const struct desc_struct *cs_desc)
102 +static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst)
104 - enum x86emul_mode mode = ctxt->mode;
106 + int rc = update_emulation_mode(ctxt);
108 -#ifdef CONFIG_X86_64
109 - if (ctxt->mode >= X86EMUL_MODE_PROT16) {
112 + if (rc != X86EMUL_CONTINUE)
115 - ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
116 - if (efer & EFER_LMA)
117 - mode = X86EMUL_MODE_PROT64;
119 - mode = X86EMUL_MODE_PROT32; /* temporary value */
122 - if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32)
123 - mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
124 - rc = assign_eip(ctxt, dst, mode);
125 - if (rc == X86EMUL_CONTINUE)
128 + return assign_eip(ctxt, dst);
131 static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
132 @@ -2154,7 +2183,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
133 if (rc != X86EMUL_CONTINUE)
136 - rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
137 + rc = assign_eip_far(ctxt, ctxt->src.val);
138 /* Error handling is not implemented. */
139 if (rc != X86EMUL_CONTINUE)
140 return X86EMUL_UNHANDLEABLE;
141 @@ -2235,7 +2264,7 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
143 if (rc != X86EMUL_CONTINUE)
145 - rc = assign_eip_far(ctxt, eip, &new_desc);
146 + rc = assign_eip_far(ctxt, eip);
147 /* Error handling is not implemented. */
148 if (rc != X86EMUL_CONTINUE)
149 return X86EMUL_UNHANDLEABLE;
150 @@ -3459,7 +3488,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
151 if (rc != X86EMUL_CONTINUE)
154 - rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
155 + rc = assign_eip_far(ctxt, ctxt->src.val);
156 if (rc != X86EMUL_CONTINUE)