Fixed LDT 16-bit limit, must support all 32-bit values.

This commit is contained in:
Stanislav Shwartsman 2006-08-22 19:06:03 +00:00
parent 9ec4f3e60e
commit 54fb3b769a
3 changed files with 81 additions and 95 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: descriptor.h,v 1.14 2006-06-12 16:58:27 sshwarts Exp $
// $Id: descriptor.h,v 1.15 2006-08-22 19:06:03 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -156,7 +156,7 @@ union {
} tss;
struct {
bx_address base; /* 286=24 386+ =32/64 bit LDT base */
Bit16u limit; /* 286+ =16 bit LDT limit */
Bit32u limit; /* 286+ =16 bit LDT limit */
} ldt;
} u;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: protect_ctrl.cc,v 1.48 2006-06-12 16:58:27 sshwarts Exp $
// $Id: protect_ctrl.cc,v 1.49 2006-08-22 19:06:03 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -278,7 +278,7 @@ void BX_CPU_C::SLDT_Ew(bxInstruction_c *i)
BX_INFO(("SLDT: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i);
}
else {
Bit16u val16 = BX_CPU_THIS_PTR ldtr.selector.value;
if (i->modC0()) {
BX_WRITE_16BIT_REG(i->rm(), val16);
@ -286,7 +286,6 @@ void BX_CPU_C::SLDT_Ew(bxInstruction_c *i)
else {
write_virtual_word(i->seg(), RMAddr(i), &val16);
}
}
}
#endif
@ -297,7 +296,7 @@ void BX_CPU_C::STR_Ew(bxInstruction_c *i)
BX_INFO(("STR: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i);
}
else {
Bit16u val16 = BX_CPU_THIS_PTR tr.selector.value;
if (i->modC0()) {
BX_WRITE_16BIT_REG(i->rm(), val16);
@ -305,25 +304,27 @@ void BX_CPU_C::STR_Ew(bxInstruction_c *i)
else {
write_virtual_word(i->seg(), RMAddr(i), &val16);
}
}
}
#if BX_CPU_LEVEL >= 2
void BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
{
if (real_mode() || v8086_mode()) {
BX_INFO(("LLDT: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i);
}
invalidate_prefetch_q();
/* protected mode */
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit16u raw_selector;
Bit32u dword1, dword2;
#if BX_SUPPORT_X86_64
Bit32u dword3;
#endif
if (real_mode() || v8086_mode()) {
BX_INFO(("LTR: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i);
}
invalidate_prefetch_q();
/* #GP(0) if the current privilege level is not 0 */
if (CPL != 0) {
@ -354,19 +355,21 @@ void BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
}
if ((selector.index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
BX_PANIC(("LLDT: GDT: index > limit"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
return;
}
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8, 4, 0,
BX_READ, &dword1);
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0,
BX_READ, &dword2);
/* fetch 2 dwords of descriptor; call handles out of limits checks */
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &descriptor);
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
// set upper 32 bits of tss base
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 8, 4, 0, BX_READ, &dword3);
descriptor.u.ldt.base |= ((Bit64u)dword3 << 32);
BX_INFO(("64 bit LDT base = 0x%08x%08x",
(Bit32u)(descriptor.u.ldt.base >> 32),
(Bit32u) descriptor.u.ldt.base));
}
#endif
/* if selector doesn't point to an LDT descriptor #GP(selector) */
if (descriptor.valid == 0 || descriptor.segment ||
descriptor.type != BX_SYS_SEGMENT_LDT)
@ -388,14 +391,6 @@ void BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
void BX_CPU_C::LTR_Ew(bxInstruction_c *i)
{
if (real_mode() || v8086_mode()) {
BX_INFO(("LTR: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i);
}
// protected mode
invalidate_prefetch_q();
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit16u raw_selector;
@ -404,6 +399,13 @@ void BX_CPU_C::LTR_Ew(bxInstruction_c *i)
Bit32u dword3;
#endif
if (real_mode() || v8086_mode()) {
BX_INFO(("LTR: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i);
}
invalidate_prefetch_q();
/* #GP(0) if the current privilege level is not 0 */
if (CPL != 0) {
BX_ERROR(("LTR: The current priveledge level is not 0"));
@ -461,16 +463,6 @@ void BX_CPU_C::LTR_Ew(bxInstruction_c *i)
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0);
}
/*
// the real hardware CPU allow loading of tss with limit < minimum
if (descriptor.type==1 && descriptor.u.tss286.limit<43) {
BX_PANIC(("LTR:286TSS: loading tr.limit < 43"));
}
else if (descriptor.type==9 && descriptor.u.tss386.limit_scaled<103) {
BX_PANIC(("LTR:386TSS: loading tr.limit < 103"));
}
*/
BX_CPU_THIS_PTR tr.selector = selector;
BX_CPU_THIS_PTR tr.cache = descriptor;
BX_CPU_THIS_PTR tr.cache.valid = 1;
@ -650,8 +642,7 @@ void BX_CPU_C::SGDT_Ms(bxInstruction_c *i)
{
/* op1 is a register or memory reference */
if (i->modC0()) {
/* undefined opcode exception */
BX_INFO(("SGDT_Ms: use of register is undefined opcode."));
BX_INFO(("SGDT_Ms: use of register is undefined opcode"));
UndefinedOpcode(i);
}
@ -689,8 +680,7 @@ void BX_CPU_C::SIDT_Ms(bxInstruction_c *i)
/* op1 is a register or memory reference */
if (i->modC0()) {
/* undefined opcode exception */
BX_INFO(("SIDT: use of register is undefined opcode."));
BX_INFO(("SIDT: use of register is undefined opcode"));
UndefinedOpcode(i);
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: segment_ctrl_pro.cc,v 1.65 2006-06-12 19:51:31 sshwarts Exp $
// $Id: segment_ctrl_pro.cc,v 1.66 2006-08-22 19:06:03 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -343,8 +343,7 @@ BX_CPU_C::get_descriptor_l(const bx_descriptor_t *d)
}
if (d->segment) {
val = ((d->u.segment.base & 0xffff) << 16) |
(d->u.segment.limit & 0xffff);
val = ((d->u.segment.base & 0xffff) << 16) | (d->u.segment.limit & 0xffff);
return(val);
}
else {
@ -357,12 +356,11 @@ BX_CPU_C::get_descriptor_l(const bx_descriptor_t *d)
case BX_SYS_SEGMENT_BUSY_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
val = ((d->u.tss.base & 0xffff) << 16) |
(d->u.tss.limit & 0xffff);
val = ((d->u.tss.base & 0xffff) << 16) | (d->u.tss.limit & 0xffff);
return(val);
case BX_SYS_SEGMENT_LDT:
val = ((d->u.ldt.base & 0xffff) << 16) | d->u.ldt.limit;
val = ((d->u.ldt.base & 0xffff) << 16) | (d->u.ldt.limit & 0xffff);
return(val);
default:
@ -430,6 +428,7 @@ BX_CPU_C::get_descriptor_h(const bx_descriptor_t *d)
(d->type << 8) |
(d->dpl << 13) |
(d->p << 15) |
(d->u.ldt.limit & 0xf0000) |
(d->u.ldt.base & 0xff000000);
return(val);
@ -612,11 +611,9 @@ BX_CPU_C::parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
temp->valid = 1;
break;
case BX_SYS_SEGMENT_LDT:
temp->u.ldt.base = (dword1 >> 16) | ((dword2 & 0xFF) << 16);
#if BX_CPU_LEVEL >= 3
temp->u.ldt.base |= (dword2 & 0xff000000);
#endif
temp->u.ldt.limit = (dword1 & 0xffff);
temp->u.ldt.base = (dword1 >> 16) |
((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
temp->u.ldt.limit = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
temp->valid = 1;
break;
case BX_286_CALL_GATE:
@ -636,8 +633,7 @@ BX_CPU_C::parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
temp->u.tss.base = (dword1 >> 16) |
((dword2 & 0xff) << 16) |
(dword2 & 0xff000000);
((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
temp->u.tss.limit = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
temp->u.tss.g = (dword2 & 0x00800000) > 0;
temp->u.tss.avl = (dword2 & 0x00100000) > 0;
@ -682,9 +678,8 @@ BX_CPU_C::load_ldtr(bx_selector_t *selector, bx_descriptor_t *descriptor)
BX_CPU_THIS_PTR ldtr.cache = *descriptor; /* whole structure copy */
BX_CPU_THIS_PTR ldtr.selector = *selector;
if (BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit < 7) {
if (BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit < 7)
BX_PANIC(("load_ldtr(): ldtr.limit < 7"));
}
BX_CPU_THIS_PTR ldtr.cache.valid = 1;
}
@ -715,14 +710,15 @@ BX_CPU_C::load_ss(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cp
BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
{
Bit32u index = selector->index;
if (selector->ti == 0) { /* GDT */
if ((selector->index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
BX_ERROR(("fetch_raw_descriptor: GDT: index (%x)%x > limit (%x)",
(selector->index*8 + 7), selector->index,
BX_CPU_THIS_PTR gdtr.limit));
(selector->index*8 + 7), index, BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
bx_address offset = BX_CPU_THIS_PTR gdtr.base + selector->index*8;
bx_address offset = BX_CPU_THIS_PTR gdtr.base + index*8;
access_linear(offset, 4, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2);
}
@ -731,13 +727,12 @@ BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
BX_PANIC(("fetch_raw_descriptor: LDTR.valid=0"));
debug(BX_CPU_THIS_PTR prev_eip);
}
if ((selector->index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit) {
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit) {
BX_ERROR(("fetch_raw_descriptor: LDT: index (%x)%x > limit (%x)",
(selector->index*8 + 7), selector->index,
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
(index*8 + 7), index, BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
bx_address offset = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8;
bx_address offset = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + index*8;
access_linear(offset, 4, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2);
}
@ -746,10 +741,12 @@ BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
bx_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2)
{
Bit32u index = selector->index;
if (selector->ti == 0) { /* GDT */
if ((selector->index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit)
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit)
return(0);
bx_address offset = BX_CPU_THIS_PTR gdtr.base + selector->index*8;
bx_address offset = BX_CPU_THIS_PTR gdtr.base + index*8;
access_linear(offset, 4, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2);
return(1);
@ -759,9 +756,9 @@ BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, B
BX_PANIC(("fetch_raw_descriptor2: LDTR.valid=0"));
return(0);
}
if ((selector->index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit)
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit)
return(0);
bx_address offset = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8;
bx_address offset = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + index*8;
access_linear(offset, 4, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2);
return(1);
@ -772,16 +769,16 @@ BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, B
void BX_CPU_C::fetch_raw_descriptor64(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no)
{
Bit32u index = selector->index;
Bit32u dword4;
if (selector->ti == 0) { /* GDT */
if ((selector->index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
BX_ERROR(("fetch_raw_descriptor64: GDT: index (%x)%x > limit (%x)",
(selector->index*8 + 15), selector->index,
BX_CPU_THIS_PTR gdtr.limit));
(index*8 + 15), index, BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
bx_address offset = BX_CPU_THIS_PTR gdtr.base + selector->index*8;
bx_address offset = BX_CPU_THIS_PTR gdtr.base + index*8;
access_linear(offset, 4, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2);
access_linear(offset + 8, 4, 0, BX_READ, dword3);
@ -792,13 +789,12 @@ void BX_CPU_C::fetch_raw_descriptor64(const bx_selector_t *selector,
BX_PANIC(("fetch_raw_descriptor: LDTR.valid=0"));
debug(BX_CPU_THIS_PTR prev_eip);
}
if ((selector->index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit) {
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit) {
BX_ERROR(("fetch_raw_descriptor64: LDT: index (%x)%x > limit (%x)",
(selector->index*8 + 15), selector->index,
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
(index*8 + 15), index, BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
bx_address offset = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8;
bx_address offset = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + index*8;
access_linear(offset, 4, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2);
access_linear(offset + 8, 4, 0, BX_READ, dword3);