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. // Copyright (C) 2001 MandrakeSoft S.A.
@ -156,7 +156,7 @@ union {
} tss; } tss;
struct { struct {
bx_address base; /* 286=24 386+ =32/64 bit LDT base */ 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; } ldt;
} u; } 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. // 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")); BX_INFO(("SLDT: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i); UndefinedOpcode(i);
} }
else {
Bit16u val16 = BX_CPU_THIS_PTR ldtr.selector.value; Bit16u val16 = BX_CPU_THIS_PTR ldtr.selector.value;
if (i->modC0()) { if (i->modC0()) {
BX_WRITE_16BIT_REG(i->rm(), val16); BX_WRITE_16BIT_REG(i->rm(), val16);
@ -287,7 +287,6 @@ void BX_CPU_C::SLDT_Ew(bxInstruction_c *i)
write_virtual_word(i->seg(), RMAddr(i), &val16); write_virtual_word(i->seg(), RMAddr(i), &val16);
} }
} }
}
#endif #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")); BX_INFO(("STR: not recognized in real or virtual-8086 mode"));
UndefinedOpcode(i); UndefinedOpcode(i);
} }
else {
Bit16u val16 = BX_CPU_THIS_PTR tr.selector.value; Bit16u val16 = BX_CPU_THIS_PTR tr.selector.value;
if (i->modC0()) { if (i->modC0()) {
BX_WRITE_16BIT_REG(i->rm(), val16); BX_WRITE_16BIT_REG(i->rm(), val16);
@ -306,24 +305,26 @@ void BX_CPU_C::STR_Ew(bxInstruction_c *i)
write_virtual_word(i->seg(), RMAddr(i), &val16); write_virtual_word(i->seg(), RMAddr(i), &val16);
} }
} }
}
#if BX_CPU_LEVEL >= 2 #if BX_CPU_LEVEL >= 2
void BX_CPU_C::LLDT_Ew(bxInstruction_c *i) 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 */ /* protected mode */
bx_descriptor_t descriptor; bx_descriptor_t descriptor;
bx_selector_t selector; bx_selector_t selector;
Bit16u raw_selector; Bit16u raw_selector;
Bit32u dword1, dword2; 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 */ /* #GP(0) if the current privilege level is not 0 */
if (CPL != 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); exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
} }
if ((selector.index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) { /* fetch 2 dwords of descriptor; call handles out of limits checks */
BX_PANIC(("LLDT: GDT: index > limit")); fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
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);
parse_descriptor(dword1, dword2, &descriptor); 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 selector doesn't point to an LDT descriptor #GP(selector) */
if (descriptor.valid == 0 || descriptor.segment || if (descriptor.valid == 0 || descriptor.segment ||
descriptor.type != BX_SYS_SEGMENT_LDT) 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) 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_descriptor_t descriptor;
bx_selector_t selector; bx_selector_t selector;
Bit16u raw_selector; Bit16u raw_selector;
@ -404,6 +399,13 @@ void BX_CPU_C::LTR_Ew(bxInstruction_c *i)
Bit32u dword3; Bit32u dword3;
#endif #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 */ /* #GP(0) if the current privilege level is not 0 */
if (CPL != 0) { if (CPL != 0) {
BX_ERROR(("LTR: The current priveledge level is not 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); 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.selector = selector;
BX_CPU_THIS_PTR tr.cache = descriptor; BX_CPU_THIS_PTR tr.cache = descriptor;
BX_CPU_THIS_PTR tr.cache.valid = 1; 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 */ /* op1 is a register or memory reference */
if (i->modC0()) { 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); UndefinedOpcode(i);
} }
@ -689,8 +680,7 @@ void BX_CPU_C::SIDT_Ms(bxInstruction_c *i)
/* op1 is a register or memory reference */ /* op1 is a register or memory reference */
if (i->modC0()) { 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); 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. // Copyright (C) 2001 MandrakeSoft S.A.
@ -343,8 +343,7 @@ BX_CPU_C::get_descriptor_l(const bx_descriptor_t *d)
} }
if (d->segment) { if (d->segment) {
val = ((d->u.segment.base & 0xffff) << 16) | val = ((d->u.segment.base & 0xffff) << 16) | (d->u.segment.limit & 0xffff);
(d->u.segment.limit & 0xffff);
return(val); return(val);
} }
else { 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_BUSY_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS: case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS: case BX_SYS_SEGMENT_BUSY_386_TSS:
val = ((d->u.tss.base & 0xffff) << 16) | val = ((d->u.tss.base & 0xffff) << 16) | (d->u.tss.limit & 0xffff);
(d->u.tss.limit & 0xffff);
return(val); return(val);
case BX_SYS_SEGMENT_LDT: 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); return(val);
default: default:
@ -430,6 +428,7 @@ BX_CPU_C::get_descriptor_h(const bx_descriptor_t *d)
(d->type << 8) | (d->type << 8) |
(d->dpl << 13) | (d->dpl << 13) |
(d->p << 15) | (d->p << 15) |
(d->u.ldt.limit & 0xf0000) |
(d->u.ldt.base & 0xff000000); (d->u.ldt.base & 0xff000000);
return(val); return(val);
@ -612,11 +611,9 @@ BX_CPU_C::parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
temp->valid = 1; temp->valid = 1;
break; break;
case BX_SYS_SEGMENT_LDT: case BX_SYS_SEGMENT_LDT:
temp->u.ldt.base = (dword1 >> 16) | ((dword2 & 0xFF) << 16); temp->u.ldt.base = (dword1 >> 16) |
#if BX_CPU_LEVEL >= 3 ((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
temp->u.ldt.base |= (dword2 & 0xff000000); temp->u.ldt.limit = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
#endif
temp->u.ldt.limit = (dword1 & 0xffff);
temp->valid = 1; temp->valid = 1;
break; break;
case BX_286_CALL_GATE: 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_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS: case BX_SYS_SEGMENT_BUSY_386_TSS:
temp->u.tss.base = (dword1 >> 16) | temp->u.tss.base = (dword1 >> 16) |
((dword2 & 0xff) << 16) | ((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
(dword2 & 0xff000000);
temp->u.tss.limit = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000); temp->u.tss.limit = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
temp->u.tss.g = (dword2 & 0x00800000) > 0; temp->u.tss.g = (dword2 & 0x00800000) > 0;
temp->u.tss.avl = (dword2 & 0x00100000) > 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.cache = *descriptor; /* whole structure copy */
BX_CPU_THIS_PTR ldtr.selector = *selector; 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_PANIC(("load_ldtr(): ldtr.limit < 7"));
}
BX_CPU_THIS_PTR ldtr.cache.valid = 1; 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, BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, unsigned exception_no) Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
{ {
Bit32u index = selector->index;
if (selector->ti == 0) { /* GDT */ 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)", BX_ERROR(("fetch_raw_descriptor: GDT: index (%x)%x > limit (%x)",
(selector->index*8 + 7), selector->index, (selector->index*8 + 7), index, BX_CPU_THIS_PTR gdtr.limit));
BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc, 0); 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, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2); 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")); BX_PANIC(("fetch_raw_descriptor: LDTR.valid=0"));
debug(BX_CPU_THIS_PTR prev_eip); 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)", BX_ERROR(("fetch_raw_descriptor: LDT: index (%x)%x > limit (%x)",
(selector->index*8 + 7), selector->index, (index*8 + 7), index, BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
exception(exception_no, selector->value & 0xfffc, 0); 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, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2); 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_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2) 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->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); 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, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2); access_linear(offset + 4, 4, 0, BX_READ, dword2);
return(1); 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")); BX_PANIC(("fetch_raw_descriptor2: LDTR.valid=0"));
return(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); 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, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2); access_linear(offset + 4, 4, 0, BX_READ, dword2);
return(1); 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, void BX_CPU_C::fetch_raw_descriptor64(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no) Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no)
{ {
Bit32u index = selector->index;
Bit32u dword4; Bit32u dword4;
if (selector->ti == 0) { /* GDT */ 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)", BX_ERROR(("fetch_raw_descriptor64: GDT: index (%x)%x > limit (%x)",
(selector->index*8 + 15), selector->index, (index*8 + 15), index, BX_CPU_THIS_PTR gdtr.limit));
BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc, 0); 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, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2); access_linear(offset + 4, 4, 0, BX_READ, dword2);
access_linear(offset + 8, 4, 0, BX_READ, dword3); 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")); BX_PANIC(("fetch_raw_descriptor: LDTR.valid=0"));
debug(BX_CPU_THIS_PTR prev_eip); 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)", BX_ERROR(("fetch_raw_descriptor64: LDT: index (%x)%x > limit (%x)",
(selector->index*8 + 15), selector->index, (index*8 + 15), index, BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
exception(exception_no, selector->value & 0xfffc, 0); 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, 0, BX_READ, dword1);
access_linear(offset + 4, 4, 0, BX_READ, dword2); access_linear(offset + 4, 4, 0, BX_READ, dword2);
access_linear(offset + 8, 4, 0, BX_READ, dword3); access_linear(offset + 8, 4, 0, BX_READ, dword3);