Added Thumb rejection. Can run retail games now.

This commit is contained in:
Dani Messerman 2015-05-05 21:24:23 +03:00
parent 1b87113184
commit 840ab06561
3 changed files with 102 additions and 39 deletions

View File

@ -152,7 +152,7 @@ void ModuleGen::GenerateGetBlockAddressFunction()
/*
entry_basic_block:
auto index = (pc - block_address_array_base) / 4;
if(index < block_address_array_size)
if(((pc & 3) == 0) && index < block_address_array_size)
{
index_in_bounds_basic_block:
return block_address_array[index];
@ -169,10 +169,12 @@ void ModuleGen::GenerateGetBlockAddressFunction()
auto index_out_of_bounds_basic_block = BasicBlock::Create(getGlobalContext(), "IndexOutOfBounds", get_block_address_function);
ir_builder->SetInsertPoint(entry_basic_block);
auto index = ir_builder->CreateUDiv(pc, ir_builder->getInt32(4));
auto index = ir_builder->CreateUDiv(pc, ir_builder->getInt32(4), "", true);
index = ir_builder->CreateSub(index, ir_builder->getInt32(block_address_array_base));
auto in_bounds_pred = ir_builder->CreateICmpULT(index, ir_builder->getInt32(block_address_array_size));
ir_builder->CreateCondBr(in_bounds_pred, index_in_bounds_basic_block, index_out_of_bounds_basic_block);
auto arm_pred = ir_builder->CreateICmpEQ(ir_builder->CreateAnd(pc, 3), ir_builder->getInt32(0));
auto pred = ir_builder->CreateAnd(in_bounds_pred, arm_pred);
ir_builder->CreateCondBr(pred, index_in_bounds_basic_block, index_out_of_bounds_basic_block);
ir_builder->SetInsertPoint(index_in_bounds_basic_block);
Value *gep_values[] = { ir_builder->getInt32(0), index };

View File

@ -11,21 +11,66 @@ using namespace llvm;
bool g_enabled = false;
bool g_verify = false;
ARMul_State *g_state;
std::unique_ptr<SectionMemoryManager> g_memory_manager;
std::unique_ptr<RuntimeDyld> g_dyld;
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> g_loaded_object_info;
void (*g_run_function)();
void(*g_run_function)();
bool(*g_can_run_function)();
// Used by the verifier
bool (*g_can_run_function)();
struct SavedState
{
SavedState() { }
SavedState(const ARMul_State &state)
{
memcpy(regs, state.Reg, sizeof(regs));
memcpy(flags, &state.NFlag, sizeof(flags));
t_flag = state.TFlag;
}
void CopyTo(ARMul_State &state)
{
memcpy(state.Reg, regs, sizeof(regs));
memcpy(&state.NFlag, flags, sizeof(flags));
t_flag = state.TFlag;
}
void SwapWith(ARMul_State &state)
{
SavedState arm_state = state;
std::swap(*this, arm_state);
arm_state.CopyTo(state);
}
void Print()
{
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
regs[0], regs[1], regs[2], regs[3],
regs[4], regs[5], regs[6], regs[7]);
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
regs[8], regs[9], regs[10], regs[11],
regs[12], regs[13], regs[14], regs[15]);
LOG_ERROR(BinaryTranslator, "%01x %01x %01x %01x %01x", flags[0], flags[1], flags[2], flags[3], t_flag);
}
u32 regs[16];
u32 flags[4];
u32 t_flag;
};
bool operator==(const SavedState& lhs, const SavedState& rhs)
{
return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
bool operator!=(const SavedState& lhs, const SavedState& rhs)
{
return memcmp(&lhs, &rhs, sizeof(lhs)) != 0;
}
bool g_have_saved_state; // Whether there is a copied state
ARMul_State *g_state;
u32 g_regs_copy[16];
u32 g_flags_copy[4];
u32 g_regs_copy_before[16];
u32 g_flags_copy_before[4];
SavedState g_state_copy;
SavedState g_state_copy_before;
void BinaryTranslationLoader::Load(FileUtil::IOFile& file)
{
@ -90,12 +135,35 @@ void BinaryTranslationLoader::SetCpuState(ARMul_State* state)
g_state = state;
}
bool BinaryTranslationLoader::CanRun(bool specific_address)
{
if (!g_enabled) return false;
// Thumb not implemented
if (g_state->TFlag) return false;
if (specific_address)
if (!g_can_run_function()) return false;
return true;
}
void BinaryTranslationLoader::Run()
{
// No need to check the PC, Run does it anyway
if (!CanRun(false)) return;
// If verify is enabled, it will run opcodes
if (!g_enabled || g_verify) return;
if (g_verify) return;
RunInternal();
}
void BinaryTranslationLoader::RunInternal()
{
g_run_function();
g_state->TFlag = g_state->Reg[15] & 1;
if (g_state->TFlag)
g_state->Reg[15] &= 0xfffffffe;
else
g_state->Reg[15] &= 0xfffffffc;
}
void Swap(void *a, void *b, size_t size)
@ -108,65 +176,53 @@ void Swap(void *a, void *b, size_t size)
}
}
void ShowRegs(u32 *regs, u32 *flags)
{
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
regs[0], regs[1], regs[2], regs[3],
regs[4], regs[5], regs[6], regs[7]);
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
regs[8], regs[9], regs[10], regs[11],
regs[12], regs[13], regs[14], regs[15]);
LOG_ERROR(BinaryTranslator, "%01x %01x %01x %01x", flags[0], flags[1], flags[2], flags[3]);
}
void BinaryTranslationLoader::VerifyCallback()
{
if (!g_enabled || !g_verify) return;
// Swap the PC to the old state before checking if it can run
std::swap(g_regs_copy[15], g_state->Reg[15]);
auto can_run = g_can_run_function();
std::swap(g_regs_copy[15], g_state->Reg[15]);
// Swap the PC and TFlag to the old state before checking if it can run
std::swap(g_state_copy.regs[15], g_state->Reg[15]);
std::swap(g_state_copy.t_flag, g_state->TFlag);
auto can_run = CanRun(true);
std::swap(g_state_copy.regs[15], g_state->Reg[15]);
std::swap(g_state_copy.t_flag, g_state->TFlag);
if (g_have_saved_state && can_run)
{
// An opcode is finished, simulate it
// Copy the state before
memcpy(g_regs_copy_before, g_regs_copy, sizeof(g_regs_copy));
memcpy(g_flags_copy_before, &g_flags_copy, sizeof(g_flags_copy));
g_state_copy_before = g_state_copy;
// Swap to the state before the opcode
Swap(g_state->Reg, g_regs_copy, sizeof(g_regs_copy));
Swap(&g_state->NFlag, g_flags_copy, sizeof(g_flags_copy));
g_state_copy.SwapWith(*g_state);
// Run the opcode
g_run_function();
RunInternal();
// Test
if (memcmp(g_state->Reg, g_regs_copy, sizeof(g_regs_copy)) || memcmp(&g_state->NFlag, g_flags_copy, sizeof(g_flags_copy)))
auto current_as_saved_state = SavedState(*g_state);
if (current_as_saved_state != g_state_copy)
{
LOG_ERROR(BinaryTranslator, "Verify failed");
LOG_ERROR(BinaryTranslator, "Regs Before");
ShowRegs(g_regs_copy_before, g_flags_copy_before);
g_state_copy_before.Print();
LOG_ERROR(BinaryTranslator, "Regs OK");
ShowRegs(g_regs_copy, g_flags_copy);
g_state_copy.Print();
LOG_ERROR(BinaryTranslator, "Regs not OK");
ShowRegs(g_state->Reg, &g_state->NFlag);
current_as_saved_state.Print();
// Don't spam
g_enabled = false;
// Make sure it has a valid state to continue to run
Swap(g_state->Reg, g_regs_copy, sizeof(g_regs_copy));
Swap(&g_state->NFlag, g_flags_copy, sizeof(g_flags_copy));
g_state_copy.CopyTo(*g_state);
}
}
else
{
// If this opcode is not translated or there is no saved state, just save the state and continue
memcpy(g_regs_copy, g_state->Reg, sizeof(g_regs_copy));
memcpy(g_flags_copy, &g_state->NFlag, sizeof(g_flags_copy));
g_state_copy = *g_state;
g_have_saved_state = true;
}

View File

@ -9,7 +9,12 @@ class BinaryTranslationLoader
public:
static void Load(FileUtil::IOFile& file);
static void SetCpuState(ARMul_State *state);
// Checks whether the cpu state can be run
// If specific_address, checks the specific PC too
static bool CanRun(bool specific_address);
// Runs the state provided at SetCpuState.
static void Run();
// Link between Run and VerifyCallback
static void RunInternal();
static void VerifyCallback();
};