- tftp_send_optack() was not 64-bit clean (patch from SF bug #1787500)
[bochs-mirror.git] / cpu / jmp_far.cc
blob06c604ab2b119814d366f54be5430c22c2f6a9d3
1 ////////////////////////////////////////////////////////////////////////
2 // $Id: jmp_far.cc,v 1.8 2006/10/04 19:08:40 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
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
30 #include "bochs.h"
31 #include "cpu.h"
32 #define LOG_THIS BX_CPU_THIS_PTR
34 #if BX_SUPPORT_X86_64==0
35 // Make life easier merging cpu64 & cpu code.
36 #define RIP EIP
37 #endif
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);
65 return;
67 else {
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);
86 #if BX_SUPPORT_X86_64
87 if (long_mode()) {
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);
92 else {
93 jmp_call_gate64(&selector);
94 return;
97 #endif
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"));
105 else
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);
116 return;
118 case BX_286_CALL_GATE:
119 jmp_call_gate16(&descriptor);
120 return;
122 case BX_TASK_GATE:
123 jmp_task_gate(&descriptor);
124 return;
126 case BX_386_CALL_GATE:
127 jmp_call_gate32(&descriptor);
128 return;
130 default:
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;
144 Bit32u temp_eIP;
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)
183 temp_eIP = EIP;
184 else
185 temp_eIP = IP;
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);
308 #endif