Revision 20054ef0
b/target-i386/op_helper.c | ||
---|---|---|
31 | 31 |
#endif /* !defined(CONFIG_USER_ONLY) */ |
32 | 32 |
|
33 | 33 |
//#define DEBUG_PCALL |
34 |
//#define DEBUG_MULDIV |
|
34 | 35 |
|
35 | 36 |
#ifdef DEBUG_PCALL |
36 |
# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
|
|
37 |
# define LOG_PCALL_STATE(env) \
|
|
38 |
log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
|
|
37 |
# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) |
|
38 |
# define LOG_PCALL_STATE(env) \
|
|
39 |
log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP) |
|
39 | 40 |
#else |
40 |
# define LOG_PCALL(...) do { } while (0)
|
|
41 |
# define LOG_PCALL_STATE(env) do { } while (0)
|
|
41 |
# define LOG_PCALL(...) do { } while (0) |
|
42 |
# define LOG_PCALL_STATE(env) do { } while (0) |
|
42 | 43 |
#endif |
43 | 44 |
|
44 | 45 |
/* n must be a constant to be efficient */ |
... | ... | |
75 | 76 |
|
76 | 77 |
static inline void fpop(void) |
77 | 78 |
{ |
78 |
env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
|
|
79 |
env->fptags[env->fpstt] = 1; /* invalidate stack entry */ |
|
79 | 80 |
env->fpstt = (env->fpstt + 1) & 7; |
80 | 81 |
} |
81 | 82 |
|
... | ... | |
124 | 125 |
} |
125 | 126 |
|
126 | 127 |
/* load efer and update the corresponding hflags. XXX: do consistency |
127 |
checks with cpuid bits ? */
|
|
128 |
checks with cpuid bits? */ |
|
128 | 129 |
static inline void cpu_load_efer(CPUX86State *env, uint64_t val) |
129 | 130 |
{ |
130 | 131 |
env->efer = val; |
... | ... | |
138 | 139 |
} |
139 | 140 |
|
140 | 141 |
#if 0 |
141 |
#define raise_exception_err(a, b)\ |
|
142 |
do {\
|
|
143 |
qemu_log("raise_exception line=%d\n", __LINE__);\
|
|
144 |
(raise_exception_err)(a, b);\
|
|
145 |
} while (0) |
|
142 |
#define raise_exception_err(a, b) \
|
|
143 |
do { \
|
|
144 |
qemu_log("raise_exception line=%d\n", __LINE__); \
|
|
145 |
(raise_exception_err)(a, b); \
|
|
146 |
} while (0)
|
|
146 | 147 |
#endif |
147 | 148 |
|
148 | 149 |
static void QEMU_NORETURN raise_exception_err(int exception_index, |
... | ... | |
186 | 187 |
/* modulo 17 table */ |
187 | 188 |
static const uint8_t rclw_table[32] = { |
188 | 189 |
0, 1, 2, 3, 4, 5, 6, 7, |
189 |
8, 9,10,11,12,13,14,15,
|
|
190 |
16, 0, 1, 2, 3, 4, 5, 6, |
|
191 |
7, 8, 9,10,11,12,13,14,
|
|
190 |
8, 9, 10, 11, 12, 13, 14, 15,
|
|
191 |
16, 0, 1, 2, 3, 4, 5, 6,
|
|
192 |
7, 8, 9, 10, 11, 12, 13, 14,
|
|
192 | 193 |
}; |
193 | 194 |
|
194 | 195 |
/* modulo 9 table */ |
... | ... | |
199 | 200 |
6, 7, 8, 0, 1, 2, 3, 4, |
200 | 201 |
}; |
201 | 202 |
|
202 |
#define floatx80_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
|
|
203 |
#define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
|
|
204 |
#define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
|
|
203 |
#define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL)
|
|
204 |
#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
|
|
205 |
#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
|
|
205 | 206 |
|
206 | 207 |
/* broken thread support */ |
207 | 208 |
|
... | ... | |
225 | 226 |
target_ulong helper_read_eflags(void) |
226 | 227 |
{ |
227 | 228 |
uint32_t eflags; |
229 |
|
|
228 | 230 |
eflags = helper_cc_compute_all(CC_OP); |
229 | 231 |
eflags |= (DF & DF_MASK); |
230 | 232 |
eflags |= env->eflags & ~(VM_MASK | RF_MASK); |
... | ... | |
239 | 241 |
int index; |
240 | 242 |
target_ulong ptr; |
241 | 243 |
|
242 |
if (selector & 0x4) |
|
244 |
if (selector & 0x4) {
|
|
243 | 245 |
dt = &env->ldt; |
244 |
else
|
|
246 |
} else {
|
|
245 | 247 |
dt = &env->gdt; |
248 |
} |
|
246 | 249 |
index = selector & ~7; |
247 |
if ((index + 7) > dt->limit) |
|
250 |
if ((index + 7) > dt->limit) {
|
|
248 | 251 |
return -1; |
252 |
} |
|
249 | 253 |
ptr = dt->base + index; |
250 | 254 |
*e1_ptr = ldl_kernel(ptr); |
251 | 255 |
*e2_ptr = ldl_kernel(ptr + 4); |
... | ... | |
255 | 259 |
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) |
256 | 260 |
{ |
257 | 261 |
unsigned int limit; |
262 |
|
|
258 | 263 |
limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
259 |
if (e2 & DESC_G_MASK) |
|
264 |
if (e2 & DESC_G_MASK) {
|
|
260 | 265 |
limit = (limit << 12) | 0xfff; |
266 |
} |
|
261 | 267 |
return limit; |
262 | 268 |
} |
263 | 269 |
|
264 | 270 |
static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) |
265 | 271 |
{ |
266 |
return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
|
|
272 |
return (e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000);
|
|
267 | 273 |
} |
268 | 274 |
|
269 |
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) |
|
275 |
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, |
|
276 |
uint32_t e2) |
|
270 | 277 |
{ |
271 | 278 |
sc->base = get_seg_base(e1, e2); |
272 | 279 |
sc->limit = get_seg_limit(e1, e2); |
... | ... | |
290 | 297 |
{ |
291 | 298 |
int i; |
292 | 299 |
printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); |
293 |
for(i=0;i<env->tr.limit;i++) {
|
|
300 |
for (i = 0; i < env->tr.limit; i++) {
|
|
294 | 301 |
printf("%02x ", env->tr.base[i]); |
295 |
if ((i & 7) == 7) printf("\n"); |
|
302 |
if ((i & 7) == 7) { |
|
303 |
printf("\n"); |
|
304 |
} |
|
296 | 305 |
} |
297 | 306 |
printf("\n"); |
298 | 307 |
} |
299 | 308 |
#endif |
300 | 309 |
|
301 |
if (!(env->tr.flags & DESC_P_MASK)) |
|
310 |
if (!(env->tr.flags & DESC_P_MASK)) {
|
|
302 | 311 |
cpu_abort(env, "invalid tss"); |
312 |
} |
|
303 | 313 |
type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; |
304 |
if ((type & 7) != 1) |
|
314 |
if ((type & 7) != 1) {
|
|
305 | 315 |
cpu_abort(env, "invalid tss type"); |
316 |
} |
|
306 | 317 |
shift = type >> 3; |
307 | 318 |
index = (dpl * 4 + 2) << shift; |
308 |
if (index + (4 << shift) - 1 > env->tr.limit) |
|
319 |
if (index + (4 << shift) - 1 > env->tr.limit) {
|
|
309 | 320 |
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); |
321 |
} |
|
310 | 322 |
if (shift == 0) { |
311 | 323 |
*esp_ptr = lduw_kernel(env->tr.base + index); |
312 | 324 |
*ss_ptr = lduw_kernel(env->tr.base + index + 2); |
... | ... | |
323 | 335 |
int rpl, dpl, cpl; |
324 | 336 |
|
325 | 337 |
if ((selector & 0xfffc) != 0) { |
326 |
if (load_segment(&e1, &e2, selector) != 0) |
|
338 |
if (load_segment(&e1, &e2, selector) != 0) {
|
|
327 | 339 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
328 |
if (!(e2 & DESC_S_MASK)) |
|
340 |
} |
|
341 |
if (!(e2 & DESC_S_MASK)) { |
|
329 | 342 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
343 |
} |
|
330 | 344 |
rpl = selector & 3; |
331 | 345 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
332 | 346 |
cpl = env->hflags & HF_CPL_MASK; |
333 | 347 |
if (seg_reg == R_CS) { |
334 |
if (!(e2 & DESC_CS_MASK)) |
|
348 |
if (!(e2 & DESC_CS_MASK)) {
|
|
335 | 349 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
336 |
/* XXX: is it correct ? */ |
|
337 |
if (dpl != rpl) |
|
350 |
} |
|
351 |
/* XXX: is it correct? */ |
|
352 |
if (dpl != rpl) { |
|
338 | 353 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
339 |
if ((e2 & DESC_C_MASK) && dpl > rpl) |
|
354 |
} |
|
355 |
if ((e2 & DESC_C_MASK) && dpl > rpl) { |
|
340 | 356 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
357 |
} |
|
341 | 358 |
} else if (seg_reg == R_SS) { |
342 | 359 |
/* SS must be writable data */ |
343 |
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) |
|
360 |
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
|
|
344 | 361 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
345 |
if (dpl != cpl || dpl != rpl) |
|
362 |
} |
|
363 |
if (dpl != cpl || dpl != rpl) { |
|
346 | 364 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
365 |
} |
|
347 | 366 |
} else { |
348 | 367 |
/* not readable code */ |
349 |
if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) |
|
368 |
if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) {
|
|
350 | 369 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
370 |
} |
|
351 | 371 |
/* if data or non conforming code, checks the rights */ |
352 | 372 |
if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { |
353 |
if (dpl < cpl || dpl < rpl) |
|
373 |
if (dpl < cpl || dpl < rpl) {
|
|
354 | 374 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
375 |
} |
|
355 | 376 |
} |
356 | 377 |
} |
357 |
if (!(e2 & DESC_P_MASK)) |
|
378 |
if (!(e2 & DESC_P_MASK)) {
|
|
358 | 379 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
380 |
} |
|
359 | 381 |
cpu_x86_load_seg_cache(env, seg_reg, selector, |
360 |
get_seg_base(e1, e2), |
|
361 |
get_seg_limit(e1, e2), |
|
362 |
e2); |
|
382 |
get_seg_base(e1, e2),
|
|
383 |
get_seg_limit(e1, e2),
|
|
384 |
e2);
|
|
363 | 385 |
} else { |
364 |
if (seg_reg == R_SS || seg_reg == R_CS) |
|
386 |
if (seg_reg == R_SS || seg_reg == R_CS) {
|
|
365 | 387 |
raise_exception_err(EXCP0A_TSS, selector & 0xfffc); |
388 |
} |
|
366 | 389 |
} |
367 | 390 |
} |
368 | 391 |
|
... | ... | |
385 | 408 |
target_ulong ptr; |
386 | 409 |
|
387 | 410 |
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
388 |
LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); |
|
411 |
LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, |
|
412 |
source); |
|
389 | 413 |
|
390 | 414 |
/* if task gate, we read the TSS segment and we load it */ |
391 | 415 |
if (type == 5) { |
392 |
if (!(e2 & DESC_P_MASK)) |
|
416 |
if (!(e2 & DESC_P_MASK)) {
|
|
393 | 417 |
raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); |
418 |
} |
|
394 | 419 |
tss_selector = e1 >> 16; |
395 |
if (tss_selector & 4) |
|
420 |
if (tss_selector & 4) {
|
|
396 | 421 |
raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); |
397 |
if (load_segment(&e1, &e2, tss_selector) != 0) |
|
422 |
} |
|
423 |
if (load_segment(&e1, &e2, tss_selector) != 0) { |
|
398 | 424 |
raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); |
399 |
if (e2 & DESC_S_MASK) |
|
425 |
} |
|
426 |
if (e2 & DESC_S_MASK) { |
|
400 | 427 |
raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); |
428 |
} |
|
401 | 429 |
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
402 |
if ((type & 7) != 1) |
|
430 |
if ((type & 7) != 1) {
|
|
403 | 431 |
raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); |
432 |
} |
|
404 | 433 |
} |
405 | 434 |
|
406 |
if (!(e2 & DESC_P_MASK)) |
|
435 |
if (!(e2 & DESC_P_MASK)) {
|
|
407 | 436 |
raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); |
437 |
} |
|
408 | 438 |
|
409 |
if (type & 8) |
|
439 |
if (type & 8) {
|
|
410 | 440 |
tss_limit_max = 103; |
411 |
else
|
|
441 |
} else {
|
|
412 | 442 |
tss_limit_max = 43; |
443 |
} |
|
413 | 444 |
tss_limit = get_seg_limit(e1, e2); |
414 | 445 |
tss_base = get_seg_base(e1, e2); |
415 | 446 |
if ((tss_selector & 4) != 0 || |
416 |
tss_limit < tss_limit_max) |
|
447 |
tss_limit < tss_limit_max) {
|
|
417 | 448 |
raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); |
449 |
} |
|
418 | 450 |
old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; |
419 |
if (old_type & 8) |
|
451 |
if (old_type & 8) {
|
|
420 | 452 |
old_tss_limit_max = 103; |
421 |
else
|
|
453 |
} else {
|
|
422 | 454 |
old_tss_limit_max = 43; |
455 |
} |
|
423 | 456 |
|
424 | 457 |
/* read all the registers from the new TSS */ |
425 | 458 |
if (type & 8) { |
... | ... | |
427 | 460 |
new_cr3 = ldl_kernel(tss_base + 0x1c); |
428 | 461 |
new_eip = ldl_kernel(tss_base + 0x20); |
429 | 462 |
new_eflags = ldl_kernel(tss_base + 0x24); |
430 |
for(i = 0; i < 8; i++)
|
|
463 |
for (i = 0; i < 8; i++) {
|
|
431 | 464 |
new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); |
432 |
for(i = 0; i < 6; i++) |
|
465 |
} |
|
466 |
for (i = 0; i < 6; i++) { |
|
433 | 467 |
new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); |
468 |
} |
|
434 | 469 |
new_ldt = lduw_kernel(tss_base + 0x60); |
435 | 470 |
new_trap = ldl_kernel(tss_base + 0x64); |
436 | 471 |
} else { |
... | ... | |
438 | 473 |
new_cr3 = 0; |
439 | 474 |
new_eip = lduw_kernel(tss_base + 0x0e); |
440 | 475 |
new_eflags = lduw_kernel(tss_base + 0x10); |
441 |
for(i = 0; i < 8; i++)
|
|
476 |
for (i = 0; i < 8; i++) {
|
|
442 | 477 |
new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; |
443 |
for(i = 0; i < 4; i++) |
|
478 |
} |
|
479 |
for (i = 0; i < 4; i++) { |
|
444 | 480 |
new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); |
481 |
} |
|
445 | 482 |
new_ldt = lduw_kernel(tss_base + 0x2a); |
446 | 483 |
new_segs[R_FS] = 0; |
447 | 484 |
new_segs[R_GS] = 0; |
... | ... | |
466 | 503 |
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { |
467 | 504 |
target_ulong ptr; |
468 | 505 |
uint32_t e2; |
506 |
|
|
469 | 507 |
ptr = env->gdt.base + (env->tr.selector & ~7); |
470 | 508 |
e2 = ldl_kernel(ptr + 4); |
471 | 509 |
e2 &= ~DESC_TSS_BUSY_MASK; |
472 | 510 |
stl_kernel(ptr + 4, e2); |
473 | 511 |
} |
474 | 512 |
old_eflags = compute_eflags(); |
475 |
if (source == SWITCH_TSS_IRET) |
|
513 |
if (source == SWITCH_TSS_IRET) {
|
|
476 | 514 |
old_eflags &= ~NT_MASK; |
515 |
} |
|
477 | 516 |
|
478 | 517 |
/* save the current state in the old TSS */ |
479 | 518 |
if (type & 8) { |
... | ... | |
488 | 527 |
stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); |
489 | 528 |
stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); |
490 | 529 |
stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); |
491 |
for(i = 0; i < 6; i++)
|
|
530 |
for (i = 0; i < 6; i++) {
|
|
492 | 531 |
stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); |
532 |
} |
|
493 | 533 |
} else { |
494 | 534 |
/* 16 bit */ |
495 | 535 |
stw_kernel(env->tr.base + 0x0e, next_eip); |
... | ... | |
502 | 542 |
stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); |
503 | 543 |
stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); |
504 | 544 |
stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); |
505 |
for(i = 0; i < 4; i++)
|
|
545 |
for (i = 0; i < 4; i++) {
|
|
506 | 546 |
stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); |
547 |
} |
|
507 | 548 |
} |
508 | 549 |
|
509 | 550 |
/* now if an exception occurs, it will occurs in the next task |
... | ... | |
518 | 559 |
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { |
519 | 560 |
target_ulong ptr; |
520 | 561 |
uint32_t e2; |
562 |
|
|
521 | 563 |
ptr = env->gdt.base + (tss_selector & ~7); |
522 | 564 |
e2 = ldl_kernel(ptr + 4); |
523 | 565 |
e2 |= DESC_TSS_BUSY_MASK; |
... | ... | |
542 | 584 |
env->eip = new_eip; |
543 | 585 |
eflags_mask = TF_MASK | AC_MASK | ID_MASK | |
544 | 586 |
IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; |
545 |
if (!(type & 8)) |
|
587 |
if (!(type & 8)) {
|
|
546 | 588 |
eflags_mask &= 0xffff; |
589 |
} |
|
547 | 590 |
load_eflags(new_eflags, eflags_mask); |
548 |
/* XXX: what to do in 16 bit case ? */
|
|
591 |
/* XXX: what to do in 16 bit case? */ |
|
549 | 592 |
EAX = new_regs[0]; |
550 | 593 |
ECX = new_regs[1]; |
551 | 594 |
EDX = new_regs[2]; |
... | ... | |
555 | 598 |
ESI = new_regs[6]; |
556 | 599 |
EDI = new_regs[7]; |
557 | 600 |
if (new_eflags & VM_MASK) { |
558 |
for(i = 0; i < 6; i++)
|
|
601 |
for (i = 0; i < 6; i++) {
|
|
559 | 602 |
load_seg_vm(i, new_segs[i]); |
603 |
} |
|
560 | 604 |
/* in vm86, CPL is always 3 */ |
561 | 605 |
cpu_x86_set_cpl(env, 3); |
562 | 606 |
} else { |
563 | 607 |
/* CPL is set the RPL of CS */ |
564 | 608 |
cpu_x86_set_cpl(env, new_segs[R_CS] & 3); |
565 | 609 |
/* first just selectors as the rest may trigger exceptions */ |
566 |
for(i = 0; i < 6; i++)
|
|
610 |
for (i = 0; i < 6; i++) {
|
|
567 | 611 |
cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); |
612 |
} |
|
568 | 613 |
} |
569 | 614 |
|
570 | 615 |
env->ldt.selector = new_ldt & ~4; |
... | ... | |
573 | 618 |
env->ldt.flags = 0; |
574 | 619 |
|
575 | 620 |
/* load the LDT */ |
576 |
if (new_ldt & 4) |
|
621 |
if (new_ldt & 4) {
|
|
577 | 622 |
raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); |
623 |
} |
|
578 | 624 |
|
579 | 625 |
if ((new_ldt & 0xfffc) != 0) { |
580 | 626 |
dt = &env->gdt; |
581 | 627 |
index = new_ldt & ~7; |
582 |
if ((index + 7) > dt->limit) |
|
628 |
if ((index + 7) > dt->limit) {
|
|
583 | 629 |
raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); |
630 |
} |
|
584 | 631 |
ptr = dt->base + index; |
585 | 632 |
e1 = ldl_kernel(ptr); |
586 | 633 |
e2 = ldl_kernel(ptr + 4); |
587 |
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) |
|
634 |
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) {
|
|
588 | 635 |
raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); |
589 |
if (!(e2 & DESC_P_MASK)) |
|
636 |
} |
|
637 |
if (!(e2 & DESC_P_MASK)) { |
|
590 | 638 |
raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); |
639 |
} |
|
591 | 640 |
load_seg_cache_raw_dt(&env->ldt, e1, e2); |
592 | 641 |
} |
593 | 642 |
|
... | ... | |
603 | 652 |
|
604 | 653 |
/* check that EIP is in the CS segment limits */ |
605 | 654 |
if (new_eip > env->segs[R_CS].limit) { |
606 |
/* XXX: different exception if CALL ? */
|
|
655 |
/* XXX: different exception if CALL? */ |
|
607 | 656 |
raise_exception_err(EXCP0D_GPF, 0); |
608 | 657 |
} |
609 | 658 |
|
... | ... | |
611 | 660 |
/* reset local breakpoints */ |
612 | 661 |
if (env->dr[7] & 0x55) { |
613 | 662 |
for (i = 0; i < 4; i++) { |
614 |
if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) |
|
663 |
if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) {
|
|
615 | 664 |
hw_breakpoint_remove(env, i); |
665 |
} |
|
616 | 666 |
} |
617 | 667 |
env->dr[7] &= ~0x55; |
618 | 668 |
} |
... | ... | |
627 | 677 |
/* TSS must be a valid 32 bit one */ |
628 | 678 |
if (!(env->tr.flags & DESC_P_MASK) || |
629 | 679 |
((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || |
630 |
env->tr.limit < 103) |
|
680 |
env->tr.limit < 103) {
|
|
631 | 681 |
goto fail; |
682 |
} |
|
632 | 683 |
io_offset = lduw_kernel(env->tr.base + 0x66); |
633 | 684 |
io_offset += (addr >> 3); |
634 | 685 |
/* Note: the check needs two bytes */ |
635 |
if ((io_offset + 1) > env->tr.limit) |
|
686 |
if ((io_offset + 1) > env->tr.limit) {
|
|
636 | 687 |
goto fail; |
688 |
} |
|
637 | 689 |
val = lduw_kernel(env->tr.base + io_offset); |
638 | 690 |
val >>= (addr & 7); |
639 | 691 |
mask = (1 << size) - 1; |
... | ... | |
691 | 743 |
|
692 | 744 |
static inline unsigned int get_sp_mask(unsigned int e2) |
693 | 745 |
{ |
694 |
if (e2 & DESC_B_MASK) |
|
746 |
if (e2 & DESC_B_MASK) {
|
|
695 | 747 |
return 0xffffffff; |
696 |
else
|
|
748 |
} else {
|
|
697 | 749 |
return 0xffff; |
750 |
} |
|
698 | 751 |
} |
699 | 752 |
|
700 |
static int exeption_has_error_code(int intno) |
|
753 |
static int exception_has_error_code(int intno)
|
|
701 | 754 |
{ |
702 |
switch(intno) {
|
|
703 |
case 8:
|
|
704 |
case 10:
|
|
705 |
case 11:
|
|
706 |
case 12:
|
|
707 |
case 13:
|
|
708 |
case 14:
|
|
709 |
case 17:
|
|
710 |
return 1;
|
|
711 |
}
|
|
712 |
return 0;
|
|
755 |
switch (intno) {
|
|
756 |
case 8: |
|
757 |
case 10: |
|
758 |
case 11: |
|
759 |
case 12: |
|
760 |
case 13: |
|
761 |
case 14: |
|
762 |
case 17: |
|
763 |
return 1; |
|
764 |
} |
|
765 |
return 0;
|
|
713 | 766 |
} |
714 | 767 |
|
715 | 768 |
#ifdef TARGET_X86_64 |
716 |
#define SET_ESP(val, sp_mask)\ |
|
717 |
do {\ |
|
718 |
if ((sp_mask) == 0xffff)\ |
|
719 |
ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ |
|
720 |
else if ((sp_mask) == 0xffffffffLL)\ |
|
721 |
ESP = (uint32_t)(val);\ |
|
722 |
else\ |
|
723 |
ESP = (val);\ |
|
724 |
} while (0) |
|
769 |
#define SET_ESP(val, sp_mask) \ |
|
770 |
do { \ |
|
771 |
if ((sp_mask) == 0xffff) { \ |
|
772 |
ESP = (ESP & ~0xffff) | ((val) & 0xffff); \ |
|
773 |
} else if ((sp_mask) == 0xffffffffLL) { \ |
|
774 |
ESP = (uint32_t)(val); \ |
|
775 |
} else { \ |
|
776 |
ESP = (val); \ |
|
777 |
} \ |
|
778 |
} while (0) |
|
725 | 779 |
#else |
726 |
#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)) |
|
780 |
#define SET_ESP(val, sp_mask) \ |
|
781 |
do { \ |
|
782 |
ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)); \ |
|
783 |
} while (0) |
|
727 | 784 |
#endif |
728 | 785 |
|
729 | 786 |
/* in 64-bit machines, this can overflow. So this segment addition macro |
... | ... | |
731 | 788 |
#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask)))) |
732 | 789 |
|
733 | 790 |
/* XXX: add a is_user flag to have proper security support */ |
734 |
#define PUSHW(ssp, sp, sp_mask, val)\ |
|
735 |
{\
|
|
736 |
sp -= 2;\
|
|
737 |
stw_kernel((ssp) + (sp & (sp_mask)), (val));\
|
|
738 |
} |
|
791 |
#define PUSHW(ssp, sp, sp_mask, val) \
|
|
792 |
{ \
|
|
793 |
sp -= 2; \
|
|
794 |
stw_kernel((ssp) + (sp & (sp_mask)), (val)); \
|
|
795 |
}
|
|
739 | 796 |
|
740 |
#define PUSHL(ssp, sp, sp_mask, val)\ |
|
741 |
{\
|
|
742 |
sp -= 4;\
|
|
743 |
stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
|
|
744 |
} |
|
797 |
#define PUSHL(ssp, sp, sp_mask, val) \
|
|
798 |
{ \
|
|
799 |
sp -= 4; \
|
|
800 |
stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val)); \
|
|
801 |
}
|
|
745 | 802 |
|
746 |
#define POPW(ssp, sp, sp_mask, val)\ |
|
747 |
{\
|
|
748 |
val = lduw_kernel((ssp) + (sp & (sp_mask)));\
|
|
749 |
sp += 2;\
|
|
750 |
} |
|
803 |
#define POPW(ssp, sp, sp_mask, val) \
|
|
804 |
{ \
|
|
805 |
val = lduw_kernel((ssp) + (sp & (sp_mask))); \
|
|
806 |
sp += 2; \
|
|
807 |
}
|
|
751 | 808 |
|
752 |
#define POPL(ssp, sp, sp_mask, val)\ |
|
753 |
{\
|
|
754 |
val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
|
|
755 |
sp += 4;\
|
|
756 |
} |
|
809 |
#define POPL(ssp, sp, sp_mask, val) \
|
|
810 |
{ \
|
|
811 |
val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask)); \
|
|
812 |
sp += 4; \
|
|
813 |
}
|
|
757 | 814 |
|
758 | 815 |
/* protected mode interrupt */ |
759 | 816 |
static void do_interrupt_protected(int intno, int is_int, int error_code, |
... | ... | |
767 | 824 |
uint32_t old_eip, sp_mask; |
768 | 825 |
|
769 | 826 |
has_error_code = 0; |
770 |
if (!is_int && !is_hw) |
|
771 |
has_error_code = exeption_has_error_code(intno); |
|
772 |
if (is_int) |
|
827 |
if (!is_int && !is_hw) { |
|
828 |
has_error_code = exception_has_error_code(intno); |
|
829 |
} |
|
830 |
if (is_int) { |
|
773 | 831 |
old_eip = next_eip; |
774 |
else
|
|
832 |
} else {
|
|
775 | 833 |
old_eip = env->eip; |
834 |
} |
|
776 | 835 |
|
777 | 836 |
dt = &env->idt; |
778 |
if (intno * 8 + 7 > dt->limit) |
|
837 |
if (intno * 8 + 7 > dt->limit) {
|
|
779 | 838 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
839 |
} |
|
780 | 840 |
ptr = dt->base + intno * 8; |
781 | 841 |
e1 = ldl_kernel(ptr); |
782 | 842 |
e2 = ldl_kernel(ptr + 4); |
783 | 843 |
/* check gate type */ |
784 | 844 |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
785 |
switch(type) { |
|
845 |
switch (type) {
|
|
786 | 846 |
case 5: /* task gate */ |
787 | 847 |
/* must do that check here to return the correct error code */ |
788 |
if (!(e2 & DESC_P_MASK)) |
|
848 |
if (!(e2 & DESC_P_MASK)) {
|
|
789 | 849 |
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); |
850 |
} |
|
790 | 851 |
switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); |
791 | 852 |
if (has_error_code) { |
792 | 853 |
int type; |
793 | 854 |
uint32_t mask; |
855 |
|
|
794 | 856 |
/* push the error code */ |
795 | 857 |
type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; |
796 | 858 |
shift = type >> 3; |
797 |
if (env->segs[R_SS].flags & DESC_B_MASK) |
|
859 |
if (env->segs[R_SS].flags & DESC_B_MASK) {
|
|
798 | 860 |
mask = 0xffffffff; |
799 |
else
|
|
861 |
} else {
|
|
800 | 862 |
mask = 0xffff; |
863 |
} |
|
801 | 864 |
esp = (ESP - (2 << shift)) & mask; |
802 | 865 |
ssp = env->segs[R_SS].base + esp; |
803 |
if (shift) |
|
866 |
if (shift) {
|
|
804 | 867 |
stl_kernel(ssp, error_code); |
805 |
else
|
|
868 |
} else {
|
|
806 | 869 |
stw_kernel(ssp, error_code); |
870 |
} |
|
807 | 871 |
SET_ESP(esp, mask); |
808 | 872 |
} |
809 | 873 |
return; |
... | ... | |
819 | 883 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
820 | 884 |
cpl = env->hflags & HF_CPL_MASK; |
821 | 885 |
/* check privilege if software int */ |
822 |
if (is_int && dpl < cpl) |
|
886 |
if (is_int && dpl < cpl) {
|
|
823 | 887 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
888 |
} |
|
824 | 889 |
/* check valid bit */ |
825 |
if (!(e2 & DESC_P_MASK)) |
|
890 |
if (!(e2 & DESC_P_MASK)) {
|
|
826 | 891 |
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); |
892 |
} |
|
827 | 893 |
selector = e1 >> 16; |
828 | 894 |
offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); |
829 |
if ((selector & 0xfffc) == 0) |
|
895 |
if ((selector & 0xfffc) == 0) {
|
|
830 | 896 |
raise_exception_err(EXCP0D_GPF, 0); |
831 |
|
|
832 |
if (load_segment(&e1, &e2, selector) != 0) |
|
897 |
} |
|
898 |
if (load_segment(&e1, &e2, selector) != 0) {
|
|
833 | 899 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
834 |
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) |
|
900 |
} |
|
901 |
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) { |
|
835 | 902 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
903 |
} |
|
836 | 904 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
837 |
if (dpl > cpl) |
|
905 |
if (dpl > cpl) {
|
|
838 | 906 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
839 |
if (!(e2 & DESC_P_MASK)) |
|
907 |
} |
|
908 |
if (!(e2 & DESC_P_MASK)) { |
|
840 | 909 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
910 |
} |
|
841 | 911 |
if (!(e2 & DESC_C_MASK) && dpl < cpl) { |
842 | 912 |
/* to inner privilege */ |
843 | 913 |
get_ss_esp_from_tss(&ss, &esp, dpl); |
844 |
if ((ss & 0xfffc) == 0) |
|
914 |
if ((ss & 0xfffc) == 0) {
|
|
845 | 915 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
846 |
if ((ss & 3) != dpl) |
|
916 |
} |
|
917 |
if ((ss & 3) != dpl) { |
|
847 | 918 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
848 |
if (load_segment(&ss_e1, &ss_e2, ss) != 0) |
|
919 |
} |
|
920 |
if (load_segment(&ss_e1, &ss_e2, ss) != 0) { |
|
849 | 921 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
922 |
} |
|
850 | 923 |
ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; |
851 |
if (ss_dpl != dpl) |
|
924 |
if (ss_dpl != dpl) {
|
|
852 | 925 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
926 |
} |
|
853 | 927 |
if (!(ss_e2 & DESC_S_MASK) || |
854 | 928 |
(ss_e2 & DESC_CS_MASK) || |
855 |
!(ss_e2 & DESC_W_MASK)) |
|
929 |
!(ss_e2 & DESC_W_MASK)) {
|
|
856 | 930 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
857 |
if (!(ss_e2 & DESC_P_MASK)) |
|
931 |
} |
|
932 |
if (!(ss_e2 & DESC_P_MASK)) { |
|
858 | 933 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
934 |
} |
|
859 | 935 |
new_stack = 1; |
860 | 936 |
sp_mask = get_sp_mask(ss_e2); |
861 | 937 |
ssp = get_seg_base(ss_e1, ss_e2); |
862 | 938 |
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
863 | 939 |
/* to same privilege */ |
864 |
if (env->eflags & VM_MASK) |
|
940 |
if (env->eflags & VM_MASK) {
|
|
865 | 941 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
942 |
} |
|
866 | 943 |
new_stack = 0; |
867 | 944 |
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
868 | 945 |
ssp = env->segs[R_SS].base; |
... | ... | |
881 | 958 |
#if 0 |
882 | 959 |
/* XXX: check that enough room is available */ |
883 | 960 |
push_size = 6 + (new_stack << 2) + (has_error_code << 1); |
884 |
if (env->eflags & VM_MASK) |
|
961 |
if (env->eflags & VM_MASK) {
|
|
885 | 962 |
push_size += 8; |
963 |
} |
|
886 | 964 |
push_size <<= shift; |
887 | 965 |
#endif |
888 | 966 |
if (shift == 1) { |
... | ... | |
951 | 1029 |
|
952 | 1030 |
#ifdef TARGET_X86_64 |
953 | 1031 |
|
954 |
#define PUSHQ(sp, val)\ |
|
955 |
{\
|
|
956 |
sp -= 8;\
|
|
957 |
stq_kernel(sp, (val));\
|
|
958 |
} |
|
1032 |
#define PUSHQ(sp, val) \
|
|
1033 |
{ \
|
|
1034 |
sp -= 8; \
|
|
1035 |
stq_kernel(sp, (val)); \
|
|
1036 |
}
|
|
959 | 1037 |
|
960 |
#define POPQ(sp, val)\ |
|
961 |
{\
|
|
962 |
val = ldq_kernel(sp);\
|
|
963 |
sp += 8;\
|
|
964 |
} |
|
1038 |
#define POPQ(sp, val) \
|
|
1039 |
{ \
|
|
1040 |
val = ldq_kernel(sp); \
|
|
1041 |
sp += 8; \
|
|
1042 |
}
|
|
965 | 1043 |
|
966 | 1044 |
static inline target_ulong get_rsp_from_tss(int level) |
967 | 1045 |
{ |
... | ... | |
972 | 1050 |
env->tr.base, env->tr.limit); |
973 | 1051 |
#endif |
974 | 1052 |
|
975 |
if (!(env->tr.flags & DESC_P_MASK)) |
|
1053 |
if (!(env->tr.flags & DESC_P_MASK)) {
|
|
976 | 1054 |
cpu_abort(env, "invalid tss"); |
1055 |
} |
|
977 | 1056 |
index = 8 * level + 4; |
978 |
if ((index + 7) > env->tr.limit) |
|
1057 |
if ((index + 7) > env->tr.limit) {
|
|
979 | 1058 |
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); |
1059 |
} |
|
980 | 1060 |
return ldq_kernel(env->tr.base + index); |
981 | 1061 |
} |
982 | 1062 |
|
... | ... | |
992 | 1072 |
target_ulong old_eip, esp, offset; |
993 | 1073 |
|
994 | 1074 |
has_error_code = 0; |
995 |
if (!is_int && !is_hw) |
|
996 |
has_error_code = exeption_has_error_code(intno); |
|
997 |
if (is_int) |
|
1075 |
if (!is_int && !is_hw) { |
|
1076 |
has_error_code = exception_has_error_code(intno); |
|
1077 |
} |
|
1078 |
if (is_int) { |
|
998 | 1079 |
old_eip = next_eip; |
999 |
else
|
|
1080 |
} else {
|
|
1000 | 1081 |
old_eip = env->eip; |
1082 |
} |
|
1001 | 1083 |
|
1002 | 1084 |
dt = &env->idt; |
1003 |
if (intno * 16 + 15 > dt->limit) |
|
1085 |
if (intno * 16 + 15 > dt->limit) {
|
|
1004 | 1086 |
raise_exception_err(EXCP0D_GPF, intno * 16 + 2); |
1087 |
} |
|
1005 | 1088 |
ptr = dt->base + intno * 16; |
1006 | 1089 |
e1 = ldl_kernel(ptr); |
1007 | 1090 |
e2 = ldl_kernel(ptr + 4); |
1008 | 1091 |
e3 = ldl_kernel(ptr + 8); |
1009 | 1092 |
/* check gate type */ |
1010 | 1093 |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
1011 |
switch(type) { |
|
1094 |
switch (type) {
|
|
1012 | 1095 |
case 14: /* 386 interrupt gate */ |
1013 | 1096 |
case 15: /* 386 trap gate */ |
1014 | 1097 |
break; |
... | ... | |
1019 | 1102 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
1020 | 1103 |
cpl = env->hflags & HF_CPL_MASK; |
1021 | 1104 |
/* check privilege if software int */ |
1022 |
if (is_int && dpl < cpl) |
|
1105 |
if (is_int && dpl < cpl) {
|
|
1023 | 1106 |
raise_exception_err(EXCP0D_GPF, intno * 16 + 2); |
1107 |
} |
|
1024 | 1108 |
/* check valid bit */ |
1025 |
if (!(e2 & DESC_P_MASK)) |
|
1109 |
if (!(e2 & DESC_P_MASK)) {
|
|
1026 | 1110 |
raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); |
1111 |
} |
|
1027 | 1112 |
selector = e1 >> 16; |
1028 | 1113 |
offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); |
1029 | 1114 |
ist = e2 & 7; |
1030 |
if ((selector & 0xfffc) == 0) |
|
1115 |
if ((selector & 0xfffc) == 0) {
|
|
1031 | 1116 |
raise_exception_err(EXCP0D_GPF, 0); |
1117 |
} |
|
1032 | 1118 |
|
1033 |
if (load_segment(&e1, &e2, selector) != 0) |
|
1119 |
if (load_segment(&e1, &e2, selector) != 0) {
|
|
1034 | 1120 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1035 |
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) |
|
1121 |
} |
|
1122 |
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) { |
|
1036 | 1123 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1124 |
} |
|
1037 | 1125 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
1038 |
if (dpl > cpl) |
|
1126 |
if (dpl > cpl) {
|
|
1039 | 1127 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1040 |
if (!(e2 & DESC_P_MASK)) |
|
1128 |
} |
|
1129 |
if (!(e2 & DESC_P_MASK)) { |
|
1041 | 1130 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
1042 |
if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) |
|
1131 |
} |
|
1132 |
if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) { |
|
1043 | 1133 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1134 |
} |
|
1044 | 1135 |
if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { |
1045 | 1136 |
/* to inner privilege */ |
1046 |
if (ist != 0) |
|
1137 |
if (ist != 0) {
|
|
1047 | 1138 |
esp = get_rsp_from_tss(ist + 3); |
1048 |
else
|
|
1139 |
} else {
|
|
1049 | 1140 |
esp = get_rsp_from_tss(dpl); |
1141 |
} |
|
1050 | 1142 |
esp &= ~0xfLL; /* align stack */ |
1051 | 1143 |
ss = 0; |
1052 | 1144 |
new_stack = 1; |
1053 | 1145 |
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
1054 | 1146 |
/* to same privilege */ |
1055 |
if (env->eflags & VM_MASK) |
|
1147 |
if (env->eflags & VM_MASK) {
|
|
1056 | 1148 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1149 |
} |
|
1057 | 1150 |
new_stack = 0; |
1058 |
if (ist != 0) |
|
1151 |
if (ist != 0) {
|
|
1059 | 1152 |
esp = get_rsp_from_tss(ist + 3); |
1060 |
else
|
|
1153 |
} else {
|
|
1061 | 1154 |
esp = ESP; |
1155 |
} |
|
1062 | 1156 |
esp &= ~0xfLL; /* align stack */ |
1063 | 1157 |
dpl = cpl; |
1064 | 1158 |
} else { |
... | ... | |
1128 | 1222 |
0, 0xffffffff, |
1129 | 1223 |
DESC_G_MASK | DESC_P_MASK | |
1130 | 1224 |
DESC_S_MASK | |
1131 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); |
|
1225 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | |
|
1226 |
DESC_L_MASK); |
|
1132 | 1227 |
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, |
1133 | 1228 |
0, 0xffffffff, |
1134 | 1229 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
... | ... | |
1136 | 1231 |
DESC_W_MASK | DESC_A_MASK); |
1137 | 1232 |
env->eflags &= ~env->fmask; |
1138 | 1233 |
load_eflags(env->eflags, 0); |
1139 |
if (code64) |
|
1234 |
if (code64) {
|
|
1140 | 1235 |
env->eip = env->lstar; |
1141 |
else
|
|
1236 |
} else {
|
|
1142 | 1237 |
env->eip = env->cstar; |
1238 |
} |
|
1143 | 1239 |
} else { |
1144 | 1240 |
ECX = (uint32_t)(env->eip + next_eip_addend); |
1145 | 1241 |
|
... | ... | |
1227 | 1323 |
uint32_t offset, esp; |
1228 | 1324 |
uint32_t old_cs, old_eip; |
1229 | 1325 |
|
1230 |
/* real mode (simpler !) */
|
|
1326 |
/* real mode (simpler!) */ |
|
1231 | 1327 |
dt = &env->idt; |
1232 |
if (intno * 4 + 3 > dt->limit) |
|
1328 |
if (intno * 4 + 3 > dt->limit) {
|
|
1233 | 1329 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
1330 |
} |
|
1234 | 1331 |
ptr = dt->base + intno * 4; |
1235 | 1332 |
offset = lduw_kernel(ptr); |
1236 | 1333 |
selector = lduw_kernel(ptr + 2); |
1237 | 1334 |
esp = ESP; |
1238 | 1335 |
ssp = env->segs[R_SS].base; |
1239 |
if (is_int) |
|
1336 |
if (is_int) {
|
|
1240 | 1337 |
old_eip = next_eip; |
1241 |
else
|
|
1338 |
} else {
|
|
1242 | 1339 |
old_eip = env->eip; |
1340 |
} |
|
1243 | 1341 |
old_cs = env->segs[R_CS].selector; |
1244 |
/* XXX: use SS segment size ? */
|
|
1342 |
/* XXX: use SS segment size? */ |
|
1245 | 1343 |
PUSHW(ssp, esp, 0xffff, compute_eflags()); |
1246 | 1344 |
PUSHW(ssp, esp, 0xffff, old_cs); |
1247 | 1345 |
PUSHW(ssp, esp, 0xffff, old_eip); |
... | ... | |
1276 | 1374 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
1277 | 1375 |
cpl = env->hflags & HF_CPL_MASK; |
1278 | 1376 |
/* check privilege if software int */ |
1279 |
if (is_int && dpl < cpl) |
|
1377 |
if (is_int && dpl < cpl) {
|
|
1280 | 1378 |
raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); |
1379 |
} |
|
1281 | 1380 |
|
1282 | 1381 |
/* Since we emulate only user space, we cannot do more than |
1283 | 1382 |
exiting the emulation with the suitable exception and error |
1284 | 1383 |
code */ |
1285 |
if (is_int) |
|
1384 |
if (is_int) {
|
|
1286 | 1385 |
EIP = next_eip; |
1386 |
} |
|
1287 | 1387 |
} |
1288 | 1388 |
|
1289 | 1389 |
#else |
1290 | 1390 |
|
1291 | 1391 |
static void handle_even_inj(int intno, int is_int, int error_code, |
1292 |
int is_hw, int rm)
|
|
1392 |
int is_hw, int rm)
|
|
1293 | 1393 |
{ |
1294 |
uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); |
|
1394 |
uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, |
|
1395 |
control.event_inj)); |
|
1396 |
|
|
1295 | 1397 |
if (!(event_inj & SVM_EVTINJ_VALID)) { |
1296 |
int type; |
|
1297 |
if (is_int) |
|
1298 |
type = SVM_EVTINJ_TYPE_SOFT; |
|
1299 |
else |
|
1300 |
type = SVM_EVTINJ_TYPE_EXEPT; |
|
1301 |
event_inj = intno | type | SVM_EVTINJ_VALID; |
|
1302 |
if (!rm && exeption_has_error_code(intno)) { |
|
1303 |
event_inj |= SVM_EVTINJ_VALID_ERR; |
|
1304 |
stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code); |
|
1305 |
} |
|
1306 |
stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj); |
|
1398 |
int type; |
|
1399 |
|
|
1400 |
if (is_int) { |
|
1401 |
type = SVM_EVTINJ_TYPE_SOFT; |
|
1402 |
} else { |
|
1403 |
type = SVM_EVTINJ_TYPE_EXEPT; |
|
1404 |
} |
|
1405 |
event_inj = intno | type | SVM_EVTINJ_VALID; |
|
1406 |
if (!rm && exception_has_error_code(intno)) { |
|
1407 |
event_inj |= SVM_EVTINJ_VALID_ERR; |
|
1408 |
stl_phys(env->vm_vmcb + offsetof(struct vmcb, |
|
1409 |
control.event_inj_err), |
|
1410 |
error_code); |
|
1411 |
} |
|
1412 |
stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), |
|
1413 |
event_inj); |
|
1307 | 1414 |
} |
1308 | 1415 |
} |
1309 | 1416 |
#endif |
... | ... | |
1319 | 1426 |
if (qemu_loglevel_mask(CPU_LOG_INT)) { |
1320 | 1427 |
if ((env->cr[0] & CR0_PE_MASK)) { |
1321 | 1428 |
static int count; |
1322 |
qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, |
|
1323 |
count, intno, error_code, is_int, |
|
1324 |
env->hflags & HF_CPL_MASK, |
|
1325 |
env->segs[R_CS].selector, EIP, |
|
1326 |
(int)env->segs[R_CS].base + EIP, |
|
1327 |
env->segs[R_SS].selector, ESP); |
|
1429 |
|
|
1430 |
qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx |
|
1431 |
" pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, |
|
1432 |
count, intno, error_code, is_int, |
|
1433 |
env->hflags & HF_CPL_MASK, |
|
1434 |
env->segs[R_CS].selector, EIP, |
|
1435 |
(int)env->segs[R_CS].base + EIP, |
|
1436 |
env->segs[R_SS].selector, ESP); |
|
1328 | 1437 |
if (intno == 0x0e) { |
1329 | 1438 |
qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]); |
1330 | 1439 |
} else { |
... | ... | |
1336 | 1445 |
{ |
1337 | 1446 |
int i; |
1338 | 1447 |
target_ulong ptr; |
1448 |
|
|
1339 | 1449 |
qemu_log(" code="); |
1340 | 1450 |
ptr = env->segs[R_CS].base + env->eip; |
1341 |
for(i = 0; i < 16; i++) { |
|
1451 |
for (i = 0; i < 16; i++) {
|
|
1342 | 1452 |
qemu_log(" %02x", ldub(ptr + i)); |
1343 | 1453 |
} |
1344 | 1454 |
qemu_log("\n"); |
... | ... | |
1349 | 1459 |
} |
1350 | 1460 |
if (env->cr[0] & CR0_PE_MASK) { |
1351 | 1461 |
#if !defined(CONFIG_USER_ONLY) |
1352 |
if (env->hflags & HF_SVMI_MASK) |
|
1462 |
if (env->hflags & HF_SVMI_MASK) {
|
|
1353 | 1463 |
handle_even_inj(intno, is_int, error_code, is_hw, 0); |
1464 |
} |
|
1354 | 1465 |
#endif |
1355 | 1466 |
#ifdef TARGET_X86_64 |
1356 | 1467 |
if (env->hflags & HF_LMA_MASK) { |
... | ... | |
1362 | 1473 |
} |
1363 | 1474 |
} else { |
1364 | 1475 |
#if !defined(CONFIG_USER_ONLY) |
1365 |
if (env->hflags & HF_SVMI_MASK) |
|
1476 |
if (env->hflags & HF_SVMI_MASK) {
|
|
1366 | 1477 |
handle_even_inj(intno, is_int, error_code, is_hw, 1); |
1478 |
} |
|
1367 | 1479 |
#endif |
1368 | 1480 |
do_interrupt_real(intno, is_int, error_code, next_eip); |
1369 | 1481 |
} |
1370 | 1482 |
|
1371 | 1483 |
#if !defined(CONFIG_USER_ONLY) |
1372 | 1484 |
if (env->hflags & HF_SVMI_MASK) { |
1373 |
uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); |
|
1374 |
stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID); |
|
1485 |
uint32_t event_inj = ldl_phys(env->vm_vmcb + |
|
1486 |
offsetof(struct vmcb, |
|
1487 |
control.event_inj)); |
|
1488 |
|
|
1489 |
stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), |
|
1490 |
event_inj & ~SVM_EVTINJ_VALID); |
|
1375 | 1491 |
} |
1376 | 1492 |
#endif |
1377 | 1493 |
} |
... | ... | |
1437 | 1553 |
|
1438 | 1554 |
#if !defined(CONFIG_USER_ONLY) |
1439 | 1555 |
if (env->old_exception == EXCP08_DBLE) { |
1440 |
if (env->hflags & HF_SVMI_MASK) |
|
1556 |
if (env->hflags & HF_SVMI_MASK) {
|
|
1441 | 1557 |
helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */ |
1558 |
} |
|
1442 | 1559 |
|
1443 | 1560 |
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); |
1444 | 1561 |
|
... | ... | |
1455 | 1572 |
} |
1456 | 1573 |
|
1457 | 1574 |
if (second_contributory || (intno == EXCP0E_PAGE) || |
1458 |
(intno == EXCP08_DBLE)) |
|
1575 |
(intno == EXCP08_DBLE)) {
|
|
1459 | 1576 |
env->old_exception = intno; |
1577 |
} |
|
1460 | 1578 |
|
1461 | 1579 |
return intno; |
1462 | 1580 |
} |
... | ... | |
1471 | 1589 |
int next_eip_addend) |
1472 | 1590 |
{ |
1473 | 1591 |
if (!is_int) { |
1474 |
helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); |
|
1592 |
helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, |
|
1593 |
error_code); |
|
1475 | 1594 |
intno = check_exception(intno, &error_code); |
1476 | 1595 |
} else { |
1477 | 1596 |
helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0); |
... | ... | |
1548 | 1667 |
sm_state = env->smbase + 0x8000; |
1549 | 1668 |
|
1550 | 1669 |
#ifdef TARGET_X86_64 |
1551 |
for(i = 0; i < 6; i++) { |
|
1670 |
for (i = 0; i < 6; i++) {
|
|
1552 | 1671 |
dt = &env->segs[i]; |
1553 | 1672 |
offset = 0x7e00 + i * 16; |
1554 | 1673 |
stw_phys(sm_state + offset, dt->selector); |
... | ... | |
1583 | 1702 |
stq_phys(sm_state + 0x7fd0, EBP); |
1584 | 1703 |
stq_phys(sm_state + 0x7fc8, ESI); |
1585 | 1704 |
stq_phys(sm_state + 0x7fc0, EDI); |
1586 |
for(i = 8; i < 16; i++)
|
|
1705 |
for (i = 8; i < 16; i++) {
|
|
1587 | 1706 |
stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); |
1707 |
} |
|
1588 | 1708 |
stq_phys(sm_state + 0x7f78, env->eip); |
1589 | 1709 |
stl_phys(sm_state + 0x7f70, compute_eflags()); |
1590 | 1710 |
stl_phys(sm_state + 0x7f68, env->dr[6]); |
... | ... | |
1628 | 1748 |
stl_phys(sm_state + 0x7f58, env->idt.base); |
1629 | 1749 |
stl_phys(sm_state + 0x7f54, env->idt.limit); |
1630 | 1750 |
|
1631 |
for(i = 0; i < 6; i++) { |
|
1751 |
for (i = 0; i < 6; i++) {
|
|
1632 | 1752 |
dt = &env->segs[i]; |
1633 |
if (i < 3) |
|
1753 |
if (i < 3) {
|
|
1634 | 1754 |
offset = 0x7f84 + i * 12; |
1635 |
else
|
|
1755 |
} else {
|
|
1636 | 1756 |
offset = 0x7f2c + (i - 3) * 12; |
1757 |
} |
|
1637 | 1758 |
stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector); |
1638 | 1759 |
stl_phys(sm_state + offset + 8, dt->base); |
1639 | 1760 |
stl_phys(sm_state + offset + 4, dt->limit); |
... | ... | |
1660 | 1781 |
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); |
1661 | 1782 |
|
1662 | 1783 |
cpu_x86_update_cr0(env, |
1663 |
env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); |
|
1784 |
env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | |
|
1785 |
CR0_PG_MASK)); |
|
1664 | 1786 |
cpu_x86_update_cr4(env, 0); |
1665 | 1787 |
env->dr[7] = 0x00000400; |
1666 | 1788 |
CC_OP = CC_OP_EFLAGS; |
... | ... | |
1677 | 1799 |
#ifdef TARGET_X86_64 |
1678 | 1800 |
cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0)); |
1679 | 1801 |
|
1680 |
for(i = 0; i < 6; i++) { |
|
1802 |
for (i = 0; i < 6; i++) {
|
|
1681 | 1803 |
offset = 0x7e00 + i * 16; |
1682 | 1804 |
cpu_x86_load_seg_cache(env, i, |
1683 | 1805 |
lduw_phys(sm_state + offset), |
1684 | 1806 |
ldq_phys(sm_state + offset + 8), |
1685 | 1807 |
ldl_phys(sm_state + offset + 4), |
1686 |
(lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8); |
|
1808 |
(lduw_phys(sm_state + offset + 2) & |
|
1809 |
0xf0ff) << 8); |
|
1687 | 1810 |
} |
1688 | 1811 |
|
1689 | 1812 |
env->gdt.base = ldq_phys(sm_state + 0x7e68); |
... | ... | |
1710 | 1833 |
EBP = ldq_phys(sm_state + 0x7fd0); |
1711 | 1834 |
ESI = ldq_phys(sm_state + 0x7fc8); |
1712 | 1835 |
EDI = ldq_phys(sm_state + 0x7fc0); |
1713 |
for(i = 8; i < 16; i++)
|
|
1836 |
for (i = 8; i < 16; i++) {
|
|
1714 | 1837 |
env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); |
1838 |
} |
|
1715 | 1839 |
env->eip = ldq_phys(sm_state + 0x7f78); |
1716 | 1840 |
load_eflags(ldl_phys(sm_state + 0x7f70), |
1717 | 1841 |
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); |
... | ... | |
1759 | 1883 |
env->idt.base = ldl_phys(sm_state + 0x7f58); |
1760 | 1884 |
env->idt.limit = ldl_phys(sm_state + 0x7f54); |
1761 | 1885 |
|
1762 |
for(i = 0; i < 6; i++) { |
|
1763 |
if (i < 3) |
|
1886 |
for (i = 0; i < 6; i++) {
|
|
1887 |
if (i < 3) {
|
|
1764 | 1888 |
offset = 0x7f84 + i * 12; |
1765 |
else
|
|
1889 |
} else {
|
|
1766 | 1890 |
offset = 0x7f2c + (i - 3) * 12; |
1891 |
} |
|
1767 | 1892 |
cpu_x86_load_seg_cache(env, i, |
1768 | 1893 |
ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, |
1769 | 1894 |
ldl_phys(sm_state + offset + 8), |
... | ... | |
1800 | 1925 |
raise_exception(EXCP00_DIVZ); |
1801 | 1926 |
} |
1802 | 1927 |
q = (num / den); |
1803 |
if (q > 0xff) |
|
1928 |
if (q > 0xff) {
|
|
1804 | 1929 |
raise_exception(EXCP00_DIVZ); |
1930 |
} |
|
1805 | 1931 |
q &= 0xff; |
1806 | 1932 |
r = (num % den) & 0xff; |
1807 | 1933 |
EAX = (EAX & ~0xffff) | (r << 8) | q; |
... | ... | |
1817 | 1943 |
raise_exception(EXCP00_DIVZ); |
1818 | 1944 |
} |
1819 | 1945 |
q = (num / den); |
1820 |
if (q != (int8_t)q) |
|
1946 |
if (q != (int8_t)q) {
|
|
1821 | 1947 |
raise_exception(EXCP00_DIVZ); |
1948 |
} |
|
1822 | 1949 |
q &= 0xff; |
1823 | 1950 |
r = (num % den) & 0xff; |
1824 | 1951 |
EAX = (EAX & ~0xffff) | (r << 8) | q; |
... | ... | |
1834 | 1961 |
raise_exception(EXCP00_DIVZ); |
1835 | 1962 |
} |
1836 | 1963 |
q = (num / den); |
1837 |
if (q > 0xffff) |
|
1964 |
if (q > 0xffff) {
|
|
1838 | 1965 |
raise_exception(EXCP00_DIVZ); |
1966 |
} |
|
1839 | 1967 |
q &= 0xffff; |
1840 | 1968 |
r = (num % den) & 0xffff; |
1841 | 1969 |
EAX = (EAX & ~0xffff) | q; |
... | ... | |
1852 | 1980 |
raise_exception(EXCP00_DIVZ); |
1853 | 1981 |
} |
1854 | 1982 |
q = (num / den); |
1855 |
if (q != (int16_t)q) |
|
1983 |
if (q != (int16_t)q) {
|
|
1856 | 1984 |
raise_exception(EXCP00_DIVZ); |
1985 |
} |
|
1857 | 1986 |
q &= 0xffff; |
1858 | 1987 |
r = (num % den) & 0xffff; |
1859 | 1988 |
EAX = (EAX & ~0xffff) | q; |
... | ... | |
1872 | 2001 |
} |
1873 | 2002 |
q = (num / den); |
1874 | 2003 |
r = (num % den); |
1875 |
if (q > 0xffffffff) |
|
2004 |
if (q > 0xffffffff) {
|
|
1876 | 2005 |
raise_exception(EXCP00_DIVZ); |
2006 |
} |
|
1877 | 2007 |
EAX = (uint32_t)q; |
1878 | 2008 |
EDX = (uint32_t)r; |
1879 | 2009 |
} |
... | ... | |
1890 | 2020 |
} |
1891 | 2021 |
q = (num / den); |
1892 | 2022 |
r = (num % den); |
1893 |
if (q != (int32_t)q) |
|
2023 |
if (q != (int32_t)q) {
|
|
1894 | 2024 |
raise_exception(EXCP00_DIVZ); |
2025 |
} |
|
1895 | 2026 |
EAX = (uint32_t)q; |
1896 | 2027 |
EDX = (uint32_t)r; |
1897 | 2028 |
} |
... | ... | |
1902 | 2033 |
void helper_aam(int base) |
1903 | 2034 |
{ |
1904 | 2035 |
int al, ah; |
2036 |
|
|
1905 | 2037 |
al = EAX & 0xff; |
1906 | 2038 |
ah = al / base; |
1907 | 2039 |
al = al % base; |
... | ... | |
1912 | 2044 |
void helper_aad(int base) |
1913 | 2045 |
{ |
1914 | 2046 |
int al, ah; |
2047 |
|
|
1915 | 2048 |
al = EAX & 0xff; |
1916 | 2049 |
ah = (EAX >> 8) & 0xff; |
1917 | 2050 |
al = ((ah * base) + al) & 0xff; |
... | ... | |
1931 | 2064 |
ah = (EAX >> 8) & 0xff; |
1932 | 2065 |
|
1933 | 2066 |
icarry = (al > 0xf9); |
1934 |
if (((al & 0x0f) > 9 ) || af) {
|
|
2067 |
if (((al & 0x0f) > 9) || af) { |
|
1935 | 2068 |
al = (al + 6) & 0x0f; |
1936 | 2069 |
ah = (ah + 1 + icarry) & 0xff; |
1937 | 2070 |
eflags |= CC_C | CC_A; |
... | ... | |
1955 | 2088 |
ah = (EAX >> 8) & 0xff; |
1956 | 2089 |
|
1957 | 2090 |
icarry = (al < 6); |
1958 |
if (((al & 0x0f) > 9 ) || af) {
|
|
2091 |
if (((al & 0x0f) > 9) || af) { |
|
1959 | 2092 |
al = (al - 6) & 0x0f; |
1960 | 2093 |
ah = (ah - 1 - icarry) & 0xff; |
1961 | 2094 |
eflags |= CC_C | CC_A; |
... | ... | |
1978 | 2111 |
old_al = al = EAX & 0xff; |
1979 | 2112 |
|
1980 | 2113 |
eflags = 0; |
1981 |
if (((al & 0x0f) > 9 ) || af) {
|
|
2114 |
if (((al & 0x0f) > 9) || af) { |
|
1982 | 2115 |
al = (al + 6) & 0xff; |
1983 | 2116 |
eflags |= CC_A; |
1984 | 2117 |
} |
... | ... | |
2006 | 2139 |
|
2007 | 2140 |
eflags = 0; |
2008 | 2141 |
al1 = al; |
2009 |
if (((al & 0x0f) > 9 ) || af) {
|
|
2142 |
if (((al & 0x0f) > 9) || af) { |
|
2010 | 2143 |
eflags |= CC_A; |
2011 |
if (al < 6 || cf) |
|
2144 |
if (al < 6 || cf) {
|
|
2012 | 2145 |
eflags |= CC_C; |
2146 |
} |
|
2013 | 2147 |
al = (al - 6) & 0xff; |
2014 | 2148 |
} |
2015 | 2149 |
if ((al1 > 0x99) || cf) { |
... | ... | |
2027 | 2161 |
void helper_into(int next_eip_addend) |
2028 | 2162 |
{ |
2029 | 2163 |
int eflags; |
2164 |
|
|
2030 | 2165 |
eflags = helper_cc_compute_all(CC_OP); |
2031 | 2166 |
if (eflags & CC_O) { |
2032 | 2167 |
raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend); |
... | ... | |
2045 | 2180 |
eflags |= CC_Z; |
2046 | 2181 |
} else { |
2047 | 2182 |
/* always do the store */ |
2048 |
stq(a0, d);
|
|
2183 |
stq(a0, d); |
|
2049 | 2184 |
EDX = (uint32_t)(d >> 32); |
2050 | 2185 |
EAX = (uint32_t)d; |
2051 | 2186 |
eflags &= ~CC_Z; |
... | ... | |
2059 | 2194 |
uint64_t d0, d1; |
2060 | 2195 |
int eflags; |
2061 | 2196 |
|
2062 |
if ((a0 & 0xf) != 0) |
|
2197 |
if ((a0 & 0xf) != 0) {
|
|
2063 | 2198 |
raise_exception(EXCP0D_GPF); |
2199 |
} |
|
2064 | 2200 |
eflags = helper_cc_compute_all(CC_OP); |
2065 | 2201 |
d0 = ldq(a0); |
2066 | 2202 |
d1 = ldq(a0 + 8); |
... | ... | |
2070 | 2206 |
eflags |= CC_Z; |
2071 | 2207 |
} else { |
2072 | 2208 |
/* always do the store */ |
2073 |
stq(a0, d0);
|
|
2074 |
stq(a0 + 8, d1);
|
|
2209 |
stq(a0, d0); |
|
2210 |
stq(a0 + 8, d1); |
|
2075 | 2211 |
EDX = d1; |
2076 | 2212 |
EAX = d0; |
2077 | 2213 |
eflags &= ~CC_Z; |
... | ... | |
2138 | 2274 |
void helper_enter64_level(int level, int data64, target_ulong t1) |
2139 | 2275 |
{ |
2140 | 2276 |
target_ulong esp, ebp; |
2277 |
|
|
2141 | 2278 |
ebp = EBP; |
2142 | 2279 |
esp = ESP; |
2143 | 2280 |
|
... | ... | |
2178 | 2315 |
env->ldt.base = 0; |
2179 | 2316 |
env->ldt.limit = 0; |
2180 | 2317 |
} else { |
2181 |
if (selector & 0x4) |
|
2318 |
if (selector & 0x4) {
|
|
2182 | 2319 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2320 |
} |
|
2183 | 2321 |
dt = &env->gdt; |
2184 | 2322 |
index = selector & ~7; |
2185 | 2323 |
#ifdef TARGET_X86_64 |
2186 |
if (env->hflags & HF_LMA_MASK) |
|
2324 |
if (env->hflags & HF_LMA_MASK) {
|
|
2187 | 2325 |
entry_limit = 15; |
2188 |
else |
|
2326 |
} else
|
|
2189 | 2327 |
#endif |
2328 |
{ |
|
2190 | 2329 |
entry_limit = 7; |
2191 |
if ((index + entry_limit) > dt->limit) |
|
2330 |
} |
|
2331 |
if ((index + entry_limit) > dt->limit) { |
|
2192 | 2332 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2333 |
} |
|
2193 | 2334 |
ptr = dt->base + index; |
2194 | 2335 |
e1 = ldl_kernel(ptr); |
2195 | 2336 |
e2 = ldl_kernel(ptr + 4); |
2196 |
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) |
|
2337 |
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) {
|
|
2197 | 2338 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2198 |
if (!(e2 & DESC_P_MASK)) |
|
2339 |
} |
|
2340 |
if (!(e2 & DESC_P_MASK)) { |
|
2199 | 2341 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
2342 |
} |
|
2200 | 2343 |
#ifdef TARGET_X86_64 |
2201 | 2344 |
if (env->hflags & HF_LMA_MASK) { |
2202 | 2345 |
uint32_t e3; |
2346 |
|
|
2203 | 2347 |
e3 = ldl_kernel(ptr + 8); |
2204 | 2348 |
load_seg_cache_raw_dt(&env->ldt, e1, e2); |
2205 | 2349 |
env->ldt.base |= (target_ulong)e3 << 32; |
... | ... | |
2226 | 2370 |
env->tr.limit = 0; |
2227 | 2371 |
env->tr.flags = 0; |
2228 | 2372 |
} else { |
2229 |
if (selector & 0x4) |
|
2373 |
if (selector & 0x4) {
|
|
2230 | 2374 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2375 |
} |
|
2231 | 2376 |
dt = &env->gdt; |
2232 | 2377 |
index = selector & ~7; |
2233 | 2378 |
#ifdef TARGET_X86_64 |
2234 |
if (env->hflags & HF_LMA_MASK) |
|
2379 |
if (env->hflags & HF_LMA_MASK) {
|
|
2235 | 2380 |
entry_limit = 15; |
2236 |
else |
|
2381 |
} else
|
|
2237 | 2382 |
#endif |
2383 |
{ |
|
2238 | 2384 |
entry_limit = 7; |
2239 |
if ((index + entry_limit) > dt->limit) |
|
2385 |
} |
|
2386 |
if ((index + entry_limit) > dt->limit) { |
|
2240 | 2387 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2388 |
} |
|
2241 | 2389 |
ptr = dt->base + index; |
2242 | 2390 |
e1 = ldl_kernel(ptr); |
2243 | 2391 |
e2 = ldl_kernel(ptr + 4); |
2244 | 2392 |
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
2245 | 2393 |
if ((e2 & DESC_S_MASK) || |
2246 |
(type != 1 && type != 9)) |
|
2394 |
(type != 1 && type != 9)) {
|
|
2247 | 2395 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2248 |
if (!(e2 & DESC_P_MASK)) |
|
2396 |
} |
|
2397 |
if (!(e2 & DESC_P_MASK)) { |
|
2249 | 2398 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
2399 |
} |
|
2250 | 2400 |
#ifdef TARGET_X86_64 |
2251 | 2401 |
if (env->hflags & HF_LMA_MASK) { |
2252 | 2402 |
uint32_t e3, e4; |
2403 |
|
|
2253 | 2404 |
e3 = ldl_kernel(ptr + 8); |
2254 | 2405 |
e4 = ldl_kernel(ptr + 12); |
2255 |
if ((e4 >> DESC_TYPE_SHIFT) & 0xf) |
|
2406 |
if ((e4 >> DESC_TYPE_SHIFT) & 0xf) {
|
|
2256 | 2407 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
2408 |
} |
|
2257 | 2409 |
load_seg_cache_raw_dt(&env->tr, e1, e2); |
2258 | 2410 |
env->tr.base |= (target_ulong)e3 << 32; |
2259 | 2411 |
} else |
... | ... | |
2284 | 2436 |
#ifdef TARGET_X86_64 |
2285 | 2437 |
&& (!(env->hflags & HF_CS64_MASK) || cpl == 3) |
2286 | 2438 |
#endif |
2287 |
) |
|
2439 |
) {
|
|
2288 | 2440 |
raise_exception_err(EXCP0D_GPF, 0); |
2441 |
} |
|
2289 | 2442 |
cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); |
2290 | 2443 |
} else { |
2291 | 2444 |
|
2292 |
if (selector & 0x4) |
|
2445 |
if (selector & 0x4) {
|
|
2293 | 2446 |
dt = &env->ldt; |
2294 |
else |
|
2447 |
} else { |
Also available in: Unified diff