]> git.proxmox.com Git - pve-kernel.git/blob - patches/kernel/0021-KVM-x86-emulator-introduce-update_emulation_mode.patch
1ccc27df012668961f885cb35243100f135f01fe
[pve-kernel.git] / patches / kernel / 0021-KVM-x86-emulator-introduce-update_emulation_mode.patch
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
5
6 Some instructions update the cpu execution mode, which needs
7 to update the emulation mode.
8
9 Extract this code, and make assign_eip_far use it.
10
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.
14
15 No functional change is intended.
16
17 Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
18 Signed-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
23 diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
24 index 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