]>
Commit | Line | Data |
---|---|---|
54ebe3cb TL |
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 |