157 |
break; |
break; |
158 |
} |
} |
159 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
160 |
cpl = env->segs[R_CS] & 3; |
cpl = env->segs[R_CS].selector & 3; |
161 |
/* check privledge if software int */ |
/* check privledge if software int */ |
162 |
if (is_int && dpl < cpl) |
if (is_int && dpl < cpl) |
163 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
176 |
void raise_interrupt(int intno, int is_int, int error_code, |
void raise_interrupt(int intno, int is_int, int error_code, |
177 |
unsigned int next_eip) |
unsigned int next_eip) |
178 |
{ |
{ |
179 |
SegmentDescriptorTable *dt; |
SegmentCache *dt; |
180 |
uint8_t *ptr; |
uint8_t *ptr; |
181 |
int dpl, cpl; |
int dpl, cpl; |
182 |
uint32_t e2; |
uint32_t e2; |
331 |
} |
} |
332 |
} |
} |
333 |
|
|
334 |
|
static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) |
335 |
|
{ |
336 |
|
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
337 |
|
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
338 |
|
if (e2 & (1 << 23)) |
339 |
|
sc->limit = (sc->limit << 12) | 0xfff; |
340 |
|
sc->seg_32bit = (e2 >> 22) & 1; |
341 |
|
} |
342 |
|
|
343 |
|
void helper_lldt_T0(void) |
344 |
|
{ |
345 |
|
int selector; |
346 |
|
SegmentCache *dt; |
347 |
|
uint32_t e1, e2; |
348 |
|
int index; |
349 |
|
uint8_t *ptr; |
350 |
|
|
351 |
|
selector = T0 & 0xffff; |
352 |
|
if ((selector & 0xfffc) == 0) { |
353 |
|
/* XXX: NULL selector case: invalid LDT */ |
354 |
|
env->ldt.base = NULL; |
355 |
|
env->ldt.limit = 0; |
356 |
|
} else { |
357 |
|
if (selector & 0x4) |
358 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
359 |
|
dt = &env->gdt; |
360 |
|
index = selector & ~7; |
361 |
|
if ((index + 7) > dt->limit) |
362 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
363 |
|
ptr = dt->base + index; |
364 |
|
e1 = ldl(ptr); |
365 |
|
e2 = ldl(ptr + 4); |
366 |
|
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) |
367 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
368 |
|
if (!(e2 & DESC_P_MASK)) |
369 |
|
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
370 |
|
load_seg_cache(&env->ldt, e1, e2); |
371 |
|
} |
372 |
|
env->ldt.selector = selector; |
373 |
|
} |
374 |
|
|
375 |
|
void helper_ltr_T0(void) |
376 |
|
{ |
377 |
|
int selector; |
378 |
|
SegmentCache *dt; |
379 |
|
uint32_t e1, e2; |
380 |
|
int index, type; |
381 |
|
uint8_t *ptr; |
382 |
|
|
383 |
|
selector = T0 & 0xffff; |
384 |
|
if ((selector & 0xfffc) == 0) { |
385 |
|
/* XXX: NULL selector case: invalid LDT */ |
386 |
|
env->tr.base = NULL; |
387 |
|
env->tr.limit = 0; |
388 |
|
} else { |
389 |
|
if (selector & 0x4) |
390 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
391 |
|
dt = &env->gdt; |
392 |
|
index = selector & ~7; |
393 |
|
if ((index + 7) > dt->limit) |
394 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
395 |
|
ptr = dt->base + index; |
396 |
|
e1 = ldl(ptr); |
397 |
|
e2 = ldl(ptr + 4); |
398 |
|
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
399 |
|
if ((e2 & DESC_S_MASK) || |
400 |
|
(type != 2 && type != 9)) |
401 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
402 |
|
if (!(e2 & DESC_P_MASK)) |
403 |
|
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
404 |
|
load_seg_cache(&env->tr, e1, e2); |
405 |
|
e2 |= 0x00000200; /* set the busy bit */ |
406 |
|
stl(ptr + 4, e2); |
407 |
|
} |
408 |
|
env->tr.selector = selector; |
409 |
|
} |
410 |
|
|
411 |
/* only works if protected mode and not VM86 */ |
/* only works if protected mode and not VM86 */ |
412 |
void load_seg(int seg_reg, int selector, unsigned cur_eip) |
void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
413 |
{ |
{ |
414 |
SegmentCache *sc; |
SegmentCache *sc; |
415 |
SegmentDescriptorTable *dt; |
SegmentCache *dt; |
416 |
int index; |
int index; |
417 |
uint32_t e1, e2; |
uint32_t e1, e2; |
418 |
uint8_t *ptr; |
uint8_t *ptr; |
419 |
|
|
420 |
sc = &env->seg_cache[seg_reg]; |
sc = &env->segs[seg_reg]; |
421 |
if ((selector & 0xfffc) == 0) { |
if ((selector & 0xfffc) == 0) { |
422 |
/* null selector case */ |
/* null selector case */ |
423 |
if (seg_reg == R_SS) { |
if (seg_reg == R_SS) { |
424 |
EIP = cur_eip; |
EIP = cur_eip; |
425 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, 0); |
426 |
} else { |
} else { |
427 |
/* XXX: each access should trigger an exception */ |
/* XXX: each access should trigger an exception */ |
428 |
sc->base = NULL; |
sc->base = NULL; |
467 |
else |
else |
468 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
469 |
} |
} |
470 |
|
load_seg_cache(sc, e1, e2); |
|
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
|
|
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
|
|
if (e2 & (1 << 23)) |
|
|
sc->limit = (sc->limit << 12) | 0xfff; |
|
|
sc->seg_32bit = (e2 >> 22) & 1; |
|
471 |
#if 0 |
#if 0 |
472 |
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", |
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", |
473 |
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); |
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); |
474 |
#endif |
#endif |
475 |
} |
} |
476 |
env->segs[seg_reg] = selector; |
sc->selector = selector; |
477 |
|
} |
478 |
|
|
479 |
|
/* protected mode jump */ |
480 |
|
void jmp_seg(int selector, unsigned int new_eip) |
481 |
|
{ |
482 |
|
SegmentCache sc1; |
483 |
|
SegmentCache *dt; |
484 |
|
int index; |
485 |
|
uint32_t e1, e2, cpl, dpl, rpl; |
486 |
|
uint8_t *ptr; |
487 |
|
|
488 |
|
if ((selector & 0xfffc) == 0) { |
489 |
|
raise_exception_err(EXCP0D_GPF, 0); |
490 |
|
} |
491 |
|
|
492 |
|
if (selector & 0x4) |
493 |
|
dt = &env->ldt; |
494 |
|
else |
495 |
|
dt = &env->gdt; |
496 |
|
index = selector & ~7; |
497 |
|
if ((index + 7) > dt->limit) |
498 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
499 |
|
ptr = dt->base + index; |
500 |
|
e1 = ldl(ptr); |
501 |
|
e2 = ldl(ptr + 4); |
502 |
|
cpl = env->segs[R_CS].selector & 3; |
503 |
|
if (e2 & DESC_S_MASK) { |
504 |
|
if (!(e2 & DESC_CS_MASK)) |
505 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
506 |
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
507 |
|
if (e2 & DESC_CS_MASK) { |
508 |
|
/* conforming code segment */ |
509 |
|
if (dpl > cpl) |
510 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
511 |
|
} else { |
512 |
|
/* non conforming code segment */ |
513 |
|
rpl = selector & 3; |
514 |
|
if (rpl > cpl) |
515 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
516 |
|
if (dpl != cpl) |
517 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
518 |
|
} |
519 |
|
if (!(e2 & DESC_P_MASK)) |
520 |
|
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
521 |
|
load_seg_cache(&sc1, e1, e2); |
522 |
|
if (new_eip > sc1.limit) |
523 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
524 |
|
env->segs[R_CS] = sc1; |
525 |
|
env->segs[R_CS].selector = (selector & 0xfffc) | cpl; |
526 |
|
EIP = new_eip; |
527 |
|
} else { |
528 |
|
cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", |
529 |
|
selector, new_eip); |
530 |
|
} |
531 |
|
} |
532 |
|
|
533 |
|
/* XXX: do more */ |
534 |
|
void helper_movl_crN_T0(int reg) |
535 |
|
{ |
536 |
|
switch(reg) { |
537 |
|
case 0: |
538 |
|
default: |
539 |
|
env->cr[0] = reg; |
540 |
|
break; |
541 |
|
case 2: |
542 |
|
env->cr[2] = reg; |
543 |
|
break; |
544 |
|
case 3: |
545 |
|
env->cr[3] = reg; |
546 |
|
break; |
547 |
|
case 4: |
548 |
|
env->cr[4] = reg; |
549 |
|
break; |
550 |
|
} |
551 |
|
} |
552 |
|
|
553 |
|
/* XXX: do more */ |
554 |
|
void helper_movl_drN_T0(int reg) |
555 |
|
{ |
556 |
|
env->dr[reg] = T0; |
557 |
} |
} |
558 |
|
|
559 |
/* rdtsc */ |
/* rdtsc */ |
577 |
void helper_lsl(void) |
void helper_lsl(void) |
578 |
{ |
{ |
579 |
unsigned int selector, limit; |
unsigned int selector, limit; |
580 |
SegmentDescriptorTable *dt; |
SegmentCache *dt; |
581 |
int index; |
int index; |
582 |
uint32_t e1, e2; |
uint32_t e1, e2; |
583 |
uint8_t *ptr; |
uint8_t *ptr; |
604 |
void helper_lar(void) |
void helper_lar(void) |
605 |
{ |
{ |
606 |
unsigned int selector; |
unsigned int selector; |
607 |
SegmentDescriptorTable *dt; |
SegmentCache *dt; |
608 |
int index; |
int index; |
609 |
uint32_t e2; |
uint32_t e2; |
610 |
uint8_t *ptr; |
uint8_t *ptr; |