LDS/LES/LFS/LGS/LSS: Fix segment wraparounds in 16-bit address mode.

This commit is contained in:
OBattler
2025-04-07 06:03:19 +02:00
parent 018ff46253
commit 3b5966eb46
15 changed files with 105 additions and 31 deletions

View File

@@ -1054,6 +1054,13 @@ MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset)
addbyte(0x83); /*ADD EAX, offset*/ addbyte(0x83); /*ADD EAX, offset*/
addbyte(0xc0); addbyte(0xc0);
addbyte(offset); addbyte(offset);
if (!(op_32 & 0x200)) {
addbyte(0x25) /* AND EAX, ffffh */
addbyte(0xff);
addbyte(0xff);
addbyte(0x00);
addbyte(0x00);
}
MEM_LOAD_ADDR_EA_W(seg); MEM_LOAD_ADDR_EA_W(seg);
} }
static __inline void static __inline void

View File

@@ -802,6 +802,13 @@ MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset)
addbyte(0x83); /*ADD EAX, offset*/ addbyte(0x83); /*ADD EAX, offset*/
addbyte(0xc0); addbyte(0xc0);
addbyte(offset); addbyte(offset);
if (!(op_32 & 0x200)) {
addbyte(0x25) /* AND EAX, ffffh */
addbyte(0xff);
addbyte(0xff);
addbyte(0x00);
addbyte(0x00);
}
addbyte(0xe8); /*CALL mem_load_addr_ea_w*/ addbyte(0xe8); /*CALL mem_load_addr_ea_w*/
addlong(mem_load_addr_ea_w - (uint32_t) (&codeblock[block_current].data[block_pos + 4])); addlong(mem_load_addr_ea_w - (uint32_t) (&codeblock[block_current].data[block_pos + 4]));

View File

@@ -931,6 +931,8 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0);
if (uop->imm_data) if (uop->imm_data)
host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data);
if (uop->is_a16)
host_arm64_AND_IMM(block, REG_X0, REG_X0, 0xffff);
if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) { if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) {
host_arm64_call(block, codegen_mem_load_byte); host_arm64_call(block, codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) { } else if (REG_IS_W(dest_size)) {

View File

@@ -995,6 +995,8 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg);
if (uop->imm_data) if (uop->imm_data)
host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data);
if (uop->is_a16)
host_arm_AND_IMM(block, REG_R0, REG_R0, 0xffff);
if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) { if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) {
host_arm_BL(block, (uintptr_t) codegen_mem_load_byte); host_arm_BL(block, (uintptr_t) codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) { } else if (REG_IS_W(dest_size)) {

View File

@@ -997,8 +997,13 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg);
if (uop->imm_data) if (uop->imm_data) {
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); if (uop->is_a16) {
host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data);
} else {
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data);
}
}
if (REG_IS_B(dest_size)) { if (REG_IS_B(dest_size)) {
host_x86_CALL(block, codegen_mem_load_byte); host_x86_CALL(block, codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) { } else if (REG_IS_W(dest_size)) {

View File

@@ -981,8 +981,13 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg);
if (uop->imm_data) if (uop->imm_data) {
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); if (uop->is_a16) {
host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data);
} else {
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data);
}
}
if (REG_IS_B(dest_size)) { if (REG_IS_B(dest_size)) {
host_x86_CALL(block, codegen_mem_load_byte); host_x86_CALL(block, codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) { } else if (REG_IS_W(dest_size)) {

View File

@@ -340,6 +340,7 @@ typedef struct uop_t {
void *p; void *p;
ir_host_reg_t dest_reg_a_real; ir_host_reg_t dest_reg_a_real;
ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real; ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real;
int is_a16;
int jump_dest_uop; int jump_dest_uop;
int jump_list_next; int jump_list_next;
void *jump_dest; void *jump_dest;
@@ -364,6 +365,8 @@ uop_alloc(ir_data_t *ir, uint32_t uop_type)
uop = &ir->uops[ir->wr_pos++]; uop = &ir->uops[ir->wr_pos++];
uop->is_a16 = 0;
uop->dest_reg_a = invalid_ir_reg; uop->dest_reg_a = invalid_ir_reg;
uop->src_reg_a = invalid_ir_reg; uop->src_reg_a = invalid_ir_reg;
uop->src_reg_b = invalid_ir_reg; uop->src_reg_b = invalid_ir_reg;
@@ -489,7 +492,12 @@ uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src
uop->type = uop_type; uop->type = uop_type;
uop->src_reg_a = codegen_reg_read(src_reg_a); uop->src_reg_a = codegen_reg_read(src_reg_a);
uop->src_reg_b = codegen_reg_read(src_reg_b); uop->is_a16 = 0;
if (src_reg_b == IREG_eaa16) {
uop->src_reg_b = codegen_reg_read(IREG_eaaddr);
uop->is_a16 = 1;
} else
uop->src_reg_b = codegen_reg_read(src_reg_b);
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
uop->imm_data = imm; uop->imm_data = imm;
} }

View File

@@ -533,8 +533,8 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE
uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \
target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \
codegen_check_seg_read(block, ir, target_seg); \ codegen_check_seg_read(block, ir, target_seg); \
uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \ uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16); \
uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \ uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16, 2); \
uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ uop_LOAD_SEG(ir, seg, IREG_temp1_W); \
uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \ uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \
\ \
@@ -556,8 +556,8 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE
uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \
target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \
codegen_check_seg_read(block, ir, target_seg); \ codegen_check_seg_read(block, ir, target_seg); \
uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \ uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16); \
uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \ uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16, 4); \
uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ uop_LOAD_SEG(ir, seg, IREG_temp1_W); \
uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \ uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \
\ \

View File

@@ -169,6 +169,8 @@ struct
[IREG_GS_limit_high] = { REG_DWORD, &cpu_state.seg_gs.limit_high, REG_INTEGER, REG_PERMANENT}, [IREG_GS_limit_high] = { REG_DWORD, &cpu_state.seg_gs.limit_high, REG_INTEGER, REG_PERMANENT},
[IREG_SS_limit_high] = { REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT}, [IREG_SS_limit_high] = { REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT},
[IREG_eaa16] = { REG_WORD, &cpu_state.eaaddr, REG_INTEGER, REG_PERMANENT},
/*Temporary registers are stored on the stack, and are not guaranteed to /*Temporary registers are stored on the stack, and are not guaranteed to
be preserved across uOPs. They will not be written back if they will be preserved across uOPs. They will not be written back if they will
not be read again.*/ not be read again.*/

View File

@@ -132,7 +132,9 @@ enum {
IREG_GS_limit_high = 86, IREG_GS_limit_high = 86,
IREG_SS_limit_high = 87, IREG_SS_limit_high = 87,
IREG_COUNT = 88, IREG_eaa16 = 88,
IREG_COUNT = 89,
IREG_INVALID = 255, IREG_INVALID = 255,

View File

@@ -248,6 +248,19 @@ int checkio(uint32_t port, int mask);
return 1; \ return 1; \
} }
#define CHECK_READ_2OP(chseg, low, high, low2, high2) \
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || (low2 < (chseg)->limit_low) || (high2 > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) { \
x86gpf("Limit check (READ)", 0); \
return 1; \
} \
if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !((chseg)->access & 0x80)) { \
if ((chseg) == &cpu_state.seg_ss) \
x86ss(NULL, (chseg)->seg & 0xfffc); \
else \
x86np("Read from seg not present", (chseg)->seg & 0xfffc); \
return 1; \
}
#define CHECK_READ_REP(chseg, low, high) \ #define CHECK_READ_REP(chseg, low, high) \
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \
x86gpf("Limit check (READ)", 0); \ x86gpf("Limit check (READ)", 0); \
@@ -277,6 +290,19 @@ int checkio(uint32_t port, int mask);
#define CHECK_WRITE(chseg, low, high) \ #define CHECK_WRITE(chseg, low, high) \
CHECK_WRITE_COMMON(chseg, low, high) CHECK_WRITE_COMMON(chseg, low, high)
#define CHECK_WRITE_2OP(chseg, low, high, low2, high2) \
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || (low2 < (chseg)->limit_low) || (high2 > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) { \
x86gpf("Limit check (WRITE)", 0); \
return 1; \
} \
if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !((chseg)->access & 0x80)) { \
if ((chseg) == &cpu_state.seg_ss) \
x86ss(NULL, (chseg)->seg & 0xfffc); \
else \
x86np("Write to seg not present", (chseg)->seg & 0xfffc); \
return 1; \
}
#define CHECK_WRITE_REP(chseg, low, high) \ #define CHECK_WRITE_REP(chseg, low, high) \
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \
x86gpf("Limit check (WRITE REP)", 0); \ x86gpf("Limit check (WRITE REP)", 0); \

View File

@@ -335,7 +335,10 @@ typedef struct {
uint8_t tag[8]; uint8_t tag[8];
x86seg *ea_seg; x86seg *ea_seg;
uint32_t eaaddr; union {
uint32_t eaaddr;
uint16_t eaa16[2];
};
int flags_op; int flags_op;
uint32_t flags_res; uint32_t flags_res;

View File

@@ -272,9 +272,10 @@ opLDS_w_a16(uint32_t fetchdat)
fetch_ea_16(fetchdat); fetch_ea_16(fetchdat);
ILLEGAL_ON(cpu_mod == 3); ILLEGAL_ON(cpu_mod == 3);
SEG_CHECK_READ(cpu_state.ea_seg); SEG_CHECK_READ(cpu_state.ea_seg);
CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1,
addr = readmemw(easeg, cpu_state.eaaddr); ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1);
seg = readmemw(easeg, cpu_state.eaaddr + 2); addr = readmemw(easeg, cpu_state.eaa16[0]);
seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff);
if (cpu_state.abrt) if (cpu_state.abrt)
return 1; return 1;
op_loadseg(seg, &cpu_state.seg_ds); op_loadseg(seg, &cpu_state.seg_ds);
@@ -318,9 +319,10 @@ opLDS_l_a16(uint32_t fetchdat)
fetch_ea_16(fetchdat); fetch_ea_16(fetchdat);
ILLEGAL_ON(cpu_mod == 3); ILLEGAL_ON(cpu_mod == 3);
SEG_CHECK_READ(cpu_state.ea_seg); SEG_CHECK_READ(cpu_state.ea_seg);
CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3,
addr = readmeml(easeg, cpu_state.eaaddr); ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1);
seg = readmemw(easeg, cpu_state.eaaddr + 4); addr = readmeml(easeg, cpu_state.eaa16[0]);
seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff);
if (cpu_state.abrt) if (cpu_state.abrt)
return 1; return 1;
op_loadseg(seg, &cpu_state.seg_ds); op_loadseg(seg, &cpu_state.seg_ds);
@@ -365,9 +367,10 @@ opLSS_w_a16(uint32_t fetchdat)
fetch_ea_16(fetchdat); fetch_ea_16(fetchdat);
ILLEGAL_ON(cpu_mod == 3); ILLEGAL_ON(cpu_mod == 3);
SEG_CHECK_READ(cpu_state.ea_seg); SEG_CHECK_READ(cpu_state.ea_seg);
CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1,
addr = readmemw(easeg, cpu_state.eaaddr); ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1);
seg = readmemw(easeg, cpu_state.eaaddr + 2); addr = readmemw(easeg, cpu_state.eaa16[0]);
seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff);
if (cpu_state.abrt) if (cpu_state.abrt)
return 1; return 1;
op_loadseg(seg, &cpu_state.seg_ss); op_loadseg(seg, &cpu_state.seg_ss);
@@ -411,9 +414,11 @@ opLSS_l_a16(uint32_t fetchdat)
fetch_ea_16(fetchdat); fetch_ea_16(fetchdat);
ILLEGAL_ON(cpu_mod == 3); ILLEGAL_ON(cpu_mod == 3);
SEG_CHECK_READ(cpu_state.ea_seg); SEG_CHECK_READ(cpu_state.ea_seg);
CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3,
addr = readmeml(easeg, cpu_state.eaaddr); ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1);
seg = readmemw(easeg, cpu_state.eaaddr + 4); CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 5) & 0xffff));
addr = readmeml(easeg, cpu_state.eaa16[0]);
seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff);
if (cpu_state.abrt) if (cpu_state.abrt)
return 1; return 1;
op_loadseg(seg, &cpu_state.seg_ss); op_loadseg(seg, &cpu_state.seg_ss);
@@ -457,9 +462,9 @@ opLSS_l_a32(uint32_t fetchdat)
fetch_ea_16(fetchdat); \ fetch_ea_16(fetchdat); \
SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_READ(cpu_state.ea_seg); \
ILLEGAL_ON(cpu_mod == 3); \ ILLEGAL_ON(cpu_mod == 3); \
CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); \ CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); \
addr = readmemw(easeg, cpu_state.eaaddr); \ addr = readmemw(easeg, cpu_state.eaa16[0]); \
seg = readmemw(easeg, cpu_state.eaaddr + 2); \ seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); \
if (cpu_state.abrt) \ if (cpu_state.abrt) \
return 1; \ return 1; \
op_loadseg(seg, &sel); \ op_loadseg(seg, &sel); \
@@ -502,9 +507,9 @@ opLSS_l_a32(uint32_t fetchdat)
fetch_ea_16(fetchdat); \ fetch_ea_16(fetchdat); \
SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_READ(cpu_state.ea_seg); \
ILLEGAL_ON(cpu_mod == 3); \ ILLEGAL_ON(cpu_mod == 3); \
CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); \ CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); \
addr = readmeml(easeg, cpu_state.eaaddr); \ addr = readmeml(easeg, cpu_state.eaa16[0]); \
seg = readmemw(easeg, cpu_state.eaaddr + 4); \ seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); \
if (cpu_state.abrt) \ if (cpu_state.abrt) \
return 1; \ return 1; \
op_loadseg(seg, &sel); \ op_loadseg(seg, &sel); \

View File

@@ -15,7 +15,7 @@
op_loadcs(readmemw(ss, ESP + 2)); \ op_loadcs(readmemw(ss, ESP + 2)); \
} else { \ } else { \
cpu_state.pc = readmemw(ss, SP); \ cpu_state.pc = readmemw(ss, SP); \
op_loadcs(readmemw(ss, SP + 2)); \ op_loadcs(readmemw(ss, (SP + 2) & 0xffff)); \
} \ } \
if (cpu_state.abrt) \ if (cpu_state.abrt) \
return 1; \ return 1; \

View File

@@ -15,7 +15,7 @@
op_loadcs(readmemw(ss, ESP + 2)); \ op_loadcs(readmemw(ss, ESP + 2)); \
} else { \ } else { \
cpu_state.pc = readmemw(ss, SP); \ cpu_state.pc = readmemw(ss, SP); \
op_loadcs(readmemw(ss, SP + 2)); \ op_loadcs(readmemw(ss, (SP + 2) & 0xffff)); \
} \ } \
if (cpu_state.abrt) \ if (cpu_state.abrt) \
return 1; \ return 1; \