]> git.proxmox.com Git - pve-kernel.git/blame - patches/kernel/0021-KVM-x86-emulator-introduce-update_emulation_mode.patch
update sources to Ubuntu-5.19.0-14.14
[pve-kernel.git] / patches / kernel / 0021-KVM-x86-emulator-introduce-update_emulation_mode.patch
CommitLineData
54ebe3cb
TL
1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Maxim Levitsky <mlevitsk@redhat.com>
3Date: Tue, 21 Jun 2022 18:08:53 +0300
4Subject: [PATCH] KVM: x86: emulator: introduce update_emulation_mode
5
6Some instructions update the cpu execution mode, which needs
7to update the emulation mode.
8
9Extract this code, and make assign_eip_far use it.
10
11assign_eip_far now reads CS, instead of getting it via a parameter,
12which is ok, because callers always assign CS to the
13same value before calling it.
14
15No functional change is intended.
16
17Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
18Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
19---
20 arch/x86/kvm/emulate.c | 85 ++++++++++++++++++++++++++++--------------
21 1 file changed, 57 insertions(+), 28 deletions(-)
22
23diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
24index 13181819d52c..36c6f7897b1f 100644
25--- a/arch/x86/kvm/emulate.c
26+++ b/arch/x86/kvm/emulate.c
27@@ -793,8 +793,7 @@ static int linearize(struct x86_emulate_ctxt *ctxt,
28 ctxt->mode, linear);
29 }
30
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)
34 {
35 ulong linear;
36 int rc;
37@@ -804,41 +803,71 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
38
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)
44 ctxt->_eip = addr.ea;
45 return rc;
46 }
47
48+static inline int update_emulation_mode(struct x86_emulate_ctxt *ctxt)
49+{
50+ u64 efer;
51+ struct desc_struct cs;
52+ u16 selector;
53+ u32 base3;
54+
55+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
56+
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;
63+ }
64+
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;
71+ }
72+
73+ if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS))
74+ return X86EMUL_UNHANDLEABLE;
75+
76+ if (efer & EFER_LMA) {
77+ if (cs.l) {
78+ /* Proper long mode */
79+ ctxt->mode = X86EMUL_MODE_PROT64;
80+ } else if (cs.d) {
81+ /* 32 bit compatibility mode*/
82+ ctxt->mode = X86EMUL_MODE_PROT32;
83+ } else {
84+ ctxt->mode = X86EMUL_MODE_PROT16;
85+ }
86+ } else {
87+ /* Legacy 32 bit / 16 bit mode */
88+ ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
89+ }
90+
91+ return X86EMUL_CONTINUE;
92+}
93+
94 static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst)
95 {
96- return assign_eip(ctxt, dst, ctxt->mode);
97+ return assign_eip(ctxt, dst);
98 }
99
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)
103 {
104- enum x86emul_mode mode = ctxt->mode;
105- int rc;
106+ int rc = update_emulation_mode(ctxt);
107
108-#ifdef CONFIG_X86_64
109- if (ctxt->mode >= X86EMUL_MODE_PROT16) {
110- if (cs_desc->l) {
111- u64 efer = 0;
112+ if (rc != X86EMUL_CONTINUE)
113+ return rc;
114
115- ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
116- if (efer & EFER_LMA)
117- mode = X86EMUL_MODE_PROT64;
118- } else
119- mode = X86EMUL_MODE_PROT32; /* temporary value */
120- }
121-#endif
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)
126- ctxt->mode = mode;
127- return rc;
128+ return assign_eip(ctxt, dst);
129 }
130
131 static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
132@@ -2172,7 +2201,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
133 if (rc != X86EMUL_CONTINUE)
134 return rc;
135
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@@ -2250,7 +2279,7 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
142 &new_desc);
143 if (rc != X86EMUL_CONTINUE)
144 return rc;
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@@ -3470,7 +3499,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
151 if (rc != X86EMUL_CONTINUE)
152 return rc;
153
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)
157 goto fail;
158