1 ////////////////////////////////////////////////////////////////////////
2 // $Id: jmp_far.cc 13699 2019-12-20 07:42:07Z sshwarts $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2005-2019 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
21 //
22 ////////////////////////////////////////////////////////////////////////
23
24 #define NEED_CPU_REG_SHORTCUTS 1
25 #include "bochs.h"
26 #include "cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
28
29 void BX_CPP_AttrRegparmN(3)
jump_protected(bxInstruction_c * i,Bit16u cs_raw,bx_address disp)30 BX_CPU_C::jump_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
31 {
32 bx_descriptor_t descriptor;
33 bx_selector_t selector;
34 Bit32u dword1, dword2;
35
36 /* destination selector is not null else #GP(0) */
37 if ((cs_raw & 0xfffc) == 0) {
38 BX_ERROR(("jump_protected: cs == 0"));
39 exception(BX_GP_EXCEPTION, 0);
40 }
41
42 parse_selector(cs_raw, &selector);
43
44 /* destination selector index is within its descriptor table
45 limits else #GP(selector) */
46 fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
47
48 /* examine AR byte of destination selector for legal values: */
49 parse_descriptor(dword1, dword2, &descriptor);
50
51 if (descriptor.segment) {
52 check_cs(&descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);
53 branch_far(&selector, &descriptor, disp, CPL);
54 #if BX_SUPPORT_CET
55 track_indirect(CPL);
56 #endif
57 return;
58 }
59 else {
60 // call gate DPL must be >= CPL else #GP(gate selector)
61 if (descriptor.dpl < CPL) {
62 BX_ERROR(("jump_protected: call gate.dpl < CPL"));
63 exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
64 }
65
66 // call gate DPL must be >= gate selector RPL else #GP(gate selector)
67 if (descriptor.dpl < selector.rpl) {
68 BX_ERROR(("jump_protected: call gate.dpl < selector.rpl"));
69 exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
70 }
71
72 #if BX_SUPPORT_X86_64
73 if (long_mode()) {
74 if (descriptor.type != BX_386_CALL_GATE) {
75 BX_ERROR(("jump_protected: gate type %u unsupported in long mode", (unsigned) descriptor.type));
76 exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
77 }
78 // gate must be present else #NP(gate selector)
79 if (! IS_PRESENT(descriptor)) {
80 BX_ERROR(("jump_protected: call gate not present!"));
81 exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
82 }
83
84 jmp_call_gate64(&selector);
85 return;
86 }
87 #endif
88
89 switch (descriptor.type) {
90 case BX_SYS_SEGMENT_AVAIL_286_TSS:
91 case BX_SYS_SEGMENT_AVAIL_386_TSS:
92
93 if (descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
94 BX_DEBUG(("jump_protected: jump to 286 TSS"));
95 else
96 BX_DEBUG(("jump_protected: jump to 386 TSS"));
97
98 if (descriptor.valid==0 || selector.ti) {
99 BX_ERROR(("jump_protected: jump to bad TSS selector !"));
100 exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
101 }
102
103 // TSS must be present, else #NP(TSS selector)
104 if (! IS_PRESENT(descriptor)) {
105 BX_ERROR(("jump_protected: jump to not present TSS !"));
106 exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
107 }
108
109 // SWITCH_TASKS _without_ nesting to TSS
110 task_switch(i, &selector, &descriptor, BX_TASK_FROM_JUMP, dword1, dword2);
111 return;
112
113 case BX_TASK_GATE:
114 task_gate(i, &selector, &descriptor, BX_TASK_FROM_JUMP);
115 return;
116
117 case BX_286_CALL_GATE:
118 case BX_386_CALL_GATE:
119 jmp_call_gate(&selector, &descriptor);
120 return;
121
122 default:
123 BX_ERROR(("jump_protected: gate type %u unsupported", (unsigned) descriptor.type));
124 exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
125 }
126 }
127 }
128
task_gate(bxInstruction_c * i,bx_selector_t * selector,bx_descriptor_t * gate_descriptor,unsigned source)129 void BX_CPU_C::task_gate(bxInstruction_c *i, bx_selector_t *selector, bx_descriptor_t *gate_descriptor, unsigned source)
130 {
131 Bit16u raw_tss_selector;
132 bx_selector_t tss_selector;
133 bx_descriptor_t tss_descriptor;
134 Bit32u dword1, dword2;
135
136 // task gate must be present else #NP(gate selector)
137 if (! gate_descriptor->p) {
138 BX_ERROR(("task_gate: task gate not present"));
139 exception(BX_NP_EXCEPTION, selector->value & 0xfffc);
140 }
141
142 // examine selector to TSS, given in Task Gate descriptor
143 // must specify global in the local/global bit else #GP(TSS selector)
144 raw_tss_selector = gate_descriptor->u.taskgate.tss_selector;
145 parse_selector(raw_tss_selector, &tss_selector);
146
147 if (tss_selector.ti) {
148 BX_ERROR(("task_gate: tss_selector.ti=1"));
149 exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
150 }
151
152 // index must be within GDT limits else #GP(TSS selector)
153 fetch_raw_descriptor(&tss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
154
155 // descriptor AR byte must specify available TSS
156 // else #GP(TSS selector)
157 parse_descriptor(dword1, dword2, &tss_descriptor);
158
159 if (tss_descriptor.valid==0 || tss_descriptor.segment) {
160 BX_ERROR(("task_gate: TSS selector points to bad TSS"));
161 exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
162 }
163 if (tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
164 tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS)
165 {
166 BX_ERROR(("task_gate: TSS selector points to bad TSS"));
167 exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
168 }
169
170 // task state segment must be present, else #NP(tss selector)
171 if (! IS_PRESENT(tss_descriptor)) {
172 BX_ERROR(("task_gate: TSS descriptor.p == 0"));
173 exception(BX_NP_EXCEPTION, raw_tss_selector & 0xfffc);
174 }
175
176 // SWITCH_TASKS _without_ nesting to TSS
177 task_switch(i, &tss_selector, &tss_descriptor, source, dword1, dword2);
178 }
179
180 void BX_CPP_AttrRegparmN(2)
jmp_call_gate(bx_selector_t * selector,bx_descriptor_t * gate_descriptor)181 BX_CPU_C::jmp_call_gate(bx_selector_t *selector, bx_descriptor_t *gate_descriptor)
182 {
183 bx_selector_t gate_cs_selector;
184 bx_descriptor_t gate_cs_descriptor;
185 Bit32u dword1, dword2;
186
187 if (gate_descriptor->type==BX_286_CALL_GATE)
188 BX_DEBUG(("jmp_call_gate: jump to 286 CALL GATE"));
189 else
190 BX_DEBUG(("jmp_call_gate: jump to 386 CALL GATE"));
191
192 // task gate must be present else #NP(gate selector)
193 if (! gate_descriptor->p) {
194 BX_ERROR(("jmp_call_gate: call gate not present!"));
195 exception(BX_NP_EXCEPTION, selector->value & 0xfffc);
196 }
197
198 // examine selector to code segment given in call gate descriptor
199 // selector must not be null, else #GP(0)
200 Bit16u gate_cs_raw = gate_descriptor->u.gate.dest_selector;
201
202 if ((gate_cs_raw & 0xfffc) == 0) {
203 BX_ERROR(("jmp_call_gate: CS selector null"));
204 exception(BX_GP_EXCEPTION, 0);
205 }
206
207 parse_selector(gate_cs_raw, &gate_cs_selector);
208 // selector must be within its descriptor table limits else #GP(CS selector)
209 fetch_raw_descriptor(&gate_cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
210 parse_descriptor(dword1, dword2, &gate_cs_descriptor);
211
212 // check code-segment descriptor
213 check_cs(&gate_cs_descriptor, gate_cs_raw, 0, CPL);
214
215 Bit32u temp_EIP = gate_descriptor->u.gate.dest_offset;
216 branch_far(&gate_cs_selector, &gate_cs_descriptor, temp_EIP, CPL);
217
218 #if BX_SUPPORT_CET
219 track_indirect(CPL);
220 #endif
221 }
222
223 #if BX_SUPPORT_X86_64
224 void BX_CPP_AttrRegparmN(1)
jmp_call_gate64(bx_selector_t * gate_selector)225 BX_CPU_C::jmp_call_gate64(bx_selector_t *gate_selector)
226 {
227 bx_selector_t cs_selector;
228 Bit32u dword1, dword2, dword3;
229 bx_descriptor_t cs_descriptor;
230 bx_descriptor_t gate_descriptor;
231
232 BX_DEBUG(("jmp_call_gate64: jump to CALL GATE 64"));
233
234 fetch_raw_descriptor_64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
235 parse_descriptor(dword1, dword2, &gate_descriptor);
236
237 Bit16u dest_selector = gate_descriptor.u.gate.dest_selector;
238 // selector must not be null else #GP(0)
239 if ((dest_selector & 0xfffc) == 0) {
240 BX_ERROR(("jmp_call_gate64: selector in gate null"));
241 exception(BX_GP_EXCEPTION, 0);
242 }
243
244 parse_selector(dest_selector, &cs_selector);
245 // selector must be within its descriptor table limits,
246 // else #GP(code segment selector)
247 fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
248 parse_descriptor(dword1, dword2, &cs_descriptor);
249
250 // find the RIP in the gate_descriptor
251 Bit64u new_RIP = gate_descriptor.u.gate.dest_offset;
252 new_RIP |= ((Bit64u)dword3 << 32);
253
254 // AR byte of selected descriptor must indicate code segment,
255 // else #GP(code segment selector)
256 if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
257 IS_DATA_SEGMENT(cs_descriptor.type))
258 {
259 BX_ERROR(("jmp_call_gate64: not code segment in 64-bit call gate"));
260 exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
261 }
262
263 // In long mode, only 64-bit call gates are allowed, and they must point
264 // to 64-bit code segments, else #GP(selector)
265 if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
266 {
267 BX_ERROR(("jmp_call_gate64: not 64-bit code segment in 64-bit call gate"));
268 exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
269 }
270
271 // check code-segment descriptor
272 check_cs(&cs_descriptor, dest_selector, 0, CPL);
273 // and transfer the control
274 branch_far(&cs_selector, &cs_descriptor, new_RIP, CPL);
275
276 #if BX_SUPPORT_CET
277 track_indirect(CPL);
278 #endif
279 }
280 #endif
281