dyncom: Migrate exclusive memory access control into armstate
This commit is contained in:
parent
db4e99c186
commit
a507ea23c1
|
@ -47,27 +47,6 @@ enum {
|
||||||
|
|
||||||
typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
|
typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
|
||||||
|
|
||||||
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
|
|
||||||
// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
|
|
||||||
// support LDR/STREXD.
|
|
||||||
static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
|
|
||||||
|
|
||||||
// Exclusive memory access
|
|
||||||
static int exclusive_detect(ARMul_State* state, u32 addr) {
|
|
||||||
if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK))
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_exclusive_addr(ARMul_State* state, u32 addr){
|
|
||||||
state->exclusive_tag = addr & RESERVATION_GRANULE_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_exclusive(ARMul_State* state, u32 addr){
|
|
||||||
state->exclusive_tag = 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CondPassed(ARMul_State* cpu, unsigned int cond) {
|
static int CondPassed(ARMul_State* cpu, unsigned int cond) {
|
||||||
const u32 NFLAG = cpu->NFlag;
|
const u32 NFLAG = cpu->NFlag;
|
||||||
const u32 ZFLAG = cpu->ZFlag;
|
const u32 ZFLAG = cpu->ZFlag;
|
||||||
|
@ -4170,9 +4149,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
|
|
||||||
CLREX_INST:
|
CLREX_INST:
|
||||||
{
|
{
|
||||||
remove_exclusive(cpu, 0);
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
cpu->exclusive_state = 0;
|
|
||||||
|
|
||||||
cpu->Reg[15] += cpu->GetInstructionSize();
|
cpu->Reg[15] += cpu->GetInstructionSize();
|
||||||
INC_PC(sizeof(clrex_inst));
|
INC_PC(sizeof(clrex_inst));
|
||||||
FETCH_INST;
|
FETCH_INST;
|
||||||
|
@ -4539,8 +4516,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int read_addr = RN;
|
unsigned int read_addr = RN;
|
||||||
|
|
||||||
add_exclusive_addr(cpu, read_addr);
|
cpu->SetExclusiveMemoryAddress(read_addr);
|
||||||
cpu->exclusive_state = 1;
|
|
||||||
|
|
||||||
RD = cpu->ReadMemory32(read_addr);
|
RD = cpu->ReadMemory32(read_addr);
|
||||||
if (inst_cream->Rd == 15) {
|
if (inst_cream->Rd == 15) {
|
||||||
|
@ -4559,8 +4535,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int read_addr = RN;
|
unsigned int read_addr = RN;
|
||||||
|
|
||||||
add_exclusive_addr(cpu, read_addr);
|
cpu->SetExclusiveMemoryAddress(read_addr);
|
||||||
cpu->exclusive_state = 1;
|
|
||||||
|
|
||||||
RD = Memory::Read8(read_addr);
|
RD = Memory::Read8(read_addr);
|
||||||
if (inst_cream->Rd == 15) {
|
if (inst_cream->Rd == 15) {
|
||||||
|
@ -4579,8 +4554,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int read_addr = RN;
|
unsigned int read_addr = RN;
|
||||||
|
|
||||||
add_exclusive_addr(cpu, read_addr);
|
cpu->SetExclusiveMemoryAddress(read_addr);
|
||||||
cpu->exclusive_state = 1;
|
|
||||||
|
|
||||||
RD = cpu->ReadMemory16(read_addr);
|
RD = cpu->ReadMemory16(read_addr);
|
||||||
if (inst_cream->Rd == 15) {
|
if (inst_cream->Rd == 15) {
|
||||||
|
@ -4599,8 +4573,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int read_addr = RN;
|
unsigned int read_addr = RN;
|
||||||
|
|
||||||
add_exclusive_addr(cpu, read_addr);
|
cpu->SetExclusiveMemoryAddress(read_addr);
|
||||||
cpu->exclusive_state = 1;
|
|
||||||
|
|
||||||
RD = cpu->ReadMemory32(read_addr);
|
RD = cpu->ReadMemory32(read_addr);
|
||||||
RD2 = cpu->ReadMemory32(read_addr + 4);
|
RD2 = cpu->ReadMemory32(read_addr + 4);
|
||||||
|
@ -6085,10 +6058,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
||||||
|
|
||||||
if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
|
if (cpu->IsExclusiveMemoryAccess(write_addr)) {
|
||||||
remove_exclusive(cpu, write_addr);
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
cpu->exclusive_state = 0;
|
|
||||||
|
|
||||||
cpu->WriteMemory32(write_addr, RM);
|
cpu->WriteMemory32(write_addr, RM);
|
||||||
RD = 0;
|
RD = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -6107,10 +6078,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
||||||
|
|
||||||
if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
|
if (cpu->IsExclusiveMemoryAccess(write_addr)) {
|
||||||
remove_exclusive(cpu, write_addr);
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
cpu->exclusive_state = 0;
|
|
||||||
|
|
||||||
Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]);
|
Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]);
|
||||||
RD = 0;
|
RD = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -6129,9 +6098,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
||||||
|
|
||||||
if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
|
if (cpu->IsExclusiveMemoryAccess(write_addr)) {
|
||||||
remove_exclusive(cpu, write_addr);
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
cpu->exclusive_state = 0;
|
|
||||||
|
|
||||||
const u32 rt = cpu->Reg[inst_cream->Rm + 0];
|
const u32 rt = cpu->Reg[inst_cream->Rm + 0];
|
||||||
const u32 rt2 = cpu->Reg[inst_cream->Rm + 1];
|
const u32 rt2 = cpu->Reg[inst_cream->Rm + 1];
|
||||||
|
@ -6161,10 +6129,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||||
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
|
||||||
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
|
||||||
|
|
||||||
if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
|
if (cpu->IsExclusiveMemoryAccess(write_addr)) {
|
||||||
remove_exclusive(cpu, write_addr);
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
cpu->exclusive_state = 0;
|
|
||||||
|
|
||||||
cpu->WriteMemory16(write_addr, RM);
|
cpu->WriteMemory16(write_addr, RM);
|
||||||
RD = 0;
|
RD = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -163,6 +163,19 @@ public:
|
||||||
u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
|
u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
|
||||||
void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
|
void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
|
||||||
|
|
||||||
|
// Exclusive memory access functions
|
||||||
|
bool IsExclusiveMemoryAccess(u32 address) const {
|
||||||
|
return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK);
|
||||||
|
}
|
||||||
|
void SetExclusiveMemoryAddress(u32 address) {
|
||||||
|
exclusive_tag = address & RESERVATION_GRANULE_MASK;
|
||||||
|
exclusive_state = true;
|
||||||
|
}
|
||||||
|
void UnsetExclusiveMemoryAddress() {
|
||||||
|
exclusive_tag = 0xFFFFFFFF;
|
||||||
|
exclusive_state = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Whether or not the given CPU is in big endian mode (E bit is set)
|
// Whether or not the given CPU is in big endian mode (E bit is set)
|
||||||
bool InBigEndianMode() const {
|
bool InBigEndianMode() const {
|
||||||
return (Cpsr & (1 << 9)) != 0;
|
return (Cpsr & (1 << 9)) != 0;
|
||||||
|
@ -203,9 +216,6 @@ public:
|
||||||
|
|
||||||
u32 Mode; // The current mode
|
u32 Mode; // The current mode
|
||||||
u32 Bank; // The current register bank
|
u32 Bank; // The current register bank
|
||||||
u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
|
|
||||||
u32 exclusive_state;
|
|
||||||
u32 exclusive_result;
|
|
||||||
|
|
||||||
u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
|
u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
|
||||||
unsigned int shifter_carry_out;
|
unsigned int shifter_carry_out;
|
||||||
|
@ -230,4 +240,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ResetMPCoreCP15Registers();
|
void ResetMPCoreCP15Registers();
|
||||||
|
|
||||||
|
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
|
||||||
|
// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
|
||||||
|
// support LDR/STREXD.
|
||||||
|
static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
|
||||||
|
|
||||||
|
u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
|
||||||
|
u32 exclusive_result;
|
||||||
|
bool exclusive_state;
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue