- update sector count before calling write completion function (SF patch #2144692)
[bochs-mirror.git] / cpu / jmp_far.cc
blob2b1f54ed84674d1a908e4a520b4176db532aaa2f
1 ////////////////////////////////////////////////////////////////////////
2 // $Id: jmp_far.cc,v 1.16 2008/05/25 15:53:29 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2005 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.
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
25 #include "bochs.h"
26 #include "cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
29 #if BX_SUPPORT_X86_64==0
30 // Make life easier merging cpu64 & cpu code.
31 #define RIP EIP
32 #endif
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);
59 return;
61 else {
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);
74 #if BX_SUPPORT_X86_64
75 if (long_mode()) {
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);
81 else
82 #endif
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:
89 case BX_TASK_GATE:
90 break;
91 default:
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
104 if (long_mode()) {
105 jmp_call_gate64(&selector);
106 return;
108 #endif
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"));
116 else
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);
127 return;
129 case BX_TASK_GATE:
130 jmp_task_gate(&descriptor);
131 return;
133 case BX_286_CALL_GATE:
134 case BX_386_CALL_GATE:
135 jmp_call_gate(&descriptor);
136 return;
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;
152 Bit32u temp_eIP;
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)
193 temp_eIP = EIP;
194 else
195 temp_eIP = IP;
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"));
212 else
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);
289 #endif