1 ////////////////////////////////////////////////////////////////////////
2 // $Id: jmp_far.cc,v 1.8 2006/10/04 19:08:40 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #define NEED_CPU_REG_SHORTCUTS 1
32 #define LOG_THIS BX_CPU_THIS_PTR
34 #if BX_SUPPORT_X86_64==0
35 // Make life easier merging cpu64 & cpu code.
40 void BX_CPP_AttrRegparmN(3)
41 BX_CPU_C::jump_protected(bxInstruction_c
*i
, Bit16u cs_raw
, bx_address disp
)
43 bx_descriptor_t descriptor
;
44 bx_selector_t selector
;
45 Bit32u dword1
, dword2
;
47 /* destination selector is not null else #GP(0) */
48 if ((cs_raw
& 0xfffc) == 0) {
49 BX_ERROR(("jump_protected: cs == 0"));
50 exception(BX_GP_EXCEPTION
, 0, 0);
53 parse_selector(cs_raw
, &selector
);
55 /* destination selector index is within its descriptor table
56 limits else #GP(selector) */
57 fetch_raw_descriptor(&selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
59 /* examine AR byte of destination selector for legal values: */
60 parse_descriptor(dword1
, dword2
, &descriptor
);
62 if (descriptor
.segment
) {
63 check_cs(&descriptor
, cs_raw
, BX_SELECTOR_RPL(cs_raw
), CPL
);
64 branch_far64(&selector
, &descriptor
, disp
, CPL
);
68 // call gate DPL must be >= CPL else #GP(gate selector)
69 if (descriptor
.dpl
< CPL
) {
70 BX_ERROR(("jump_protected: call gate.dpl < CPL"));
71 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
74 // call gate DPL must be >= gate selector RPL else #GP(gate selector)
75 if (descriptor
.dpl
< selector
.rpl
) {
76 BX_ERROR(("jump_protected: call gate.dpl < selector.rpl"));
77 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
80 // task gate must be present else #NP(gate selector)
81 if (! IS_PRESENT(descriptor
)) {
82 BX_ERROR(("jump_protected: call gate.p == 0"));
83 exception(BX_NP_EXCEPTION
, cs_raw
& 0xfffc, 0);
88 if (descriptor
.type
!= BX_386_CALL_GATE
) {
89 BX_ERROR(("jump_protected: gate type %u unsupported in long mode", (unsigned) descriptor
.type
));
90 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
93 jmp_call_gate64(&selector
);
99 switch (descriptor
.type
) {
100 case BX_SYS_SEGMENT_AVAIL_286_TSS
:
101 case BX_SYS_SEGMENT_AVAIL_386_TSS
:
103 if (descriptor
.type
==BX_SYS_SEGMENT_AVAIL_286_TSS
)
104 BX_DEBUG(("jump to 286 TSS"));
106 BX_DEBUG(("jump to 386 TSS"));
108 // SWITCH_TASKS _without_ nesting to TSS
109 task_switch(&selector
, &descriptor
, BX_TASK_FROM_JUMP
, dword1
, dword2
);
111 // EIP must be in code seg limit, else #GP(0)
112 if (EIP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
) {
113 BX_ERROR(("jump_protected: EIP not within CS limits"));
114 exception(BX_GP_EXCEPTION
, 0, 0);
118 case BX_286_CALL_GATE
:
119 jmp_call_gate16(&descriptor
);
123 jmp_task_gate(&descriptor
);
126 case BX_386_CALL_GATE
:
127 jmp_call_gate32(&descriptor
);
131 BX_ERROR(("jump_protected: gate type %u unsupported", (unsigned) descriptor
.type
));
132 exception(BX_GP_EXCEPTION
, cs_raw
& 0xfffc, 0);
137 void BX_CPP_AttrRegparmN(1)
138 BX_CPU_C::jmp_task_gate(bx_descriptor_t
*gate_descriptor
)
140 Bit16u raw_tss_selector
;
141 bx_selector_t tss_selector
;
142 bx_descriptor_t tss_descriptor
;
143 Bit32u dword1
, dword2
;
146 // examine selector to TSS, given in Task Gate descriptor
147 // must specify global in the local/global bit else #GP(TSS selector)
148 raw_tss_selector
= gate_descriptor
->u
.taskgate
.tss_selector
;
149 parse_selector(raw_tss_selector
, &tss_selector
);
151 if (tss_selector
.ti
) {
152 BX_ERROR(("jump_protected: tss_selector.ti=1"));
153 exception(BX_GP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
156 // index must be within GDT limits else #GP(TSS selector)
157 fetch_raw_descriptor(&tss_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
159 // descriptor AR byte must specify available TSS
160 // else #GP(TSS selector)
161 parse_descriptor(dword1
, dword2
, &tss_descriptor
);
163 if (tss_descriptor
.valid
==0 || tss_descriptor
.segment
) {
164 BX_ERROR(("jump_protected: TSS selector points to bad TSS"));
165 exception(BX_GP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
167 if (tss_descriptor
.type
!=9 && tss_descriptor
.type
!=1) {
168 BX_ERROR(("jump_protected: TSS selector points to bad TSS"));
169 exception(BX_GP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
172 // task state segment must be present, else #NP(tss selector)
173 if (! IS_PRESENT(tss_descriptor
)) {
174 BX_ERROR(("jump_protected: TSS descriptor.p == 0"));
175 exception(BX_NP_EXCEPTION
, raw_tss_selector
& 0xfffc, 0);
178 // SWITCH_TASKS _without_ nesting to TSS
179 task_switch(&tss_selector
, &tss_descriptor
, BX_TASK_FROM_JUMP
, dword1
, dword2
);
181 // EIP must be within code segment limit, else #GP(0)
182 if (BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.d_b
)
187 if (temp_eIP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
) {
188 BX_ERROR(("jump_protected: EIP > CS.limit"));
189 exception(BX_GP_EXCEPTION
, 0, 0);
193 void BX_CPP_AttrRegparmN(1)
194 BX_CPU_C::jmp_call_gate16(bx_descriptor_t
*gate_descriptor
)
196 bx_selector_t gate_cs_selector
;
197 bx_descriptor_t gate_cs_descriptor
;
198 Bit32u dword1
, dword2
;
200 BX_DEBUG(("jump_protected: JUMP TO 286 CALL GATE"));
202 // examine selector to code segment given in call gate descriptor
203 // selector must not be null, else #GP(0)
204 Bit16u gate_cs_raw
= gate_descriptor
->u
.gate286
.dest_selector
;
206 if ((gate_cs_raw
& 0xfffc) == 0) {
207 BX_ERROR(("jump_protected: CS selector null"));
208 exception(BX_GP_EXCEPTION
, 0, 0);
211 parse_selector(gate_cs_raw
, &gate_cs_selector
);
212 // selector must be within its descriptor table limits else #GP(CS selector)
213 fetch_raw_descriptor(&gate_cs_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
214 parse_descriptor(dword1
, dword2
, &gate_cs_descriptor
);
216 // check code-segment descriptor
217 check_cs(&gate_cs_descriptor
, gate_cs_raw
, 0, CPL
);
219 Bit16u temp_IP
= gate_descriptor
->u
.gate286
.dest_offset
;
221 branch_far32(&gate_cs_selector
, &gate_cs_descriptor
, temp_IP
, CPL
);
224 void BX_CPP_AttrRegparmN(1)
225 BX_CPU_C::jmp_call_gate32(bx_descriptor_t
*gate_descriptor
)
227 bx_selector_t gate_cs_selector
;
228 bx_descriptor_t gate_cs_descriptor
;
229 Bit32u dword1
, dword2
;
231 BX_DEBUG(("jump_protected: JUMP TO 386 CALL GATE"));
233 // examine selector to code segment given in call gate descriptor
234 // selector must not be null, else #GP(0)
235 Bit16u gate_cs_raw
= gate_descriptor
->u
.gate386
.dest_selector
;
237 if ((gate_cs_raw
& 0xfffc) == 0) {
238 BX_ERROR(("jump_protected: CS selector null"));
239 exception(BX_GP_EXCEPTION
, 0, 0);
242 parse_selector(gate_cs_raw
, &gate_cs_selector
);
243 // selector must be within its descriptor table limits else #GP(CS selector)
244 fetch_raw_descriptor(&gate_cs_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
245 parse_descriptor(dword1
, dword2
, &gate_cs_descriptor
);
247 // check code-segment descriptor
248 check_cs(&gate_cs_descriptor
, gate_cs_raw
, 0, CPL
);
250 Bit32u temp_EIP
= gate_descriptor
->u
.gate386
.dest_offset
;
252 branch_far32(&gate_cs_selector
, &gate_cs_descriptor
, temp_EIP
, CPL
);
255 #if BX_SUPPORT_X86_64
256 void BX_CPP_AttrRegparmN(1)
257 BX_CPU_C::jmp_call_gate64(bx_selector_t
*gate_selector
)
259 bx_selector_t cs_selector
;
260 Bit32u dword1
, dword2
, dword3
;
261 bx_descriptor_t cs_descriptor
;
262 bx_descriptor_t gate_descriptor
;
264 BX_DEBUG(("jump_protected: jump to CALL GATE 64"));
266 fetch_raw_descriptor64(gate_selector
, &dword1
, &dword2
, &dword3
, BX_GP_EXCEPTION
);
267 parse_descriptor(dword1
, dword2
, &gate_descriptor
);
269 Bit16u dest_selector
= gate_descriptor
.u
.gate386
.dest_selector
;
270 // selector must not be null else #GP(0)
271 if ( (dest_selector
& 0xfffc) == 0 ) {
272 BX_ERROR(("call_gate64: selector in gate null"));
273 exception(BX_GP_EXCEPTION
, 0, 0);
276 parse_selector(dest_selector
, &cs_selector
);
277 // selector must be within its descriptor table limits,
278 // else #GP(code segment selector)
279 fetch_raw_descriptor(&cs_selector
, &dword1
, &dword2
, BX_GP_EXCEPTION
);
280 parse_descriptor(dword1
, dword2
, &cs_descriptor
);
282 // find the RIP in the gate_descriptor
283 Bit64u new_RIP
= gate_descriptor
.u
.gate386
.dest_offset
;
284 new_RIP
|= ((Bit64u
)dword3
<< 32);
286 // AR byte of selected descriptor must indicate code segment,
287 // else #GP(code segment selector)
288 if (cs_descriptor
.valid
==0 || cs_descriptor
.segment
==0 ||
289 IS_DATA_SEGMENT(cs_descriptor
.type
))
291 BX_ERROR(("jump_protected: not code segment in call gate 64"));
292 exception(BX_GP_EXCEPTION
, dest_selector
& 0xfffc, 0);
295 // In long mode, only 64-bit call gates are allowed, and they must point
296 // to 64-bit code segments, else #GP(selector)
297 if (! IS_LONG64_SEGMENT(cs_descriptor
) || cs_descriptor
.u
.segment
.d_b
)
299 BX_ERROR(("jump_protected: not 64-bit code segment in call gate 64"));
300 exception(BX_GP_EXCEPTION
, dest_selector
& 0xfffc, 0);
303 // check code-segment descriptor
304 check_cs(&cs_descriptor
, dest_selector
, 0, CPL
);
305 // and transfer the control
306 branch_far64(&cs_selector
, &cs_descriptor
, new_RIP
, CPL
);