Skip to content

Commit

Permalink
Move FilePatch Functality to a volume wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
phire committed Apr 24, 2019
1 parent 45600e2 commit 6f9c4f2
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 102 deletions.
9 changes: 5 additions & 4 deletions Source/Core/Core/Boot/Boot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace fs = std::experimental::filesystem;
#include "Core/FifoPlayer/FifoPlayer.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/DVD/DVDThread.h"
#include "Core/HW/EXI/EXI_DeviceIPL.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h"
Expand Down Expand Up @@ -221,9 +222,8 @@ BootParameters::IPL::IPL(DiscIO::Region region_, Disc&& disc_) : IPL(region_)
static const DiscIO::Volume* SetDisc(std::unique_ptr<DiscIO::Volume> volume,
std::vector<std::string> auto_disc_change_paths = {})
{
const DiscIO::Volume* pointer = volume.get();
DVDInterface::SetDisc(std::move(volume), auto_disc_change_paths);
return pointer;
return DVDThread::GetDiscVolume();
}

bool CBoot::DVDRead(const DiscIO::Volume& volume, u64 dvd_offset, u32 output_address, u32 length,
Expand Down Expand Up @@ -386,6 +386,9 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
VideoInterface::Preset(DiscIO::IsNTSC(config.m_region) ||
(config.bWii && Config::Get(Config::SYSCONF_PAL60)));

// Must load the patches before setting any discs.
PatchEngine::LoadPatches();

struct BootTitle
{
BootTitle() : config(SConfig::GetInstance()) {}
Expand Down Expand Up @@ -505,8 +508,6 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
const SConfig& config;
};

PatchEngine::LoadPatches();

if (!std::visit(BootTitle(), boot->parameters))
return false;

Expand Down
53 changes: 13 additions & 40 deletions Source/Core/Core/HW/DVD/DVDThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "Core/PatchEngine.h"

#include "DiscIO/Enums.h"
#include "DiscIO/OverlayVolume.h"
#include "DiscIO/Volume.h"

namespace DVDThread
Expand Down Expand Up @@ -179,11 +180,21 @@ void DoState(PointerWrap& p)

void SetDisc(std::unique_ptr<DiscIO::Volume> disc)
{
// Apply any file patches
auto filePatches = PatchEngine::GetFilePatches();
if (!filePatches.empty() && disc)
{
disc = std::make_unique<DiscIO::OverlayVolume>(std::move(disc), filePatches);
}

WaitUntilIdle();
s_disc = std::move(disc);
}

// Apply any file patches
s_disc_patches = PatchEngine::CalculateDiscPatches(*s_disc);
// UGLY, but at least this makes it obvious what is actually happening.
DiscIO::Volume* GetDiscVolume()
{
return s_disc.get();
}

bool HasDisc()
Expand Down Expand Up @@ -363,42 +374,6 @@ static void FinishRead(u64 id, s64 cycles_late)
buffer);
}

static void PatchReadRequest(std::vector<u8>& buffer, u64 offset)
{
u64 end_offset = offset + buffer.size();

// Scan through patches which might overlap our current read request and apply them

// Because the patches are variably sized, we scan in reverse order to take advantage
// of upper_bound, which gives us the first patch that starts after the read buffer.
auto it = s_disc_patches.upper_bound(end_offset);

while (it-- != s_disc_patches.begin()) // Loop backwards until start of s_disc_patches
{
if (it->first + it->second.size() < offset)
{
// Patch is before the read request, we can stop searching
return;
}
else if (it->first >= offset)
{
// Patch starts inside the read request
u64 start = it->first - offset;
std::memmove(buffer.data() + start, it->second.data(),
std::min(it->second.size(), buffer.size() - start));
INFO_LOG(DVDINTERFACE, "patch applied at %08llux", offset + start);
}
else if (it->first + it->second.size() > offset)
{
// Patch overlaps with the start of the read request
u64 start = offset - it->first;
std::memmove(buffer.data(), it->second.data() + start,
std::min(it->second.size() - start, buffer.size()));
INFO_LOG(DVDINTERFACE, "patch applied at %08llux", offset);
}
}
}

static void DVDThread()
{
Common::SetCurrentThreadName("DVD thread");
Expand All @@ -418,8 +393,6 @@ static void DVDThread()
std::vector<u8> buffer(request.length);
if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
buffer.resize(0);
else
PatchReadRequest(buffer, request.dvd_offset);

request.realtime_done_us = Common::Timer::GetTimeUs();

Expand Down
9 changes: 5 additions & 4 deletions Source/Core/Core/HW/DVD/DVDThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ namespace DiscIO
{
enum class Platform;
class Volume;
}
} // namespace DiscIO
namespace IOS
{
namespace ES
{
class TMDReader;
class TicketReader;
}
}
} // namespace ES
} // namespace IOS

namespace DVDThread
{
Expand All @@ -40,6 +40,7 @@ void Stop();
void DoState(PointerWrap& p);

void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
DiscIO::Volume* GetDiscVolume();
bool HasDisc();

bool IsEncryptedAndHashed();
Expand All @@ -60,4 +61,4 @@ void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
const DiscIO::Partition& partition, DVDInterface::ReplyType reply_type,
s64 ticks_until_completion);
}
} // namespace DVDThread
56 changes: 5 additions & 51 deletions Source/Core/Core/PatchEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ static std::vector<Patch> s_on_frame;
static std::vector<Patch> s_file_patches;
static std::map<u32, int> s_speed_hacks;

std::vector<Patch>& GetFilePatches()
{
return s_file_patches;
}

const char* PatchTypeAsString(PatchType type)
{
return s_patch_type_strings.at(static_cast<int>(type));
Expand Down Expand Up @@ -226,57 +231,6 @@ static void ApplyPatches(const std::vector<Patch>& patches)
}
}

std::map<u64, std::vector<u8>> CalculateDiscPatches(const DiscIO::Volume& disc)
{
auto partition = disc.GetGamePartition();
const DiscIO::FileSystem* fs = disc.GetFileSystem(partition);

auto patches = std::map<u64, std::vector<u8>>();

for (const auto& patch : s_file_patches)
{
if (!patch.active)
continue;

const auto& file = fs->FindFileInfo(patch.path);
if (file)
{
for (const auto& entry : patch.entries)
{
u64 disc_offset =
disc.PartitionOffsetToRawOffset(file->GetOffset(), partition) + entry.address;
std::vector<u8> data;
switch (entry.type)
{
case PatchType::Patch32Bit:
data.push_back(static_cast<u8>(entry.value >> 24));
data.push_back(static_cast<u8>(entry.value >> 16));
// [[fallthrough]];
case PatchType::Patch16Bit:
data.push_back(static_cast<u8>(entry.value >> 8));
// [[fallthrough]];
case PatchType::Patch8Bit:
data.push_back(static_cast<u8>(entry.value));
break;
default:
// unknown patch type
// In the future we could add support for larger patch entries.

// Downstream code deals with vectors of bytes which could be arbitrary length
break;
}
patches.emplace(disc_offset, data);
}

INFO_LOG(ACTIONREPLAY, "Applied patch '%s' to file '%s'", patch.name.c_str(),
patch.path.c_str());
}
}

// Return null
return patches;
}

// Requires MSR.DR, MSR.IR
// There's no perfect way to do this, it's just a heuristic.
// We require at least 2 stack frames, if the stack is shallower than that then it won't work.
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/PatchEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct Patch
const char* PatchTypeAsString(PatchType type);

int GetSpeedhackCycles(const u32 addr);
std::map<u64, std::vector<u8>> CalculateDiscPatches(const DiscIO::Volume& disc);
std::vector<Patch>& GetFilePatches();
void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, IniFile& globalIni,
IniFile& localIni);
void LoadPatches();
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DiscIO/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_library(discio
FileSystemGCWii.cpp
Filesystem.cpp
NANDImporter.cpp
OverlayVolume.cpp
TGCBlob.cpp
Volume.cpp
VolumeFileBlobReader.cpp
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DiscIO/DiscIO.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<ClCompile Include="Filesystem.cpp" />
<ClCompile Include="FileSystemGCWii.cpp" />
<ClCompile Include="NANDImporter.cpp" />
<ClCompile Include="OverlayVolume.cpp" />
<ClCompile Include="TGCBlob.cpp" />
<ClCompile Include="Volume.cpp" />
<ClCompile Include="VolumeFileBlobReader.cpp" />
Expand All @@ -71,6 +72,7 @@
<ClInclude Include="Filesystem.h" />
<ClInclude Include="FileSystemGCWii.h" />
<ClInclude Include="NANDImporter.h" />
<ClInclude Include="OverlayVolume.h" />
<ClInclude Include="TGCBlob.h" />
<ClInclude Include="Volume.h" />
<ClInclude Include="VolumeFileBlobReader.h" />
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/DiscIO/DiscIO.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
<ClCompile Include="VolumeFileBlobReader.cpp">
<Filter>Volume</Filter>
</ClCompile>
<ClCompile Include="OverlayVolume.cpp">
<Filter>Volume</Filter>
</ClCompile>
<ClCompile Include="VolumeGC.cpp">
<Filter>Volume</Filter>
</ClCompile>
Expand Down Expand Up @@ -119,6 +122,9 @@
<ClInclude Include="WbfsBlob.h">
<Filter>Volume\Blob</Filter>
</ClInclude>
<ClInclude Include="OverlayVolume.h">
<Filter>Volume</Filter>
</ClInclude>
<ClInclude Include="Volume.h">
<Filter>Volume</Filter>
</ClInclude>
Expand Down
113 changes: 113 additions & 0 deletions Source/Core/DiscIO/OverlayVolume.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <algorithm>
#include <inttypes.h>

#include "Core/PatchEngine.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/OverlayVolume.h"

namespace DiscIO
{
std::map<u64, std::vector<u8>>
OverlayVolume::CalculateDiscOffsets(Volume& disc, std::vector<PatchEngine::Patch>& patches)
{
auto partition = disc.GetGamePartition();
const DiscIO::FileSystem* fs = disc.GetFileSystem(partition);

auto offsets = std::map<u64, std::vector<u8>>();

for (const auto& patch : patches)
{
if (!patch.active)
continue;

const auto& file = fs->FindFileInfo(patch.path);
if (file)
{
for (const auto& entry : patch.entries)
{
u64 partition_offset = file->GetOffset() + entry.address;
std::vector<u8> data;
switch (entry.type)
{
case PatchEngine::PatchType::Patch32Bit:
data.push_back(static_cast<u8>(entry.value >> 24));
data.push_back(static_cast<u8>(entry.value >> 16));
// [[fallthrough]];
case PatchEngine::PatchType::Patch16Bit:
data.push_back(static_cast<u8>(entry.value >> 8));
// [[fallthrough]];
case PatchEngine::PatchType::Patch8Bit:
data.push_back(static_cast<u8>(entry.value));
break;
default:
// unknown patch type
// In the future we could add support for larger patch entries.

// Downstream code deals with vectors of bytes which could be arbitrary length
break;
}
offsets.emplace(partition_offset, data);
}

INFO_LOG(ACTIONREPLAY, "Applied patch '%s' to file '%s'", patch.name.c_str(),
patch.path.c_str());
}
}

return offsets;
}

static void applyPatchesToBuffer(u64 offset, u64 length, u8* buffer,
std::map<u64, std::vector<u8>> patches)
{
u64 end_offset = offset + length;

// Scan through patches which might overlap our current read request and apply them

// Because the patches are variably sized, we scan in reverse order to take advantage
// of upper_bound, which gives us the first patch that starts after the read buffer.
auto it = patches.upper_bound(end_offset);

while (it-- != patches.begin()) // Loop backwards until start of s_disc_patches
{
if (it->first + it->second.size() < offset)
{
// Patch is before the read request, we can stop searching
return;
}
else if (it->first >= offset)
{
// Patch starts inside the read request
u64 start = it->first - offset;
std::memmove(buffer + start, it->second.data(), std::min(it->second.size(), length - start));
INFO_LOG(DVDINTERFACE, "patch applied at %08" PRIx64, offset + start);
}
else if (it->first + it->second.size() > offset)
{
// Patch overlaps with the start of the read request
u64 start = offset - it->first;
std::memmove(buffer, it->second.data() + start, std::min(it->second.size() - start, length));
INFO_LOG(DVDINTERFACE, "patch applied at %08" PRIx64, offset);
}
}
}

bool OverlayVolume::Read(u64 offset, u64 length, u8* buffer, const Partition& partition) const
{
if (inner->Read(offset, length, buffer, partition))
{
if (partition ==
inner->GetGamePartition()) // Currently we only support patching the game partition
{
applyPatchesToBuffer(offset, length, buffer, patchOffsets);
}
return true;
}
return false;
}

} // namespace DiscIO
Loading

0 comments on commit 6f9c4f2

Please sign in to comment.