1 |
2 |
alfik |
/////////////////////////////////////////////////////////////////////////
|
2 |
|
|
// $Id: segment_ctrl_pro.cc 11107 2012-03-25 19:07:17Z sshwarts $
|
3 |
|
|
/////////////////////////////////////////////////////////////////////////
|
4 |
|
|
//
|
5 |
|
|
// Copyright (C) 2001-2012 The Bochs Project
|
6 |
|
|
//
|
7 |
|
|
// This library is free software; you can redistribute it and/or
|
8 |
|
|
// modify it under the terms of the GNU Lesser General Public
|
9 |
|
|
// License as published by the Free Software Foundation; either
|
10 |
|
|
// version 2 of the License, or (at your option) any later version.
|
11 |
|
|
//
|
12 |
|
|
// This library is distributed in the hope that it will be useful,
|
13 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 |
|
|
// Lesser General Public License for more details.
|
16 |
|
|
//
|
17 |
|
|
// You should have received a copy of the GNU Lesser General Public
|
18 |
|
|
// License along with this library; if not, write to the Free Software
|
19 |
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
|
20 |
|
|
/////////////////////////////////////////////////////////////////////////
|
21 |
|
|
|
22 |
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
23 |
|
|
#include "bochs.h"
|
24 |
|
|
#include "cpu.h"
|
25 |
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
26 |
|
|
|
27 |
|
|
void BX_CPP_AttrRegparmN(2)
|
28 |
|
|
BX_CPU_C::load_seg_reg(bx_segment_reg_t *seg, Bit16u new_value)
|
29 |
|
|
{
|
30 |
|
|
if (protected_mode())
|
31 |
|
|
{
|
32 |
|
|
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS])
|
33 |
|
|
{
|
34 |
|
|
bx_selector_t ss_selector;
|
35 |
|
|
bx_descriptor_t descriptor;
|
36 |
|
|
Bit32u dword1, dword2;
|
37 |
|
|
|
38 |
|
|
parse_selector(new_value, &ss_selector);
|
39 |
|
|
|
40 |
|
|
if ((new_value & 0xfffc) == 0) { /* null selector */
|
41 |
|
|
#if BX_SUPPORT_X86_64
|
42 |
|
|
// allow SS = 0 in 64 bit mode only with cpl != 3 and rpl=cpl
|
43 |
|
|
if (long64_mode() && CPL != 3 && ss_selector.rpl == CPL) {
|
44 |
|
|
load_null_selector(seg, new_value);
|
45 |
|
|
return;
|
46 |
|
|
}
|
47 |
|
|
#endif
|
48 |
|
|
BX_ERROR(("load_seg_reg(SS): loading null selector"));
|
49 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
50 |
|
|
}
|
51 |
|
|
|
52 |
|
|
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
53 |
|
|
|
54 |
|
|
/* selector's RPL must = CPL, else #GP(selector) */
|
55 |
|
|
if (ss_selector.rpl != CPL) {
|
56 |
|
|
BX_ERROR(("load_seg_reg(SS): rpl != CPL"));
|
57 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
58 |
|
|
}
|
59 |
|
|
|
60 |
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
61 |
|
|
|
62 |
|
|
if (descriptor.valid==0) {
|
63 |
|
|
BX_ERROR(("load_seg_reg(SS): valid bit cleared"));
|
64 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
65 |
|
|
}
|
66 |
|
|
|
67 |
|
|
/* AR byte must indicate a writable data segment else #GP(selector) */
|
68 |
|
|
if (descriptor.segment==0 || IS_CODE_SEGMENT(descriptor.type) ||
|
69 |
|
|
IS_DATA_SEGMENT_WRITEABLE(descriptor.type) == 0)
|
70 |
|
|
{
|
71 |
|
|
BX_ERROR(("load_seg_reg(SS): not writable data segment"));
|
72 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
73 |
|
|
}
|
74 |
|
|
|
75 |
|
|
/* DPL in the AR byte must equal CPL else #GP(selector) */
|
76 |
|
|
if (descriptor.dpl != CPL) {
|
77 |
|
|
BX_ERROR(("load_seg_reg(SS): dpl != CPL"));
|
78 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
79 |
|
|
}
|
80 |
|
|
|
81 |
|
|
/* segment must be marked PRESENT else #SS(selector) */
|
82 |
|
|
if (! IS_PRESENT(descriptor)) {
|
83 |
|
|
BX_ERROR(("load_seg_reg(SS): not present"));
|
84 |
|
|
exception(BX_SS_EXCEPTION, new_value & 0xfffc);
|
85 |
|
|
}
|
86 |
|
|
|
87 |
|
|
touch_segment(&ss_selector, &descriptor);
|
88 |
|
|
|
89 |
|
|
/* load SS with selector, load SS cache with descriptor */
|
90 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = ss_selector;
|
91 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = descriptor;
|
92 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
|
93 |
|
|
|
94 |
|
|
invalidate_stack_cache();
|
95 |
|
|
|
96 |
|
|
return;
|
97 |
|
|
}
|
98 |
|
|
else if ((seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS]) ||
|
99 |
|
|
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES]) ||
|
100 |
|
|
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS]) ||
|
101 |
|
|
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS])
|
102 |
|
|
)
|
103 |
|
|
{
|
104 |
|
|
bx_descriptor_t descriptor;
|
105 |
|
|
bx_selector_t selector;
|
106 |
|
|
Bit32u dword1, dword2;
|
107 |
|
|
|
108 |
|
|
if ((new_value & 0xfffc) == 0) { /* null selector */
|
109 |
|
|
load_null_selector(seg, new_value);
|
110 |
|
|
return;
|
111 |
|
|
}
|
112 |
|
|
|
113 |
|
|
parse_selector(new_value, &selector);
|
114 |
|
|
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
115 |
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
116 |
|
|
|
117 |
|
|
if (descriptor.valid==0) {
|
118 |
|
|
BX_ERROR(("load_seg_reg(%s, 0x%04x): invalid segment", strseg(seg), new_value));
|
119 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
/* AR byte must indicate data or readable code segment else #GP(selector) */
|
123 |
|
|
if (descriptor.segment==0 || (IS_CODE_SEGMENT(descriptor.type) &&
|
124 |
|
|
IS_CODE_SEGMENT_READABLE(descriptor.type) == 0))
|
125 |
|
|
{
|
126 |
|
|
BX_ERROR(("load_seg_reg(%s, 0x%04x): not data or readable code", strseg(seg), new_value));
|
127 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
128 |
|
|
}
|
129 |
|
|
|
130 |
|
|
/* If data or non-conforming code, then both the RPL and the CPL
|
131 |
|
|
* must be less than or equal to DPL in AR byte else #GP(selector) */
|
132 |
|
|
if (IS_DATA_SEGMENT(descriptor.type) ||
|
133 |
|
|
IS_CODE_SEGMENT_NON_CONFORMING(descriptor.type))
|
134 |
|
|
{
|
135 |
|
|
if ((selector.rpl > descriptor.dpl) || (CPL > descriptor.dpl)) {
|
136 |
|
|
BX_ERROR(("load_seg_reg(%s, 0x%04x): RPL & CPL must be <= DPL", strseg(seg), new_value));
|
137 |
|
|
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
138 |
|
|
}
|
139 |
|
|
}
|
140 |
|
|
|
141 |
|
|
/* segment must be marked PRESENT else #NP(selector) */
|
142 |
|
|
if (! IS_PRESENT(descriptor)) {
|
143 |
|
|
BX_ERROR(("load_seg_reg(%s, 0x%04x): segment not present", strseg(seg), new_value));
|
144 |
|
|
exception(BX_NP_EXCEPTION, new_value & 0xfffc);
|
145 |
|
|
}
|
146 |
|
|
|
147 |
|
|
touch_segment(&selector, &descriptor);
|
148 |
|
|
|
149 |
|
|
/* load segment register with selector */
|
150 |
|
|
/* load segment register-cache with descriptor */
|
151 |
|
|
seg->selector = selector;
|
152 |
|
|
seg->cache = descriptor;
|
153 |
|
|
seg->cache.valid = 1;
|
154 |
|
|
|
155 |
|
|
return;
|
156 |
|
|
}
|
157 |
|
|
else {
|
158 |
|
|
BX_PANIC(("load_seg_reg(): invalid segment register passed!"));
|
159 |
|
|
return;
|
160 |
|
|
}
|
161 |
|
|
}
|
162 |
|
|
|
163 |
|
|
/* real or v8086 mode */
|
164 |
|
|
|
165 |
|
|
/* www.x86.org:
|
166 |
|
|
According to Intel, each time any segment register is loaded in real
|
167 |
|
|
mode, the base address is calculated as 16 times the segment value,
|
168 |
|
|
while the access rights and size limit attributes are given fixed,
|
169 |
|
|
"real-mode compatible" values. This is not true. In fact, only the CS
|
170 |
|
|
descriptor caches for the 286, 386, and 486 get loaded with fixed
|
171 |
|
|
values each time the segment register is loaded. Loading CS, or any
|
172 |
|
|
other segment register in real mode, on later Intel processors doesn't
|
173 |
|
|
change the access rights or the segment size limit attributes stored
|
174 |
|
|
in the descriptor cache registers. For these segments, the access
|
175 |
|
|
rights and segment size limit attributes from any previous setting are
|
176 |
|
|
honored. */
|
177 |
|
|
|
178 |
|
|
seg->selector.value = new_value;
|
179 |
|
|
seg->selector.rpl = real_mode() ? 0 : 3;
|
180 |
|
|
seg->cache.valid = 1;
|
181 |
|
|
seg->cache.u.segment.base = new_value << 4;
|
182 |
|
|
seg->cache.segment = 1; /* regular segment */
|
183 |
|
|
seg->cache.p = 1; /* present */
|
184 |
|
|
|
185 |
|
|
/* Do not modify segment limit and AR bytes when in real mode */
|
186 |
|
|
/* Support for big real mode */
|
187 |
|
|
if (!real_mode()) {
|
188 |
|
|
seg->cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
189 |
|
|
seg->cache.dpl = 3; /* we are in v8086 mode */
|
190 |
|
|
seg->cache.u.segment.limit_scaled = 0xffff;
|
191 |
|
|
seg->cache.u.segment.g = 0; /* byte granular */
|
192 |
|
|
seg->cache.u.segment.d_b = 0; /* default 16bit size */
|
193 |
|
|
#if BX_SUPPORT_X86_64
|
194 |
|
|
seg->cache.u.segment.l = 0; /* default 16bit size */
|
195 |
|
|
#endif
|
196 |
|
|
seg->cache.u.segment.avl = 0;
|
197 |
|
|
}
|
198 |
|
|
|
199 |
|
|
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS]) {
|
200 |
|
|
invalidate_prefetch_q();
|
201 |
|
|
updateFetchModeMask(/* CS reloaded */);
|
202 |
|
|
#if BX_CPU_LEVEL >= 4
|
203 |
|
|
handleAlignmentCheck(/* CPL change */);
|
204 |
|
|
#endif
|
205 |
|
|
}
|
206 |
|
|
|
207 |
|
|
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS])
|
208 |
|
|
invalidate_stack_cache();
|
209 |
|
|
}
|
210 |
|
|
|
211 |
|
|
void BX_CPP_AttrRegparmN(2)
|
212 |
|
|
BX_CPU_C::load_null_selector(bx_segment_reg_t *seg, unsigned value)
|
213 |
|
|
{
|
214 |
|
|
BX_ASSERT((value & 0xfffc) == 0);
|
215 |
|
|
|
216 |
|
|
seg->selector.index = 0;
|
217 |
|
|
seg->selector.ti = 0;
|
218 |
|
|
seg->selector.rpl = BX_SELECTOR_RPL(value);
|
219 |
|
|
seg->selector.value = value;
|
220 |
|
|
|
221 |
|
|
seg->cache.valid = 0; /* invalidate null selector */
|
222 |
|
|
seg->cache.p = 0;
|
223 |
|
|
seg->cache.dpl = 0;
|
224 |
|
|
seg->cache.segment = 1; /* data/code segment */
|
225 |
|
|
seg->cache.type = 0;
|
226 |
|
|
|
227 |
|
|
seg->cache.u.segment.base = 0;
|
228 |
|
|
seg->cache.u.segment.limit_scaled = 0;
|
229 |
|
|
seg->cache.u.segment.g = 0;
|
230 |
|
|
seg->cache.u.segment.d_b = 0;
|
231 |
|
|
seg->cache.u.segment.avl = 0;
|
232 |
|
|
#if BX_SUPPORT_X86_64
|
233 |
|
|
seg->cache.u.segment.l = 0;
|
234 |
|
|
#endif
|
235 |
|
|
|
236 |
|
|
invalidate_stack_cache();
|
237 |
|
|
}
|
238 |
|
|
|
239 |
|
|
BX_CPP_INLINE void BX_CPU_C::validate_seg_reg(unsigned seg)
|
240 |
|
|
{
|
241 |
|
|
/*
|
242 |
|
|
FOR (seg = ES, DS, FS, GS)
|
243 |
|
|
DO
|
244 |
|
|
IF ((seg.attr.dpl < CPL) && ((seg.attr.type = 'data')
|
245 |
|
|
|| (seg.attr.type = 'non-conforming-code')))
|
246 |
|
|
{
|
247 |
|
|
seg = NULL // can't use lower dpl data segment at higher cpl
|
248 |
|
|
}
|
249 |
|
|
END
|
250 |
|
|
*/
|
251 |
|
|
|
252 |
|
|
bx_segment_reg_t *segment = &BX_CPU_THIS_PTR sregs[seg];
|
253 |
|
|
|
254 |
|
|
if (segment->cache.dpl < CPL)
|
255 |
|
|
{
|
256 |
|
|
// invalidate if data or non-conforming code segment
|
257 |
|
|
if (segment->cache.valid==0 || segment->cache.segment==0 ||
|
258 |
|
|
IS_DATA_SEGMENT(segment->cache.type) ||
|
259 |
|
|
IS_CODE_SEGMENT_NON_CONFORMING(segment->cache.type))
|
260 |
|
|
{
|
261 |
|
|
segment->selector.value = 0;
|
262 |
|
|
segment->cache.valid = 0;
|
263 |
|
|
}
|
264 |
|
|
}
|
265 |
|
|
}
|
266 |
|
|
|
267 |
|
|
void BX_CPU_C::validate_seg_regs(void)
|
268 |
|
|
{
|
269 |
|
|
validate_seg_reg(BX_SEG_REG_ES);
|
270 |
|
|
validate_seg_reg(BX_SEG_REG_DS);
|
271 |
|
|
validate_seg_reg(BX_SEG_REG_FS);
|
272 |
|
|
validate_seg_reg(BX_SEG_REG_GS);
|
273 |
|
|
}
|
274 |
|
|
|
275 |
|
|
void parse_selector(Bit16u raw_selector, bx_selector_t *selector)
|
276 |
|
|
{
|
277 |
|
|
selector->value = raw_selector;
|
278 |
|
|
selector->index = raw_selector >> 3;
|
279 |
|
|
selector->ti = (raw_selector >> 2) & 0x01;
|
280 |
|
|
selector->rpl = raw_selector & 0x03;
|
281 |
|
|
}
|
282 |
|
|
|
283 |
|
|
Bit8u get_ar_byte(const bx_descriptor_t *d)
|
284 |
|
|
{
|
285 |
|
|
return (d->type) |
|
286 |
|
|
(d->segment << 4) |
|
287 |
|
|
(d->dpl << 5) |
|
288 |
|
|
(d->p << 7);
|
289 |
|
|
}
|
290 |
|
|
|
291 |
|
|
void set_ar_byte(bx_descriptor_t *d, Bit8u ar_byte)
|
292 |
|
|
{
|
293 |
|
|
d->p = (ar_byte >> 7) & 0x01;
|
294 |
|
|
d->dpl = (ar_byte >> 5) & 0x03;
|
295 |
|
|
d->segment = (ar_byte >> 4) & 0x01;
|
296 |
|
|
d->type = (ar_byte & 0x0f);
|
297 |
|
|
}
|
298 |
|
|
|
299 |
|
|
Bit32u BX_CPP_AttrRegparmN(1)
|
300 |
|
|
BX_CPU_C::get_descriptor_l(const bx_descriptor_t *d)
|
301 |
|
|
{
|
302 |
|
|
Bit32u limit = d->u.segment.limit_scaled;
|
303 |
|
|
if (d->u.segment.g)
|
304 |
|
|
limit >>= 12;
|
305 |
|
|
|
306 |
|
|
Bit32u val = ((d->u.segment.base & 0xffff) << 16) | (limit & 0xffff);
|
307 |
|
|
|
308 |
|
|
if (d->segment || !d->valid) {
|
309 |
|
|
return(val);
|
310 |
|
|
}
|
311 |
|
|
else {
|
312 |
|
|
switch (d->type) {
|
313 |
|
|
case BX_SYS_SEGMENT_LDT:
|
314 |
|
|
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
315 |
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
316 |
|
|
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
317 |
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
318 |
|
|
return(val);
|
319 |
|
|
|
320 |
|
|
default:
|
321 |
|
|
BX_ERROR(("#get_descriptor_l(): type %d not finished", d->type));
|
322 |
|
|
return(0);
|
323 |
|
|
}
|
324 |
|
|
}
|
325 |
|
|
}
|
326 |
|
|
|
327 |
|
|
Bit32u BX_CPP_AttrRegparmN(1)
|
328 |
|
|
BX_CPU_C::get_descriptor_h(const bx_descriptor_t *d)
|
329 |
|
|
{
|
330 |
|
|
Bit32u val;
|
331 |
|
|
|
332 |
|
|
Bit32u limit = d->u.segment.limit_scaled;
|
333 |
|
|
if (d->u.segment.g)
|
334 |
|
|
limit >>= 12;
|
335 |
|
|
|
336 |
|
|
if (d->segment || !d->valid) {
|
337 |
|
|
val = (d->u.segment.base & 0xff000000) |
|
338 |
|
|
((d->u.segment.base >> 16) & 0x000000ff) |
|
339 |
|
|
(d->type << 8) |
|
340 |
|
|
(d->segment << 12) |
|
341 |
|
|
(d->dpl << 13) |
|
342 |
|
|
(d->p << 15) | (limit & 0xf0000) |
|
343 |
|
|
(d->u.segment.avl << 20) |
|
344 |
|
|
#if BX_SUPPORT_X86_64
|
345 |
|
|
(d->u.segment.l << 21) |
|
346 |
|
|
#endif
|
347 |
|
|
(d->u.segment.d_b << 22) |
|
348 |
|
|
(d->u.segment.g << 23);
|
349 |
|
|
return(val);
|
350 |
|
|
}
|
351 |
|
|
else {
|
352 |
|
|
switch (d->type) {
|
353 |
|
|
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
354 |
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
355 |
|
|
case BX_SYS_SEGMENT_LDT:
|
356 |
|
|
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
357 |
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
358 |
|
|
val = ((d->u.segment.base >> 16) & 0xff) |
|
359 |
|
|
(d->type << 8) |
|
360 |
|
|
(d->dpl << 13) |
|
361 |
|
|
(d->p << 15) | (limit & 0xf0000) |
|
362 |
|
|
(d->u.segment.avl << 20) |
|
363 |
|
|
(d->u.segment.d_b << 22) |
|
364 |
|
|
(d->u.segment.g << 23) |
|
365 |
|
|
(d->u.segment.base & 0xff000000);
|
366 |
|
|
return(val);
|
367 |
|
|
|
368 |
|
|
default:
|
369 |
|
|
BX_ERROR(("#get_descriptor_h(): type %d not finished", d->type));
|
370 |
|
|
return(0);
|
371 |
|
|
}
|
372 |
|
|
}
|
373 |
|
|
}
|
374 |
|
|
|
375 |
|
|
bx_bool BX_CPU_C::set_segment_ar_data(bx_segment_reg_t *seg, bx_bool valid,
|
376 |
|
|
Bit16u raw_selector, bx_address base, Bit32u limit_scaled, Bit16u ar_data)
|
377 |
|
|
{
|
378 |
|
|
parse_selector(raw_selector, &seg->selector);
|
379 |
|
|
|
380 |
|
|
bx_descriptor_t *d = &seg->cache;
|
381 |
|
|
|
382 |
|
|
d->p = (ar_data >> 7) & 0x1;
|
383 |
|
|
d->dpl = (ar_data >> 5) & 0x3;
|
384 |
|
|
d->segment = (ar_data >> 4) & 0x1;
|
385 |
|
|
d->type = (ar_data & 0x0f);
|
386 |
|
|
|
387 |
|
|
d->valid = valid;
|
388 |
|
|
|
389 |
|
|
if (d->segment || !valid) { /* data/code segment descriptors */
|
390 |
|
|
d->u.segment.g = (ar_data >> 15) & 0x1;
|
391 |
|
|
d->u.segment.d_b = (ar_data >> 14) & 0x1;
|
392 |
|
|
#if BX_SUPPORT_X86_64
|
393 |
|
|
d->u.segment.l = (ar_data >> 13) & 0x1;
|
394 |
|
|
#endif
|
395 |
|
|
d->u.segment.avl = (ar_data >> 12) & 0x1;
|
396 |
|
|
|
397 |
|
|
d->u.segment.base = base;
|
398 |
|
|
d->u.segment.limit_scaled = limit_scaled;
|
399 |
|
|
}
|
400 |
|
|
else {
|
401 |
|
|
switch(d->type) {
|
402 |
|
|
case BX_SYS_SEGMENT_LDT:
|
403 |
|
|
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
404 |
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
405 |
|
|
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
406 |
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
407 |
|
|
d->u.segment.avl = (ar_data >> 12) & 0x1;
|
408 |
|
|
d->u.segment.d_b = (ar_data >> 14) & 0x1;
|
409 |
|
|
d->u.segment.g = (ar_data >> 15) & 0x1;
|
410 |
|
|
d->u.segment.base = base;
|
411 |
|
|
d->u.segment.limit_scaled = limit_scaled;
|
412 |
|
|
break;
|
413 |
|
|
|
414 |
|
|
default:
|
415 |
|
|
BX_ERROR(("set_segment_ar_data(): case %u unsupported, valid=%d", (unsigned) d->type, d->valid));
|
416 |
|
|
}
|
417 |
|
|
}
|
418 |
|
|
|
419 |
|
|
return d->valid;
|
420 |
|
|
}
|
421 |
|
|
|
422 |
|
|
void parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
|
423 |
|
|
{
|
424 |
|
|
Bit8u AR_byte;
|
425 |
|
|
Bit32u limit;
|
426 |
|
|
|
427 |
|
|
AR_byte = dword2 >> 8;
|
428 |
|
|
temp->p = (AR_byte >> 7) & 0x1;
|
429 |
|
|
temp->dpl = (AR_byte >> 5) & 0x3;
|
430 |
|
|
temp->segment = (AR_byte >> 4) & 0x1;
|
431 |
|
|
temp->type = (AR_byte & 0xf);
|
432 |
|
|
temp->valid = 0; /* start out invalid */
|
433 |
|
|
|
434 |
|
|
if (temp->segment) { /* data/code segment descriptors */
|
435 |
|
|
limit = (dword1 & 0xffff) | (dword2 & 0x000F0000);
|
436 |
|
|
|
437 |
|
|
temp->u.segment.base = (dword1 >> 16) | ((dword2 & 0xFF) << 16);
|
438 |
|
|
temp->u.segment.g = (dword2 & 0x00800000) > 0;
|
439 |
|
|
temp->u.segment.d_b = (dword2 & 0x00400000) > 0;
|
440 |
|
|
#if BX_SUPPORT_X86_64
|
441 |
|
|
temp->u.segment.l = (dword2 & 0x00200000) > 0;
|
442 |
|
|
#endif
|
443 |
|
|
temp->u.segment.avl = (dword2 & 0x00100000) > 0;
|
444 |
|
|
temp->u.segment.base |= (dword2 & 0xFF000000);
|
445 |
|
|
|
446 |
|
|
if (temp->u.segment.g)
|
447 |
|
|
temp->u.segment.limit_scaled = (limit << 12) | 0xfff;
|
448 |
|
|
else
|
449 |
|
|
temp->u.segment.limit_scaled = limit;
|
450 |
|
|
|
451 |
|
|
temp->valid = 1;
|
452 |
|
|
}
|
453 |
|
|
else { // system & gate segment descriptors
|
454 |
|
|
switch (temp->type) {
|
455 |
|
|
case BX_286_CALL_GATE:
|
456 |
|
|
case BX_286_INTERRUPT_GATE:
|
457 |
|
|
case BX_286_TRAP_GATE:
|
458 |
|
|
// param count only used for call gate
|
459 |
|
|
temp->u.gate.param_count = dword2 & 0x1f;
|
460 |
|
|
temp->u.gate.dest_selector = dword1 >> 16;
|
461 |
|
|
temp->u.gate.dest_offset = dword1 & 0xffff;
|
462 |
|
|
temp->valid = 1;
|
463 |
|
|
break;
|
464 |
|
|
|
465 |
|
|
case BX_386_CALL_GATE:
|
466 |
|
|
case BX_386_INTERRUPT_GATE:
|
467 |
|
|
case BX_386_TRAP_GATE:
|
468 |
|
|
// param count only used for call gate
|
469 |
|
|
temp->u.gate.param_count = dword2 & 0x1f;
|
470 |
|
|
temp->u.gate.dest_selector = dword1 >> 16;
|
471 |
|
|
temp->u.gate.dest_offset = (dword2 & 0xffff0000) |
|
472 |
|
|
(dword1 & 0x0000ffff);
|
473 |
|
|
temp->valid = 1;
|
474 |
|
|
break;
|
475 |
|
|
|
476 |
|
|
case BX_TASK_GATE:
|
477 |
|
|
temp->u.taskgate.tss_selector = dword1 >> 16;
|
478 |
|
|
temp->valid = 1;
|
479 |
|
|
break;
|
480 |
|
|
|
481 |
|
|
case BX_SYS_SEGMENT_LDT:
|
482 |
|
|
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
483 |
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
484 |
|
|
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
485 |
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
486 |
|
|
limit = (dword1 & 0xffff) | (dword2 & 0x000F0000);
|
487 |
|
|
temp->u.segment.base = (dword1 >> 16) |
|
488 |
|
|
((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
|
489 |
|
|
temp->u.segment.g = (dword2 & 0x00800000) > 0;
|
490 |
|
|
temp->u.segment.d_b = (dword2 & 0x00400000) > 0;
|
491 |
|
|
temp->u.segment.avl = (dword2 & 0x00100000) > 0;
|
492 |
|
|
if (temp->u.segment.g)
|
493 |
|
|
temp->u.segment.limit_scaled = (limit << 12) | 0xfff;
|
494 |
|
|
else
|
495 |
|
|
temp->u.segment.limit_scaled = limit;
|
496 |
|
|
temp->valid = 1;
|
497 |
|
|
break;
|
498 |
|
|
|
499 |
|
|
default: // reserved
|
500 |
|
|
temp->valid = 0;
|
501 |
|
|
break;
|
502 |
|
|
}
|
503 |
|
|
}
|
504 |
|
|
}
|
505 |
|
|
|
506 |
|
|
void BX_CPP_AttrRegparmN(2)
|
507 |
|
|
BX_CPU_C::touch_segment(bx_selector_t *selector, bx_descriptor_t *descriptor)
|
508 |
|
|
{
|
509 |
|
|
if (! IS_SEGMENT_ACCESSED(descriptor->type)) {
|
510 |
|
|
Bit8u AR_byte = get_ar_byte(descriptor);
|
511 |
|
|
AR_byte |= 1;
|
512 |
|
|
descriptor->type |= 1;
|
513 |
|
|
|
514 |
|
|
if (selector->ti == 0) { /* GDT */
|
515 |
|
|
access_write_linear(BX_CPU_THIS_PTR gdtr.base + selector->index*8 + 5, 1, 0, &AR_byte);
|
516 |
|
|
}
|
517 |
|
|
else { /* LDT */
|
518 |
|
|
access_write_linear(BX_CPU_THIS_PTR ldtr.cache.u.segment.base + selector->index*8 + 5, 1, 0, &AR_byte);
|
519 |
|
|
}
|
520 |
|
|
}
|
521 |
|
|
}
|
522 |
|
|
|
523 |
|
|
void BX_CPP_AttrRegparmN(3)
|
524 |
|
|
BX_CPU_C::load_ss(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl)
|
525 |
|
|
{
|
526 |
|
|
// Add cpl to the selector value.
|
527 |
|
|
selector->value = (BX_SELECTOR_RPL_MASK & selector->value) | cpl;
|
528 |
|
|
|
529 |
|
|
if ((selector->value & BX_SELECTOR_RPL_MASK) != 0)
|
530 |
|
|
touch_segment(selector, descriptor);
|
531 |
|
|
|
532 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = *selector;
|
533 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = *descriptor;
|
534 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = cpl;
|
535 |
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
|
536 |
|
|
|
537 |
|
|
invalidate_stack_cache();
|
538 |
|
|
}
|
539 |
|
|
|
540 |
|
|
void BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
|
541 |
|
|
Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
|
542 |
|
|
{
|
543 |
|
|
Bit32u index = selector->index;
|
544 |
|
|
bx_address offset;
|
545 |
|
|
Bit64u raw_descriptor;
|
546 |
|
|
|
547 |
|
|
if (selector->ti == 0) { /* GDT */
|
548 |
|
|
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
|
549 |
|
|
BX_ERROR(("fetch_raw_descriptor: GDT: index (%x) %x > limit (%x)",
|
550 |
|
|
index*8 + 7, index, BX_CPU_THIS_PTR gdtr.limit));
|
551 |
|
|
exception(exception_no, selector->value & 0xfffc);
|
552 |
|
|
}
|
553 |
|
|
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
554 |
|
|
}
|
555 |
|
|
else { /* LDT */
|
556 |
|
|
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
557 |
|
|
BX_ERROR(("fetch_raw_descriptor: LDTR.valid=0"));
|
558 |
|
|
exception(exception_no, selector->value & 0xfffc);
|
559 |
|
|
}
|
560 |
|
|
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
|
561 |
|
|
BX_ERROR(("fetch_raw_descriptor: LDT: index (%x) %x > limit (%x)",
|
562 |
|
|
index*8 + 7, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
|
563 |
|
|
exception(exception_no, selector->value & 0xfffc);
|
564 |
|
|
}
|
565 |
|
|
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
566 |
|
|
}
|
567 |
|
|
|
568 |
|
|
raw_descriptor = system_read_qword(offset);
|
569 |
|
|
|
570 |
|
|
*dword1 = GET32L(raw_descriptor);
|
571 |
|
|
*dword2 = GET32H(raw_descriptor);
|
572 |
|
|
}
|
573 |
|
|
|
574 |
|
|
bx_bool BX_CPP_AttrRegparmN(3)
|
575 |
|
|
BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2)
|
576 |
|
|
{
|
577 |
|
|
Bit32u index = selector->index;
|
578 |
|
|
bx_address offset;
|
579 |
|
|
Bit64u raw_descriptor;
|
580 |
|
|
|
581 |
|
|
if (selector->ti == 0) { /* GDT */
|
582 |
|
|
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit)
|
583 |
|
|
return 0;
|
584 |
|
|
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
585 |
|
|
}
|
586 |
|
|
else { /* LDT */
|
587 |
|
|
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
588 |
|
|
BX_ERROR(("fetch_raw_descriptor2: LDTR.valid=0"));
|
589 |
|
|
return 0;
|
590 |
|
|
}
|
591 |
|
|
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled)
|
592 |
|
|
return 0;
|
593 |
|
|
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
594 |
|
|
}
|
595 |
|
|
|
596 |
|
|
raw_descriptor = system_read_qword(offset);
|
597 |
|
|
|
598 |
|
|
*dword1 = GET32L(raw_descriptor);
|
599 |
|
|
*dword2 = GET32H(raw_descriptor);
|
600 |
|
|
|
601 |
|
|
return 1;
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
#if BX_SUPPORT_X86_64
|
605 |
|
|
void BX_CPU_C::fetch_raw_descriptor_64(const bx_selector_t *selector,
|
606 |
|
|
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no)
|
607 |
|
|
{
|
608 |
|
|
Bit32u index = selector->index;
|
609 |
|
|
bx_address offset;
|
610 |
|
|
Bit64u raw_descriptor1, raw_descriptor2;
|
611 |
|
|
|
612 |
|
|
if (selector->ti == 0) { /* GDT */
|
613 |
|
|
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
|
614 |
|
|
BX_ERROR(("fetch_raw_descriptor64: GDT: index (%x) %x > limit (%x)",
|
615 |
|
|
index*8 + 15, index, BX_CPU_THIS_PTR gdtr.limit));
|
616 |
|
|
exception(exception_no, selector->value & 0xfffc);
|
617 |
|
|
}
|
618 |
|
|
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
619 |
|
|
}
|
620 |
|
|
else { /* LDT */
|
621 |
|
|
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
622 |
|
|
BX_ERROR(("fetch_raw_descriptor64: LDTR.valid=0"));
|
623 |
|
|
exception(exception_no, selector->value & 0xfffc);
|
624 |
|
|
}
|
625 |
|
|
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
|
626 |
|
|
BX_ERROR(("fetch_raw_descriptor64: LDT: index (%x) %x > limit (%x)",
|
627 |
|
|
index*8 + 15, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
|
628 |
|
|
exception(exception_no, selector->value & 0xfffc);
|
629 |
|
|
}
|
630 |
|
|
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
631 |
|
|
}
|
632 |
|
|
|
633 |
|
|
raw_descriptor1 = system_read_qword(offset);
|
634 |
|
|
raw_descriptor2 = system_read_qword(offset + 8);
|
635 |
|
|
|
636 |
|
|
if (raw_descriptor2 & BX_CONST64(0x00001F0000000000)) {
|
637 |
|
|
BX_ERROR(("fetch_raw_descriptor64: extended attributes DWORD4 TYPE != 0"));
|
638 |
|
|
exception(BX_GP_EXCEPTION, selector->value & 0xfffc);
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
*dword1 = GET32L(raw_descriptor1);
|
642 |
|
|
*dword2 = GET32H(raw_descriptor1);
|
643 |
|
|
*dword3 = GET32L(raw_descriptor2);
|
644 |
|
|
}
|
645 |
|
|
|
646 |
|
|
bx_bool BX_CPU_C::fetch_raw_descriptor2_64(const bx_selector_t *selector,
|
647 |
|
|
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3)
|
648 |
|
|
{
|
649 |
|
|
Bit32u index = selector->index;
|
650 |
|
|
bx_address offset;
|
651 |
|
|
Bit64u raw_descriptor1, raw_descriptor2;
|
652 |
|
|
|
653 |
|
|
if (selector->ti == 0) { /* GDT */
|
654 |
|
|
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
|
655 |
|
|
BX_ERROR(("fetch_raw_descriptor2_64: GDT: index (%x) %x > limit (%x)",
|
656 |
|
|
index*8 + 15, index, BX_CPU_THIS_PTR gdtr.limit));
|
657 |
|
|
return 0;
|
658 |
|
|
}
|
659 |
|
|
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
660 |
|
|
}
|
661 |
|
|
else { /* LDT */
|
662 |
|
|
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
663 |
|
|
BX_ERROR(("fetch_raw_descriptor2_64: LDTR.valid=0"));
|
664 |
|
|
return 0;
|
665 |
|
|
}
|
666 |
|
|
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
|
667 |
|
|
BX_ERROR(("fetch_raw_descriptor2_64: LDT: index (%x) %x > limit (%x)",
|
668 |
|
|
index*8 + 15, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
|
669 |
|
|
return 0;
|
670 |
|
|
}
|
671 |
|
|
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
672 |
|
|
}
|
673 |
|
|
|
674 |
|
|
raw_descriptor1 = system_read_qword(offset);
|
675 |
|
|
raw_descriptor2 = system_read_qword(offset + 8);
|
676 |
|
|
|
677 |
|
|
if (raw_descriptor2 & BX_CONST64(0x00001F0000000000)) {
|
678 |
|
|
BX_ERROR(("fetch_raw_descriptor2_64: extended attributes DWORD4 TYPE != 0"));
|
679 |
|
|
return 0;
|
680 |
|
|
}
|
681 |
|
|
|
682 |
|
|
*dword1 = GET32L(raw_descriptor1);
|
683 |
|
|
*dword2 = GET32H(raw_descriptor1);
|
684 |
|
|
*dword3 = GET32L(raw_descriptor2);
|
685 |
|
|
|
686 |
|
|
return 1;
|
687 |
|
|
}
|
688 |
|
|
#endif
|