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