Skip to content

Commit

Permalink
Improve handling of dangling RAM using status heartbeat
Browse files Browse the repository at this point in the history
  • Loading branch information
aglab2 committed Apr 8, 2023
1 parent c871ec4 commit e2097b2
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 21 deletions.
1 change: 1 addition & 0 deletions Hacktice/Canary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ internal class Canary
public const uint HackticeStatusActive = 0x41435456; // ACTV
public const uint HackticeStatusDisabled = 0x4453424c; // DSBL
public const uint HackticeStatusUpgrading = 0x55504752; // UPGR
public const uint HackticeStatusHeartbeat = 0x48524254; // HRBT
}
}
8 changes: 8 additions & 0 deletions Hacktice/Emulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Hacktice header has 20 bytes in size and consists of
*/
const int HackticeHeaderSize = 20;
private IntPtr? _ptrHackticeHeader;
private IntPtr? _ptrHackticeStatus;
private byte[] _hackticeHeader = new byte[HackticeHeaderSize];
private byte[] _ram; // just a cache

Expand Down Expand Up @@ -297,6 +298,7 @@ public bool RefreshHacktice()
return true;

_ptrHackticeHeader = null;
_ptrHackticeStatus = null;
}

if (!(_ram is object))
Expand All @@ -309,6 +311,7 @@ public bool RefreshHacktice()
{
// attempt all locations and find if any is reasonable
_ptrHackticeHeader = new IntPtr((long)(_ramPtrBase + (ulong)location));
_ptrHackticeStatus = new IntPtr((long)(_ramPtrBase + (ulong)location + 8));
if (RefreshHackticeHeaderAndCheckIfValid())
return true;
}
Expand Down Expand Up @@ -438,5 +441,10 @@ public void FixSapphireTimer()
_process.WriteBytes(new IntPtr((long)(_ramPtrBase + 0x2E3A4C)), new byte[] { 0xf9, 0x00 });
_process.WriteBytes(new IntPtr((long)(_ramPtrBase + 0x2E3A34)), new byte[] { 0xe5, 0x00 });
}

public void WriteStatus(uint status)
{
_process.WriteBytes(_ptrHackticeStatus.Value, BitConverter.GetBytes(status));
}
}
}
66 changes: 45 additions & 21 deletions Hacktice/Tool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ enum State
};

const string SapphireEEPROMName = "SM64 Sapphire";
const int MaxBeatsToCheck = 200;
const int HeartbeatLeaveaway = 10;

readonly System.Threading.Timer _timer;

Expand All @@ -34,10 +36,11 @@ enum State
readonly Emulator _emulator = new Emulator();
readonly Version _payloadVersion;
Config _lastSeenEmulatorConfig = new Config();
int _heartbeatActive = 0;
private State EmulatorState
{
get { return _stateValue; }
set { var oldValue = _stateValue; _stateValue = value; if (oldValue != _stateValue) { UpdateEmulatorState(); } }
set { var oldValue = _stateValue; _stateValue = value; if (oldValue != _stateValue) { _heartbeatActive = 0; UpdateEmulatorState(); } }
}

// Used from UI thread to avoid event loops
Expand Down Expand Up @@ -318,30 +321,44 @@ private void PrepareHacktice()
if (!_emulator.RefreshHacktice())
return;

newState = State.HACKTICE_CORRUPTED;
if (_heartbeatActive >= 0)
{
int status = _emulator.HackticeStatus;
if (status == Canary.HackticeStatusInit)
newState = State.HACKTICE_CORRUPTED;
{
newState = State.HACKTICE_INJECTED;
return;
}
if (status == Canary.HackticeStatusActive)
{
newState = _emulator.HackticeVersion == _payloadVersion ? State.HACKTICE_RUNNING : State.HACKTICE_RUNNING_CAN_UPGRADE;
return;
}
if (status == Canary.HackticeStatusDisabled)
{
newState = State.HACKTICE_UPGRADE_DISABLED;
return;
}
if (status == Canary.HackticeStatusUpgrading)
{
newState = State.HACKTICE_UPGRADE_DATA_WRITTEN;
return;
int status = _emulator.HackticeStatus;
if (status == Canary.HackticeStatusInit)
{
newState = State.HACKTICE_INJECTED;
return;
}
if (status == Canary.HackticeStatusHeartbeat)
{
newState = State.ROM;
return;
}
if (status == Canary.HackticeStatusActive)
{
newState = _emulator.HackticeVersion == _payloadVersion ? State.HACKTICE_RUNNING : State.HACKTICE_RUNNING_CAN_UPGRADE;
return;
}
if (status == Canary.HackticeStatusDisabled)
{
newState = State.HACKTICE_UPGRADE_DISABLED;
return;
}
if (status == Canary.HackticeStatusUpgrading)
{
newState = State.HACKTICE_UPGRADE_DATA_WRITTEN;
return;
}
}
}
else
{
// there is a bit of leaveaway before we start complaining that hacktice does not run
newState = State.HACKTICE_RUNNING;
return;
}
}
finally
{
Expand Down Expand Up @@ -407,6 +424,13 @@ private void EmulatorStateUpdate(object state)

if (EmulatorState >= State.HACKTICE_RUNNING)
{
_heartbeatActive++;
if (_heartbeatActive >= MaxBeatsToCheck)
{
_emulator.WriteStatus(Canary.HackticeStatusHeartbeat);
_heartbeatActive = -HeartbeatLeaveaway;
}

var userUpdatedConfig = NeedToUpdateConfig;

// TODO: This logic gets complicated, separate this away
Expand Down

0 comments on commit e2097b2

Please sign in to comment.