1 ////////////////////////////////////////////////////////////////////////
2 // $Id: jmp_far.cc,v 1.16 2008/05/25 15:53:29 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2005 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 ////////////////////////////////////////////////////////////////////////
24 #define NEED_CPU_REG_SHORTCUTS 1
27 #define LOG_THIS BX_CPU_THIS_PTR
29 #if BX_SUPPORT_X86_64==0
30 // Make life easier merging cpu64 & cpu code.
34 void BX_CPP_AttrRegparmN(3)
35 BX_CPU_C::jump_protected(bxInstruction_c
*i
, Bit16u cs_raw
, bx_address disp
)
37 bx_descriptor_t descriptor
;
38 bx_selector_t selector
;
39 Bit32u dword1
, dword2
;
41 /* destination selector is not null else #GP(0) */
42 if ((cs_raw
& 0xfffc) == 0) {
43 BX_ERROR(("jump_protected: cs == 0"));
44 exception(BX_GP_EXCEPTION
, 0, 0);
47 parse_selector(cs_raw
, &selector
);
49 /* destination selector index is within its descriptor table
50 limits else #GP(selector) */
51 fetch_raw_descriptor(&selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
53 /* examine AR byte of destination selector for legal values: */
54 parse_descriptor(dword1
, dword2
, &descriptor
);
56 if (descriptor
.segment
) {
57 check_cs(&descriptor
, cs_raw
, BX_SELECTOR_RPL(cs_raw
), CPL
);
58 branch_far64(&selector
, &descriptor
, disp
, CPL
);
62 // call gate DPL must be >= CPL else #GP(gate selector)
63 if (descriptor
.dpl
< CPL
) {
64 BX_ERROR(("jump_protected: call gate.dpl < CPL"));
65 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
68 // call gate DPL must be >= gate selector RPL else #GP(gate selector)
69 if (descriptor
.dpl
< selector
.rpl
) {
70 BX_ERROR(("jump_protected: call gate.dpl < selector.rpl"));
71 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
76 if (descriptor
.type
!= BX_386_CALL_GATE
) {
77 BX_ERROR(("jump_protected: gate type %u unsupported in long mode", (unsigned) descriptor
.type
));
78 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
84 switch (descriptor
.type
) {
85 case BX_SYS_SEGMENT_AVAIL_286_TSS
:
86 case BX_SYS_SEGMENT_AVAIL_386_TSS
:
87 case BX_286_CALL_GATE
:
88 case BX_386_CALL_GATE
:
92 BX_ERROR(("jump_protected: gate type %u unsupported", (unsigned) descriptor
.type
));
93 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
97 // task gate must be present else #NP(gate selector)
98 if (! IS_PRESENT(descriptor
)) {
99 BX_ERROR(("jump_protected: call gate.p == 0"));
100 exception(BX_NP_EXCEPTION
, cs_raw
& 0xfffc, 0);
103 #if BX_SUPPORT_X86_64
105 jmp_call_gate64(&selector
);
110 switch (descriptor
.type
) {
111 case BX_SYS_SEGMENT_AVAIL_286_TSS
:
112 case BX_SYS_SEGMENT_AVAIL_386_TSS
:
114 if (descriptor
.type
==BX_SYS_SEGMENT_AVAIL_286_TSS
)
115 BX_DEBUG(("jump_protected: jump to 286 TSS"));
117 BX_DEBUG(("jump_protected: jump to 386 TSS"));
119 // SWITCH_TASKS _without_ nesting to TSS
120 task_switch(&selector
, &descriptor
, BX_TASK_FROM_JUMP
, dword1
, dword2
);
122 // EIP must be in code seg limit, else #GP(0)
123 if (EIP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
) {
124 BX_ERROR(("jump_protected: EIP not within CS limits"));
125 exception(BX_GP_EXCEPTION
, 0, 0);
130 jmp_task_gate(&descriptor
);
133 case BX_286_CALL_GATE
:
134 case BX_386_CALL_GATE
:
135 jmp_call_gate(&descriptor
);
138 default: // can't get here
139 BX_PANIC(("jump_protected: gate type %u unsupported", (unsigned) descriptor
.type
));
140 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
145 void BX_CPP_AttrRegparmN(1)
146 BX_CPU_C::jmp_task_gate(bx_descriptor_t
*gate_descriptor
)
148 Bit16u raw_tss_selector
;
149 bx_selector_t tss_selector
;
150 bx_descriptor_t tss_descriptor
;
151 Bit32u dword1
, dword2
;
154 // examine selector to TSS, given in Task Gate descriptor
155 // must specify global in the local/global bit else #GP(TSS selector)
156 raw_tss_selector
= gate_descriptor
->u
.taskgate
.tss_selector
;
157 parse_selector(raw_tss_selector
, &tss_selector
);
159 if (tss_selector
.ti
) {
160 BX_ERROR(("jmp_task_gate: tss_selector.ti=1"));
161 exception(BX_GP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
164 // index must be within GDT limits else #GP(TSS selector)
165 fetch_raw_descriptor(&tss_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
167 // descriptor AR byte must specify available TSS
168 // else #GP(TSS selector)
169 parse_descriptor(dword1
, dword2
, &tss_descriptor
);
171 if (tss_descriptor
.valid
==0 || tss_descriptor
.segment
) {
172 BX_ERROR(("jmp_task_gate: TSS selector points to bad TSS"));
173 exception(BX_GP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
175 if (tss_descriptor
.type
!=BX_SYS_SEGMENT_AVAIL_286_TSS
&&
176 tss_descriptor
.type
!=BX_SYS_SEGMENT_AVAIL_386_TSS
)
178 BX_ERROR(("jmp_task_gate: TSS selector points to bad TSS"));
179 exception(BX_GP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
182 // task state segment must be present, else #NP(tss selector)
183 if (! IS_PRESENT(tss_descriptor
)) {
184 BX_ERROR(("jmp_task_gate: TSS descriptor.p == 0"));
185 exception(BX_NP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
188 // SWITCH_TASKS _without_ nesting to TSS
189 task_switch(&tss_selector
, &tss_descriptor
, BX_TASK_FROM_JUMP
, dword1
, dword2
);
191 // EIP must be within code segment limit, else #GP(0)
192 if (BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.d_b
)
197 if (temp_eIP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
) {
198 BX_ERROR(("jmp_task_gate: EIP > CS.limit"));
199 exception(BX_GP_EXCEPTION
, 0, 0);
203 void BX_CPP_AttrRegparmN(1)
204 BX_CPU_C::jmp_call_gate(bx_descriptor_t
*gate_descriptor
)
206 bx_selector_t gate_cs_selector
;
207 bx_descriptor_t gate_cs_descriptor
;
208 Bit32u dword1
, dword2
;
210 if (gate_descriptor
->type
==BX_286_CALL_GATE
)
211 BX_DEBUG(("jmp_call_gate: jump to 286 CALL GATE"));
213 BX_DEBUG(("jmp_call_gate: jump to 386 CALL GATE"));
215 // examine selector to code segment given in call gate descriptor
216 // selector must not be null, else #GP(0)
217 Bit16u gate_cs_raw
= gate_descriptor
->u
.gate
.dest_selector
;
219 if ((gate_cs_raw
& 0xfffc) == 0) {
220 BX_ERROR(("jmp_call_gate: CS selector null"));
221 exception(BX_GP_EXCEPTION
, 0, 0);
224 parse_selector(gate_cs_raw
, &gate_cs_selector
);
225 // selector must be within its descriptor table limits else #GP(CS selector)
226 fetch_raw_descriptor(&gate_cs_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
227 parse_descriptor(dword1
, dword2
, &gate_cs_descriptor
);
229 // check code-segment descriptor
230 check_cs(&gate_cs_descriptor
, gate_cs_raw
, 0, CPL
);
232 Bit32u temp_EIP
= gate_descriptor
->u
.gate
.dest_offset
;
233 branch_far32(&gate_cs_selector
, &gate_cs_descriptor
, temp_EIP
, CPL
);
236 #if BX_SUPPORT_X86_64
237 void BX_CPP_AttrRegparmN(1)
238 BX_CPU_C::jmp_call_gate64(bx_selector_t
*gate_selector
)
240 bx_selector_t cs_selector
;
241 Bit32u dword1
, dword2
, dword3
;
242 bx_descriptor_t cs_descriptor
;
243 bx_descriptor_t gate_descriptor
;
245 BX_DEBUG(("jmp_call_gate64: jump to CALL GATE 64"));
247 fetch_raw_descriptor_64(gate_selector
, &dword1
, &dword2
, &dword3
, BX_GP_EXCEPTION
);
248 parse_descriptor(dword1
, dword2
, &gate_descriptor
);
250 Bit16u dest_selector
= gate_descriptor
.u
.gate
.dest_selector
;
251 // selector must not be null else #GP(0)
252 if ((dest_selector
& 0xfffc) == 0) {
253 BX_ERROR(("jmp_call_gate64: selector in gate null"));
254 exception(BX_GP_EXCEPTION
, 0, 0);
257 parse_selector(dest_selector
, &cs_selector
);
258 // selector must be within its descriptor table limits,
259 // else #GP(code segment selector)
260 fetch_raw_descriptor(&cs_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
261 parse_descriptor(dword1
, dword2
, &cs_descriptor
);
263 // find the RIP in the gate_descriptor
264 Bit64u new_RIP
= gate_descriptor
.u
.gate
.dest_offset
;
265 new_RIP
|= ((Bit64u
)dword3
<< 32);
267 // AR byte of selected descriptor must indicate code segment,
268 // else #GP(code segment selector)
269 if (cs_descriptor
.valid
==0 || cs_descriptor
.segment
==0 ||
270 IS_DATA_SEGMENT(cs_descriptor
.type
))
272 BX_ERROR(("jmp_call_gate64: not code segment in 64-bit call gate"));
273 exception(BX_GP_EXCEPTION
, dest_selector
& 0xfffc, 0);
276 // In long mode, only 64-bit call gates are allowed, and they must point
277 // to 64-bit code segments, else #GP(selector)
278 if (! IS_LONG64_SEGMENT(cs_descriptor
) || cs_descriptor
.u
.segment
.d_b
)
280 BX_ERROR(("jmp_call_gate64: not 64-bit code segment in 64-bit call gate"));
281 exception(BX_GP_EXCEPTION
, dest_selector
& 0xfffc, 0);
284 // check code-segment descriptor
285 check_cs(&cs_descriptor
, dest_selector
, 0, CPL
);
286 // and transfer the control
287 branch_far64(&cs_selector
, &cs_descriptor
, new_RIP
, CPL
);