Compare commits

...

6 commits

Author SHA1 Message Date
Pokechu22 30b6b552dc
Merge c7b0198154 into 50386c4e39 2024-05-09 14:09:27 +03:00
OatmealDome 50386c4e39
Merge pull request #12740 from mitaclaw/breakpoint-before-fpu-exception
Jit64/JitArm64: Check Breakpoints Before FPU Availability
2024-05-08 01:26:08 -04:00
JosJuice 2c91367429
Merge pull request #12737 from nlebeck/settingshandler-split
Eliminate SettingsHandler's `SetBytes` and `Reset` methods
2024-05-05 22:35:23 +02:00
mitaclaw 756ea81ab2 Jit64: Smaller Instruction Breakpoint Condition
Also some static_asserts in JitArm64.
2024-04-28 15:54:15 -07:00
mitaclaw 307a1e3ab8 Jit64/JitArm64: Check Breakpoints Before FPU Availability
CachedInterpreter already does it in the expected order.
2024-04-26 10:58:16 -07:00
Niel Lebeck 36cdb4a544 Eliminate SettingsHandler's SetBytes and Reset methods
Also make the `Decrypt` method private.

As far as I can tell, the only motivation for exposing the `SetBytes`
and `Reset` methods is to allow `CBoot::SetupWiiMemory` to use the same
`SettingsHandler` instance to read settings data and then write it back.
It seems cleaner to just use two separate instances, and require a given
`SettingsHandler` instance to be used for either writing data to a
buffer or reading data from a buffer, but not both.

A natural next step is to split the `SettingsHandler` class into two
classes, one for writing data and one for reading data. I've deferred
that change for a future PR.
2024-04-23 17:19:01 -07:00
9 changed files with 79 additions and 115 deletions

View file

@ -17,14 +17,14 @@
namespace Common
{
SettingsHandler::SettingsHandler()
SettingsHandler::SettingsHandler() : m_buffer{}, m_position{0}, m_key{INITIAL_SEED}, decoded{""}
{
Reset();
}
SettingsHandler::SettingsHandler(const Buffer& buffer)
SettingsHandler::SettingsHandler(const Buffer& buffer) : SettingsHandler()
{
SetBytes(buffer);
m_buffer = buffer;
Decrypt();
}
const SettingsHandler::Buffer& SettingsHandler::GetBytes() const
@ -32,13 +32,6 @@ const SettingsHandler::Buffer& SettingsHandler::GetBytes() const
return m_buffer;
}
void SettingsHandler::SetBytes(const Buffer& buffer)
{
Reset();
m_buffer = buffer;
Decrypt();
}
std::string SettingsHandler::GetValue(std::string_view key) const
{
constexpr char delim[] = "\n";
@ -84,14 +77,6 @@ void SettingsHandler::Decrypt()
std::erase(decoded, '\x0d');
}
void SettingsHandler::Reset()
{
decoded = "";
m_position = 0;
m_key = INITIAL_SEED;
m_buffer = {};
}
void SettingsHandler::AddSetting(std::string_view key, std::string_view value)
{
WriteLine(fmt::format("{}={}\r\n", key, value));

View file

@ -30,14 +30,12 @@ public:
void AddSetting(std::string_view key, std::string_view value);
const Buffer& GetBytes() const;
void SetBytes(const Buffer& buffer);
std::string GetValue(std::string_view key) const;
void Decrypt();
void Reset();
static std::string GenerateSerialNumber();
private:
void Decrypt();
void WriteLine(std::string_view str);
void WriteByte(u8 b);

View file

@ -363,7 +363,6 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
auto entryPos = region_settings.find(SConfig::GetInstance().m_region);
RegionSetting region_setting = entryPos->second;
Common::SettingsHandler gen;
std::string serno;
std::string model = "RVL-001(" + region_setting.area + ")";
CreateSystemMenuTitleDirs();
@ -377,9 +376,9 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
IOS::HLE::FS::Mode::Read);
if (file && file->Read(data.data(), data.size()))
{
gen.SetBytes(data);
serno = gen.GetValue("SERNO");
model = gen.GetValue("MODEL");
Common::SettingsHandler settings_reader(data);
serno = settings_reader.GetValue("SERNO");
model = settings_reader.GetValue("MODEL");
bool region_matches = false;
if (Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS))
@ -388,15 +387,16 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
}
else
{
const std::string code = gen.GetValue("CODE");
const std::string code = settings_reader.GetValue("CODE");
if (code.size() >= 2 && CodeRegion(code[1]) == SConfig::GetInstance().m_region)
region_matches = true;
}
if (region_matches)
{
region_setting = RegionSetting{gen.GetValue("AREA"), gen.GetValue("VIDEO"),
gen.GetValue("GAME"), gen.GetValue("CODE")};
region_setting =
RegionSetting{settings_reader.GetValue("AREA"), settings_reader.GetValue("VIDEO"),
settings_reader.GetValue("GAME"), settings_reader.GetValue("CODE")};
}
else
{
@ -404,8 +404,6 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
if (parenthesis_pos != std::string::npos)
model = model.substr(0, parenthesis_pos) + '(' + region_setting.area + ')';
}
gen.Reset();
}
}
fs->Delete(IOS::SYSMENU_UID, IOS::SYSMENU_GID, settings_file_path);
@ -423,6 +421,7 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
INFO_LOG_FMT(BOOT, "Using serial number: {}", serno);
}
Common::SettingsHandler gen;
gen.AddSetting("AREA", region_setting.area);
gen.AddSetting("MODEL", model);
gen.AddSetting("DVD", "0");

View file

@ -138,8 +138,7 @@ IPCReply GetRealProductCode(Core::System& system, const IOCtlVRequest& request)
if (!file.ReadBytes(data.data(), data.size()))
return IPCReply(IPC_ENOENT);
Common::SettingsHandler gen;
gen.SetBytes(data);
Common::SettingsHandler gen(data);
const std::string code = gen.GetValue("CODE");
const size_t length = std::min<size_t>(request.io_vectors[0].size, code.length());

View file

@ -16,6 +16,7 @@
#endif
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
#include "Common/GekkoDisassembler.h"
#include "Common/IOFile.h"
#include "Common/Logging/Log.h"
@ -1035,6 +1036,30 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
}
else
{
auto& cpu = m_system.GetCPU();
auto& power_pc = m_system.GetPowerPC();
if (m_enable_debugging && power_pc.GetBreakPoints().IsAddressBreakPoint(op.address) &&
!cpu.IsStepping())
{
gpr.Flush();
fpr.Flush();
MOV(32, PPCSTATE(pc), Imm32(op.address));
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionP(PowerPC::CheckBreakPointsFromJIT, &power_pc);
ABI_PopRegistersAndAdjustStack({}, 0);
MOV(64, R(RSCRATCH), ImmPtr(cpu.GetStatePtr()));
CMP(32, MatR(RSCRATCH), Imm32(Common::ToUnderlying(CPU::State::Running)));
FixupBranch noBreakpoint = J_CC(CC_E);
Cleanup();
MOV(32, PPCSTATE(npc), Imm32(op.address));
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
JMP(asm_routines.dispatcher_exit, Jump::Near);
SetJumpTarget(noBreakpoint);
}
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
{
// This instruction uses FPU - needs to add FP exception bailout
@ -1061,30 +1086,6 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.firstFPInstructionFound = true;
}
auto& cpu = m_system.GetCPU();
auto& power_pc = m_system.GetPowerPC();
if (m_enable_debugging && power_pc.GetBreakPoints().IsAddressBreakPoint(op.address) &&
!cpu.IsStepping())
{
gpr.Flush();
fpr.Flush();
MOV(32, PPCSTATE(pc), Imm32(op.address));
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionP(PowerPC::CheckBreakPointsFromJIT, &power_pc);
ABI_PopRegistersAndAdjustStack({}, 0);
MOV(64, R(RSCRATCH), ImmPtr(cpu.GetStatePtr()));
TEST(32, MatR(RSCRATCH), Imm32(0xFFFFFFFF));
FixupBranch noBreakpoint = J_CC(CC_Z);
Cleanup();
MOV(32, PPCSTATE(npc), Imm32(op.address));
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
JMP(asm_routines.dispatcher_exit, Jump::Near);
SetJumpTarget(noBreakpoint);
}
if (bJITRegisterCacheOff)
{
gpr.Flush();

View file

@ -6,6 +6,7 @@
#include <climits>
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
#include "Common/JitRegister.h"
#include "Common/x64ABI.h"
#include "Common/x64Emitter.h"
@ -105,8 +106,8 @@ void Jit64AsmRoutineManager::Generate()
if (enable_debugging)
{
MOV(64, R(RSCRATCH), ImmPtr(system.GetCPU().GetStatePtr()));
TEST(32, MatR(RSCRATCH), Imm32(0xFFFFFFFF));
dbg_exit = J_CC(CC_NZ, Jump::Near);
CMP(32, MatR(RSCRATCH), Imm32(Common::ToUnderlying(CPU::State::Running)));
dbg_exit = J_CC(CC_NE, Jump::Near);
}
SetJumpTarget(skipToRealDispatch);
@ -236,8 +237,8 @@ void Jit64AsmRoutineManager::Generate()
// Check the state pointer to see if we are exiting
// Gets checked on at the end of every slice
MOV(64, R(RSCRATCH), ImmPtr(system.GetCPU().GetStatePtr()));
TEST(32, MatR(RSCRATCH), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop);
CMP(32, MatR(RSCRATCH), Imm32(Common::ToUnderlying(CPU::State::Running)));
J_CC(CC_E, outerLoop);
// Landing pad for drec space
dispatcher_exit = GetCodePtr();

View file

@ -8,6 +8,7 @@
#include "Common/Arm64Emitter.h"
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
#include "Common/Logging/Log.h"
#include "Common/MathUtil.h"
#include "Common/MsgHandler.h"
@ -1239,6 +1240,37 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
}
else
{
if (m_enable_debugging && !cpu.IsStepping() &&
m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(op.address))
{
FlushCarry();
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
static_assert(PPCSTATE_OFF(pc) <= 252);
static_assert(PPCSTATE_OFF(pc) + 4 == PPCSTATE_OFF(npc));
MOVI2R(DISPATCHER_PC, op.address);
STP(IndexType::Signed, DISPATCHER_PC, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
ABI_CallFunction(&PowerPC::CheckBreakPointsFromJIT, &m_system.GetPowerPC());
LDR(IndexType::Unsigned, ARM64Reg::W0, ARM64Reg::X0,
MOVPage2R(ARM64Reg::X0, cpu.GetStatePtr()));
static_assert(Common::ToUnderlying(CPU::State::Running) == 0);
FixupBranch no_breakpoint = CBZ(ARM64Reg::W0);
Cleanup();
if (IsProfilingEnabled())
{
ABI_CallFunction(&JitBlock::ProfileData::EndProfiling, b->profile_data.get(),
js.downcountAmount);
}
DoDownCount();
B(dispatcher_exit);
SetJumpTarget(no_breakpoint);
}
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
{
// This instruction uses FPU - needs to add FP exception bailout
@ -1268,36 +1300,6 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.firstFPInstructionFound = true;
}
if (m_enable_debugging && !cpu.IsStepping() &&
m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(op.address))
{
FlushCarry();
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
static_assert(PPCSTATE_OFF(pc) <= 252);
static_assert(PPCSTATE_OFF(pc) + 4 == PPCSTATE_OFF(npc));
MOVI2R(DISPATCHER_PC, op.address);
STP(IndexType::Signed, DISPATCHER_PC, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
ABI_CallFunction(&PowerPC::CheckBreakPointsFromJIT, &m_system.GetPowerPC());
LDR(IndexType::Unsigned, ARM64Reg::W0, ARM64Reg::X0,
MOVPage2R(ARM64Reg::X0, cpu.GetStatePtr()));
FixupBranch no_breakpoint = CBZ(ARM64Reg::W0);
Cleanup();
if (IsProfilingEnabled())
{
ABI_CallFunction(&JitBlock::ProfileData::EndProfiling, b->profile_data.get(),
js.downcountAmount);
}
DoDownCount();
B(dispatcher_exit);
SetJumpTarget(no_breakpoint);
}
if (bJITRegisterCacheOff)
{
FlushCarry();

View file

@ -9,6 +9,7 @@
#include "Common/Arm64Emitter.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Common/EnumUtils.h"
#include "Common/FloatUtils.h"
#include "Common/JitRegister.h"
#include "Common/MathUtil.h"
@ -88,6 +89,7 @@ void JitArm64::GenerateAsm()
{
LDR(IndexType::Unsigned, ARM64Reg::W8, ARM64Reg::X8,
MOVPage2R(ARM64Reg::X8, cpu.GetStatePtr()));
static_assert(Common::ToUnderlying(CPU::State::Running) == 0);
debug_exit = CBNZ(ARM64Reg::W8);
}
@ -195,6 +197,7 @@ void JitArm64::GenerateAsm()
// Check the state pointer to see if we are exiting
// Gets checked on at the end of every slice
LDR(IndexType::Unsigned, ARM64Reg::W8, ARM64Reg::X8, MOVPage2R(ARM64Reg::X8, cpu.GetStatePtr()));
static_assert(Common::ToUnderlying(CPU::State::Running) == 0);
FixupBranch exit = CBNZ(ARM64Reg::W8);
SetJumpTarget(to_start_of_timing_slice);

View file

@ -75,35 +75,11 @@ TEST(SettingsHandlerTest, DecryptMultipleSettings)
EXPECT_EQ(handler.GetValue("foo"), "bar");
}
TEST(SettingsHandlerTest, SetBytesOverwritesExistingBuffer)
{
Common::SettingsHandler handler(BUFFER_A);
ASSERT_EQ(handler.GetValue("key"), "val");
ASSERT_EQ(handler.GetValue("foo"), "");
handler.SetBytes(BUFFER_B);
EXPECT_EQ(handler.GetValue("foo"), "bar");
EXPECT_EQ(handler.GetValue("key"), "");
}
TEST(SettingsHandlerTest, GetValueOnSameInstance)
{
Common::SettingsHandler handler;
handler.AddSetting("key", "val");
EXPECT_EQ(handler.GetValue("key"), "");
Common::SettingsHandler::Buffer buffer = handler.GetBytes();
handler.SetBytes(buffer);
EXPECT_EQ(handler.GetValue("key"), "val");
}
TEST(SettingsHandlerTest, GetValueAfterReset)
{
Common::SettingsHandler handler(BUFFER_A);
ASSERT_EQ(handler.GetValue("key"), "val");
handler.Reset();
EXPECT_EQ(handler.GetValue("key"), "");
}
TEST(SettingsHandlerTest, EncryptAddsLFOnNullChar)