Merge pull request #4981 from leoetlino/es-title-handling
IOS/ES: Proper active title tracking (+ neat accidental fixes)
This commit is contained in:
commit
4e062d1bf6
|
@ -278,8 +278,6 @@ bool CBoot::BootUp()
|
||||||
PanicAlertT("Warning - starting ISO in wrong console mode!");
|
PanicAlertT("Warning - starting ISO in wrong console mode!");
|
||||||
}
|
}
|
||||||
|
|
||||||
IOS::HLE::ES_DIVerify(pVolume.GetTMD());
|
|
||||||
|
|
||||||
_StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::Platform::WII_DISC;
|
_StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::Platform::WII_DISC;
|
||||||
|
|
||||||
// HLE BS2 or not
|
// HLE BS2 or not
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "Core/HW/DVDInterface.h"
|
#include "Core/HW/DVDInterface.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
|
#include "Core/IOS/ES/ES.h"
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
#include "Core/IOS/IPC.h"
|
#include "Core/IOS/IPC.h"
|
||||||
#include "Core/PatchEngine.h"
|
#include "Core/PatchEngine.h"
|
||||||
|
@ -311,6 +312,11 @@ bool CBoot::EmulatedBS2_Wii()
|
||||||
if (DVDInterface::GetVolume().GetVolumeType() != DiscIO::Platform::WII_DISC)
|
if (DVDInterface::GetVolume().GetVolumeType() != DiscIO::Platform::WII_DISC)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD();
|
||||||
|
|
||||||
|
if (!SetupWiiMemory(tmd.GetIOSId()))
|
||||||
|
return false;
|
||||||
|
|
||||||
// This is some kind of consistency check that is compared to the 0x00
|
// This is some kind of consistency check that is compared to the 0x00
|
||||||
// values as the game boots. This location keeps the 4 byte ID for as long
|
// values as the game boots. This location keeps the 4 byte ID for as long
|
||||||
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
||||||
|
@ -346,11 +352,6 @@ bool CBoot::EmulatedBS2_Wii()
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
||||||
|
|
||||||
IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD();
|
|
||||||
|
|
||||||
if (!SetupWiiMemory(tmd.GetIOSId()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Execute the apploader
|
// Execute the apploader
|
||||||
const u32 apploader_offset = 0x2440; // 0x1c40;
|
const u32 apploader_offset = 0x2440; // 0x1c40;
|
||||||
|
|
||||||
|
@ -383,11 +384,7 @@ bool CBoot::EmulatedBS2_Wii()
|
||||||
PowerPC::ppcState.gpr[3] = 0x81300000;
|
PowerPC::ppcState.gpr[3] = 0x81300000;
|
||||||
RunFunction(iAppLoaderInit);
|
RunFunction(iAppLoaderInit);
|
||||||
|
|
||||||
// Let the apploader load the exe to memory. At this point I get an unknown IPC command
|
// Let the apploader load the exe to memory
|
||||||
// (command zero) when I load Wii Sports or other games a second time. I don't notice
|
|
||||||
// any side effects however. It's a little disconcerting however that Start after Stop
|
|
||||||
// behaves differently than the first Start after starting Dolphin. It means something
|
|
||||||
// was not reset correctly.
|
|
||||||
DEBUG_LOG(BOOT, "Run iAppLoaderMain");
|
DEBUG_LOG(BOOT, "Run iAppLoaderMain");
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -410,8 +407,7 @@ bool CBoot::EmulatedBS2_Wii()
|
||||||
DEBUG_LOG(BOOT, "Run iAppLoaderClose");
|
DEBUG_LOG(BOOT, "Run iAppLoaderClose");
|
||||||
RunFunction(iAppLoaderClose);
|
RunFunction(iAppLoaderClose);
|
||||||
|
|
||||||
// Load patches and run startup patches
|
IOS::HLE::Device::ES::DIVerify(tmd, DVDInterface::GetVolume().GetTicket());
|
||||||
PatchEngine::LoadPatches();
|
|
||||||
|
|
||||||
// return
|
// return
|
||||||
PC = PowerPC::ppcState.gpr[3];
|
PC = PowerPC::ppcState.gpr[3];
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
|
|
||||||
#include "Core/Boot/Boot.h"
|
#include "Core/Boot/Boot.h"
|
||||||
|
#include "Core/IOS/ES/ES.h"
|
||||||
#include "Core/IOS/FS/FileIO.h"
|
#include "Core/IOS/FS/FileIO.h"
|
||||||
#include "Core/IOS/IPC.h"
|
#include "Core/IOS/IPC.h"
|
||||||
#include "Core/PatchEngine.h"
|
#include "Core/PatchEngine.h"
|
||||||
|
@ -87,7 +88,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
|
||||||
if (!SetupWiiMemory(ContentLoader.GetTMD().GetIOSId()))
|
if (!SetupWiiMemory(ContentLoader.GetTMD().GetIOSId()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
IOS::HLE::SetDefaultContentFile(_pFilename);
|
IOS::HLE::Device::ES::LoadWAD(_pFilename);
|
||||||
if (!IOS::HLE::BootstrapPPC(ContentLoader))
|
if (!IOS::HLE::BootstrapPPC(ContentLoader))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include "Core/HW/DVDInterface.h"
|
#include "Core/HW/DVDInterface.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/IOS/DI/DI.h"
|
#include "Core/IOS/DI/DI.h"
|
||||||
|
#include "Core/IOS/ES/ES.h"
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
#include "Core/IOS/IPC.h"
|
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
namespace IOS
|
namespace IOS
|
||||||
|
@ -106,10 +106,10 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request)
|
||||||
INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset);
|
INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset);
|
||||||
|
|
||||||
// Read TMD to the buffer
|
// Read TMD to the buffer
|
||||||
const ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD();
|
const IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD();
|
||||||
const std::vector<u8> raw_tmd = tmd.GetRawTMD();
|
const std::vector<u8> raw_tmd = tmd.GetRawTMD();
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
|
||||||
ES_DIVerify(tmd);
|
ES::DIVerify(tmd, DVDInterface::GetVolume().GetTicket());
|
||||||
|
|
||||||
return_value = 1;
|
return_value = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,17 +20,22 @@
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
|
#include "Core/Boot/Boot.h"
|
||||||
#include "Core/Boot/Boot_DOL.h"
|
#include "Core/Boot/Boot_DOL.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
#include "Core/HLE/HLE.h"
|
||||||
#include "Core/HW/DVDInterface.h"
|
#include "Core/HW/DVDInterface.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/IOS/ES/ES.h"
|
#include "Core/IOS/ES/ES.h"
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
|
#include "Core/PatchEngine.h"
|
||||||
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/WiiRoot.h"
|
#include "Core/WiiRoot.h"
|
||||||
#include "Core/ec_wii.h"
|
#include "Core/ec_wii.h"
|
||||||
#include "DiscIO/NANDContentLoader.h"
|
#include "DiscIO/NANDContentLoader.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
#include "VideoCommon/HiresTextures.h"
|
||||||
|
|
||||||
namespace IOS
|
namespace IOS
|
||||||
{
|
{
|
||||||
|
@ -38,7 +43,27 @@ namespace HLE
|
||||||
{
|
{
|
||||||
namespace Device
|
namespace Device
|
||||||
{
|
{
|
||||||
std::string ES::m_ContentFile;
|
struct TitleContext
|
||||||
|
{
|
||||||
|
void Clear();
|
||||||
|
void DoState(PointerWrap& p);
|
||||||
|
void Update(const DiscIO::CNANDContentLoader& content_loader);
|
||||||
|
void Update(const IOS::ES::TMDReader& tmd_, const IOS::ES::TicketReader& ticket_);
|
||||||
|
void UpdateRunningGame() const;
|
||||||
|
|
||||||
|
IOS::ES::TicketReader ticket;
|
||||||
|
IOS::ES::TMDReader tmd;
|
||||||
|
bool active = false;
|
||||||
|
bool first_change = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Shared across all ES instances.
|
||||||
|
static std::string s_content_file;
|
||||||
|
static std::vector<u64> s_title_ids;
|
||||||
|
static TitleContext s_title_context;
|
||||||
|
|
||||||
|
// Title to launch after IOS has been reset and reloaded (similar to /sys/launch.sys).
|
||||||
|
static u64 s_title_to_launch;
|
||||||
|
|
||||||
constexpr u8 s_key_sd[0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08,
|
constexpr u8 s_key_sd[0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08,
|
||||||
0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d};
|
0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d};
|
||||||
|
@ -67,9 +92,111 @@ ES::ES(u32 device_id, const std::string& device_name) : Device(device_id, device
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ES::Init()
|
||||||
|
{
|
||||||
|
s_content_file = "";
|
||||||
|
s_title_context = TitleContext{};
|
||||||
|
|
||||||
|
s_title_ids.clear();
|
||||||
|
DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT};
|
||||||
|
uid_sys.GetTitleIDs(s_title_ids);
|
||||||
|
|
||||||
|
// uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented
|
||||||
|
// s_title_idsOwned.clear();
|
||||||
|
// DiscIO::cUIDsys::AccessInstance().GetTitleIDs(s_title_idsOwned, true);
|
||||||
|
|
||||||
|
if (s_title_to_launch != 0)
|
||||||
|
{
|
||||||
|
NOTICE_LOG(IOS, "Re-launching title after IOS reload.");
|
||||||
|
LaunchTitle(s_title_to_launch, true);
|
||||||
|
s_title_to_launch = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleContext::Clear()
|
||||||
|
{
|
||||||
|
ticket.SetBytes({});
|
||||||
|
tmd.SetBytes({});
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleContext::DoState(PointerWrap& p)
|
||||||
|
{
|
||||||
|
ticket.DoState(p);
|
||||||
|
tmd.DoState(p);
|
||||||
|
p.Do(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleContext::Update(const DiscIO::CNANDContentLoader& content_loader)
|
||||||
|
{
|
||||||
|
if (!content_loader.IsValid())
|
||||||
|
return;
|
||||||
|
Update(content_loader.GetTMD(), content_loader.GetTicket());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleContext::Update(const IOS::ES::TMDReader& tmd_, const IOS::ES::TicketReader& ticket_)
|
||||||
|
{
|
||||||
|
if (!tmd_.IsValid() || !ticket_.IsValid())
|
||||||
|
{
|
||||||
|
ERROR_LOG(IOS_ES, "TMD or ticket is not valid -- refusing to update title context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket = ticket_;
|
||||||
|
tmd = tmd_;
|
||||||
|
active = true;
|
||||||
|
|
||||||
|
// Interesting title changes (channel or disc game launch) always happen after an IOS reload.
|
||||||
|
if (first_change)
|
||||||
|
{
|
||||||
|
UpdateRunningGame();
|
||||||
|
first_change = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleContext::UpdateRunningGame() const
|
||||||
|
{
|
||||||
|
// This one does not always make sense for Wii titles, so let's reset it back to a sane value.
|
||||||
|
SConfig::GetInstance().m_strName = "";
|
||||||
|
if (IOS::ES::IsTitleType(tmd.GetTitleId(), IOS::ES::TitleType::Game) ||
|
||||||
|
IOS::ES::IsTitleType(tmd.GetTitleId(), IOS::ES::TitleType::GameWithChannel))
|
||||||
|
{
|
||||||
|
const u32 title_identifier = Common::swap32(static_cast<u32>(tmd.GetTitleId()));
|
||||||
|
const u16 group_id = Common::swap16(tmd.GetGroupId());
|
||||||
|
|
||||||
|
char ascii_game_id[6];
|
||||||
|
std::memcpy(ascii_game_id, &title_identifier, sizeof(title_identifier));
|
||||||
|
std::memcpy(ascii_game_id + sizeof(title_identifier), &group_id, sizeof(group_id));
|
||||||
|
|
||||||
|
SConfig::GetInstance().m_strGameID = ascii_game_id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SConfig::GetInstance().m_strGameID = StringFromFormat("%016" PRIX64, tmd.GetTitleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
SConfig::GetInstance().m_title_id = tmd.GetTitleId();
|
||||||
|
|
||||||
|
// TODO: have a callback mechanism for title changes?
|
||||||
|
g_symbolDB.Clear();
|
||||||
|
CBoot::LoadMapFromFilename();
|
||||||
|
::HLE::Clear();
|
||||||
|
::HLE::PatchFunctions();
|
||||||
|
PatchEngine::Shutdown();
|
||||||
|
PatchEngine::LoadPatches();
|
||||||
|
HiresTexture::Update();
|
||||||
|
|
||||||
|
NOTICE_LOG(IOS_ES, "Active title: %016" PRIx64, tmd.GetTitleId());
|
||||||
|
}
|
||||||
|
|
||||||
void ES::LoadWAD(const std::string& _rContentFile)
|
void ES::LoadWAD(const std::string& _rContentFile)
|
||||||
{
|
{
|
||||||
m_ContentFile = _rContentFile;
|
s_content_file = _rContentFile;
|
||||||
|
// XXX: Ideally, this should be done during a launch, but because we support launching WADs
|
||||||
|
// without installing them (which is a bit of a hack), we have to do this manually here.
|
||||||
|
const auto& content_loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(s_content_file);
|
||||||
|
s_title_context.Update(content_loader);
|
||||||
|
INFO_LOG(IOS_ES, "LoadWAD: Title context changed: %016" PRIx64, s_title_context.tmd.GetTitleId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ES::DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output)
|
void ES::DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output)
|
||||||
|
@ -80,8 +207,11 @@ void ES::DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv,
|
||||||
mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, size, new_iv, input, output);
|
mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, size, new_iv, input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ES::LaunchTitle(u64 title_id, bool skip_reload) const
|
bool ES::LaunchTitle(u64 title_id, bool skip_reload)
|
||||||
{
|
{
|
||||||
|
s_title_context.Clear();
|
||||||
|
INFO_LOG(IOS_ES, "ES_Launch: Title context changed: (none)");
|
||||||
|
|
||||||
NOTICE_LOG(IOS_ES, "Launching title %016" PRIx64 "...", title_id);
|
NOTICE_LOG(IOS_ES, "Launching title %016" PRIx64 "...", title_id);
|
||||||
|
|
||||||
// ES_Launch should probably reset the whole state, which at least means closing all open files.
|
// ES_Launch should probably reset the whole state, which at least means closing all open files.
|
||||||
|
@ -94,12 +224,12 @@ bool ES::LaunchTitle(u64 title_id, bool skip_reload) const
|
||||||
return LaunchPPCTitle(title_id, skip_reload);
|
return LaunchPPCTitle(title_id, skip_reload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ES::LaunchIOS(u64 ios_title_id) const
|
bool ES::LaunchIOS(u64 ios_title_id)
|
||||||
{
|
{
|
||||||
return Reload(ios_title_id);
|
return Reload(ios_title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) const
|
bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload)
|
||||||
{
|
{
|
||||||
const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id);
|
const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id);
|
||||||
if (!content_loader.IsValid())
|
if (!content_loader.IsValid())
|
||||||
|
@ -115,52 +245,24 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) const
|
||||||
// again with the reload skipped, and the PPC will be bootstrapped then.
|
// again with the reload skipped, and the PPC will be bootstrapped then.
|
||||||
if (!skip_reload)
|
if (!skip_reload)
|
||||||
{
|
{
|
||||||
SetTitleToLaunch(title_id);
|
s_title_to_launch = title_id;
|
||||||
const u64 required_ios = content_loader.GetTMD().GetIOSId();
|
const u64 required_ios = content_loader.GetTMD().GetIOSId();
|
||||||
return LaunchTitle(required_ios);
|
return LaunchTitle(required_ios);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDefaultContentFile(Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT));
|
s_title_context.Update(content_loader);
|
||||||
|
INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64,
|
||||||
|
s_title_context.tmd.GetTitleId());
|
||||||
return BootstrapPPC(content_loader);
|
return BootstrapPPC(content_loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ES::OpenInternal()
|
|
||||||
{
|
|
||||||
auto& contentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
|
|
||||||
|
|
||||||
// check for cd ...
|
|
||||||
if (contentLoader.IsValid())
|
|
||||||
{
|
|
||||||
m_TitleID = contentLoader.GetTMD().GetTitleId();
|
|
||||||
|
|
||||||
m_TitleIDs.clear();
|
|
||||||
DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT};
|
|
||||||
uid_sys.GetTitleIDs(m_TitleIDs);
|
|
||||||
// uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented
|
|
||||||
// m_TitleIDsOwned.clear();
|
|
||||||
// DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDsOwned, true);
|
|
||||||
}
|
|
||||||
else if (DVDInterface::VolumeIsValid())
|
|
||||||
{
|
|
||||||
// blindly grab the titleID from the disc - it's unencrypted at:
|
|
||||||
// offset 0x0F8001DC and 0x0F80044C
|
|
||||||
DVDInterface::GetVolume().GetTitleID(&m_TitleID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
INFO_LOG(IOS_ES, "Set default title to %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ES::DoState(PointerWrap& p)
|
void ES::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
Device::DoState(p);
|
Device::DoState(p);
|
||||||
p.Do(m_ContentFile);
|
p.Do(s_content_file);
|
||||||
OpenInternal();
|
|
||||||
p.Do(m_AccessIdentID);
|
p.Do(m_AccessIdentID);
|
||||||
p.Do(m_TitleIDs);
|
p.Do(s_title_ids);
|
||||||
|
s_title_context.DoState(p);
|
||||||
|
|
||||||
m_addtitle_tmd.DoState(p);
|
m_addtitle_tmd.DoState(p);
|
||||||
p.Do(m_addtitle_content_id);
|
p.Do(m_addtitle_content_id);
|
||||||
|
@ -197,8 +299,6 @@ void ES::DoState(PointerWrap& p)
|
||||||
|
|
||||||
ReturnCode ES::Open(const OpenRequest& request)
|
ReturnCode ES::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
OpenInternal();
|
|
||||||
|
|
||||||
if (m_is_active)
|
if (m_is_active)
|
||||||
INFO_LOG(IOS_ES, "Device was re-opened.");
|
INFO_LOG(IOS_ES, "Device was re-opened.");
|
||||||
return Device::Open(request);
|
return Device::Open(request);
|
||||||
|
@ -206,9 +306,8 @@ ReturnCode ES::Open(const OpenRequest& request)
|
||||||
|
|
||||||
void ES::Close()
|
void ES::Close()
|
||||||
{
|
{
|
||||||
|
// XXX: does IOS really clear the content access map here?
|
||||||
m_ContentAccessMap.clear();
|
m_ContentAccessMap.clear();
|
||||||
m_TitleIDs.clear();
|
|
||||||
m_TitleID = -1;
|
|
||||||
m_AccessIdentID = 0;
|
m_AccessIdentID = 0;
|
||||||
|
|
||||||
INFO_LOG(IOS_ES, "ES: Close");
|
INFO_LOG(IOS_ES, "ES: Close");
|
||||||
|
@ -628,7 +727,10 @@ IPCCommandResult ES::OpenContent(const IOCtlVRequest& request)
|
||||||
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||||
u32 Index = Memory::Read_U32(request.in_vectors[0].address);
|
u32 Index = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
|
|
||||||
s32 CFD = OpenTitleContent(m_AccessIdentID++, m_TitleID, Index);
|
if (!s_title_context.active)
|
||||||
|
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||||
|
|
||||||
|
s32 CFD = OpenTitleContent(m_AccessIdentID++, s_title_context.tmd.GetTitleId(), Index);
|
||||||
INFO_LOG(IOS_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
|
INFO_LOG(IOS_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
|
||||||
|
|
||||||
return GetDefaultReply(CFD);
|
return GetDefaultReply(CFD);
|
||||||
|
@ -771,8 +873,13 @@ IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request)
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||||
|
|
||||||
Memory::Write_U64(m_TitleID, request.io_vectors[0].address);
|
if (!s_title_context.active)
|
||||||
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID);
|
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||||
|
|
||||||
|
const u64 title_id = s_title_context.tmd.GetTitleId();
|
||||||
|
Memory::Write_U64(title_id, request.io_vectors[0].address);
|
||||||
|
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", static_cast<u32>(title_id >> 32),
|
||||||
|
static_cast<u32>(title_id));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,9 +899,9 @@ IPCCommandResult ES::GetTitleCount(const IOCtlVRequest& request)
|
||||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
|
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
|
||||||
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||||
|
|
||||||
Memory::Write_U32((u32)m_TitleIDs.size(), request.io_vectors[0].address);
|
Memory::Write_U32((u32)s_title_ids.size(), request.io_vectors[0].address);
|
||||||
|
|
||||||
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %zu", m_TitleIDs.size());
|
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %zu", s_title_ids.size());
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -806,11 +913,11 @@ IPCCommandResult ES::GetTitles(const IOCtlVRequest& request)
|
||||||
|
|
||||||
u32 MaxCount = Memory::Read_U32(request.in_vectors[0].address);
|
u32 MaxCount = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u32 Count = 0;
|
u32 Count = 0;
|
||||||
for (int i = 0; i < (int)m_TitleIDs.size(); i++)
|
for (int i = 0; i < (int)s_title_ids.size(); i++)
|
||||||
{
|
{
|
||||||
Memory::Write_U64(m_TitleIDs[i], request.io_vectors[0].address + i * 8);
|
Memory::Write_U64(s_title_ids[i], request.io_vectors[0].address + i * 8);
|
||||||
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >> 32),
|
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(s_title_ids[i] >> 32),
|
||||||
(u32)m_TitleIDs[i]);
|
(u32)s_title_ids[i]);
|
||||||
Count++;
|
Count++;
|
||||||
if (Count >= MaxCount)
|
if (Count >= MaxCount)
|
||||||
break;
|
break;
|
||||||
|
@ -1327,8 +1434,12 @@ IPCCommandResult ES::Sign(const IOCtlVRequest& request)
|
||||||
u32 data_size = request.in_vectors[0].size;
|
u32 data_size = request.in_vectors[0].size;
|
||||||
u8* sig_out = Memory::GetPointer(request.io_vectors[0].address);
|
u8* sig_out = Memory::GetPointer(request.io_vectors[0].address);
|
||||||
|
|
||||||
|
if (!s_title_context.active)
|
||||||
|
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||||
|
|
||||||
const EcWii& ec = EcWii::GetInstance();
|
const EcWii& ec = EcWii::GetInstance();
|
||||||
MakeAPSigAndCert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.GetNGPriv(), ec.GetNGID());
|
MakeAPSigAndCert(sig_out, ap_cert_out, s_title_context.tmd.GetTitleId(), data, data_size,
|
||||||
|
ec.GetNGPriv(), ec.GetNGID());
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -1365,36 +1476,38 @@ IPCCommandResult ES::GetOwnedTitleCount(const IOCtlVRequest& request)
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
const DiscIO::CNANDContentLoader& ES::AccessContentDevice(u64 title_id) const
|
const DiscIO::CNANDContentLoader& ES::AccessContentDevice(u64 title_id)
|
||||||
{
|
{
|
||||||
// for WADs, the passed title id and the stored title id match; along with m_ContentFile being set
|
// for WADs, the passed title id and the stored title id match; along with s_content_file
|
||||||
// to the
|
// being set to the actual WAD file name. We cannot simply get a NAND Loader for the title id
|
||||||
// actual WAD file name. We cannot simply get a NAND Loader for the title id in those cases, since
|
// in those cases, since the WAD need not be installed in the NAND, but it could be opened
|
||||||
// the WAD
|
// directly from a WAD file anywhere on disk.
|
||||||
// need not be installed in the NAND, but it could be opened directly from a WAD file anywhere on
|
if (s_title_context.active && s_title_context.tmd.GetTitleId() == title_id &&
|
||||||
// disk.
|
!s_content_file.empty())
|
||||||
if (m_TitleID == title_id && !m_ContentFile.empty())
|
{
|
||||||
return DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
|
return DiscIO::CNANDContentManager::Access().GetNANDLoader(s_content_file);
|
||||||
|
}
|
||||||
|
|
||||||
return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT);
|
return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ES::ES_DIVerify(const IOS::ES::TMDReader& tmd)
|
// This is technically an ioctlv in IOS's ES, but it is an internal API which cannot be
|
||||||
|
// used from the PowerPC (for unpatched IOSes anyway).
|
||||||
|
s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket)
|
||||||
{
|
{
|
||||||
if (!tmd.IsValid())
|
s_title_context.Clear();
|
||||||
return -1;
|
INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: (none)");
|
||||||
|
|
||||||
u64 title_id = 0xDEADBEEFDEADBEEFull;
|
if (!tmd.IsValid() || !ticket.IsValid())
|
||||||
u64 tmd_title_id = tmd.GetTitleId();
|
return ES_PARAMETER_SIZE_OR_ALIGNMENT;
|
||||||
|
|
||||||
DVDInterface::GetVolume().GetTitleID(&title_id);
|
if (tmd.GetTitleId() != ticket.GetTitleId())
|
||||||
if (title_id != tmd_title_id)
|
return ES_PARAMETER_SIZE_OR_ALIGNMENT;
|
||||||
return -1;
|
|
||||||
|
|
||||||
std::string tmd_path = Common::GetTMDFileName(tmd_title_id, Common::FROM_SESSION_ROOT);
|
std::string tmd_path = Common::GetTMDFileName(tmd.GetTitleId(), Common::FROM_SESSION_ROOT);
|
||||||
|
|
||||||
File::CreateFullPath(tmd_path);
|
File::CreateFullPath(tmd_path);
|
||||||
File::CreateFullPath(Common::GetTitleDataPath(tmd_title_id, Common::FROM_SESSION_ROOT));
|
File::CreateFullPath(Common::GetTitleDataPath(tmd.GetTitleId(), Common::FROM_SESSION_ROOT));
|
||||||
|
|
||||||
if (!File::Exists(tmd_path))
|
if (!File::Exists(tmd_path))
|
||||||
{
|
{
|
||||||
|
@ -1404,11 +1517,14 @@ u32 ES::ES_DIVerify(const IOS::ES::TMDReader& tmd)
|
||||||
ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND.");
|
ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND.");
|
||||||
}
|
}
|
||||||
DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT};
|
DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT};
|
||||||
uid_sys.AddTitle(tmd_title_id);
|
uid_sys.AddTitle(tmd.GetTitleId());
|
||||||
// DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager.
|
// DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager.
|
||||||
// clear the cache to avoid content access mismatches.
|
// clear the cache to avoid content access mismatches.
|
||||||
DiscIO::CNANDContentManager::Access().ClearCache();
|
DiscIO::CNANDContentManager::Access().ClearCache();
|
||||||
return 0;
|
|
||||||
|
s_title_context.Update(tmd, ticket);
|
||||||
|
INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: %016" PRIx64, tmd.GetTitleId());
|
||||||
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
} // namespace Device
|
} // namespace Device
|
||||||
} // namespace HLE
|
} // namespace HLE
|
||||||
|
|
|
@ -34,13 +34,15 @@ class ES : public Device
|
||||||
public:
|
public:
|
||||||
ES(u32 device_id, const std::string& device_name);
|
ES(u32 device_id, const std::string& device_name);
|
||||||
|
|
||||||
void LoadWAD(const std::string& _rContentFile);
|
// Called after an IOS reload.
|
||||||
bool LaunchTitle(u64 title_id, bool skip_reload = false) const;
|
static void Init();
|
||||||
|
|
||||||
|
static s32 DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket);
|
||||||
|
static void LoadWAD(const std::string& _rContentFile);
|
||||||
|
static bool LaunchTitle(u64 title_id, bool skip_reload = false);
|
||||||
|
|
||||||
// Internal implementation of the ES_DECRYPT ioctlv.
|
// Internal implementation of the ES_DECRYPT ioctlv.
|
||||||
void DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output);
|
static void DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output);
|
||||||
|
|
||||||
void OpenInternal();
|
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
|
@ -48,11 +50,6 @@ public:
|
||||||
void Close() override;
|
void Close() override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
static u32 ES_DIVerify(const IOS::ES::TMDReader& tmd);
|
|
||||||
|
|
||||||
// This should only be cleared on power reset
|
|
||||||
static std::string m_ContentFile;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -200,18 +197,16 @@ private:
|
||||||
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
|
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request);
|
IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request);
|
||||||
|
|
||||||
bool LaunchIOS(u64 ios_title_id) const;
|
static bool LaunchIOS(u64 ios_title_id);
|
||||||
bool LaunchPPCTitle(u64 title_id, bool skip_reload) const;
|
static bool LaunchPPCTitle(u64 title_id, bool skip_reload);
|
||||||
|
|
||||||
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id) const;
|
static const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id);
|
||||||
|
|
||||||
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
||||||
|
|
||||||
using ContentAccessMap = std::map<u32, OpenedContent>;
|
using ContentAccessMap = std::map<u32, OpenedContent>;
|
||||||
ContentAccessMap m_ContentAccessMap;
|
ContentAccessMap m_ContentAccessMap;
|
||||||
|
|
||||||
std::vector<u64> m_TitleIDs;
|
|
||||||
u64 m_TitleID = -1;
|
|
||||||
u32 m_AccessIdentID = 0;
|
u32 m_AccessIdentID = 0;
|
||||||
|
|
||||||
// For title installation (ioctls IOCTL_ES_ADDTITLE*).
|
// For title installation (ioctls IOCTL_ES_ADDTITLE*).
|
||||||
|
|
|
@ -126,6 +126,11 @@ u16 TMDReader::GetTitleVersion() const
|
||||||
return Common::swap16(m_bytes.data() + offsetof(TMDHeader, title_version));
|
return Common::swap16(m_bytes.data() + offsetof(TMDHeader, title_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u16 TMDReader::GetGroupId() const
|
||||||
|
{
|
||||||
|
return Common::swap16(m_bytes.data() + offsetof(TMDHeader, group_id));
|
||||||
|
}
|
||||||
|
|
||||||
u16 TMDReader::GetNumContents() const
|
u16 TMDReader::GetNumContents() const
|
||||||
{
|
{
|
||||||
return Common::swap16(m_bytes.data() + offsetof(TMDHeader, num_contents));
|
return Common::swap16(m_bytes.data() + offsetof(TMDHeader, num_contents));
|
||||||
|
@ -212,6 +217,11 @@ bool TicketReader::IsValid() const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TicketReader::DoState(PointerWrap& p)
|
||||||
|
{
|
||||||
|
p.Do(m_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
u32 TicketReader::GetNumberOfTickets() const
|
u32 TicketReader::GetNumberOfTickets() const
|
||||||
{
|
{
|
||||||
return static_cast<u32>(m_bytes.size() / (GetOffset() + sizeof(Ticket)));
|
return static_cast<u32>(m_bytes.size() / (GetOffset() + sizeof(Ticket)));
|
||||||
|
|
|
@ -137,6 +137,7 @@ public:
|
||||||
DiscIO::Region GetRegion() const;
|
DiscIO::Region GetRegion() const;
|
||||||
u64 GetTitleId() const;
|
u64 GetTitleId() const;
|
||||||
u16 GetTitleVersion() const;
|
u16 GetTitleVersion() const;
|
||||||
|
u16 GetGroupId() const;
|
||||||
|
|
||||||
u16 GetNumContents() const;
|
u16 GetNumContents() const;
|
||||||
bool GetContent(u16 index, Content* content) const;
|
bool GetContent(u16 index, Content* content) const;
|
||||||
|
@ -160,6 +161,7 @@ public:
|
||||||
void SetBytes(std::vector<u8>&& bytes);
|
void SetBytes(std::vector<u8>&& bytes);
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
const std::vector<u8>& GetRawTicket() const;
|
const std::vector<u8>& GetRawTicket() const;
|
||||||
u32 GetNumberOfTickets() const;
|
u32 GetNumberOfTickets() const;
|
||||||
|
|
|
@ -95,7 +95,6 @@ static CoreTiming::EventType* s_event_sdio_notify;
|
||||||
static u64 s_last_reply_time;
|
static u64 s_last_reply_time;
|
||||||
|
|
||||||
static u64 s_active_title_id;
|
static u64 s_active_title_id;
|
||||||
static u64 s_title_to_launch;
|
|
||||||
|
|
||||||
static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL;
|
static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL;
|
||||||
static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL;
|
static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL;
|
||||||
|
@ -586,7 +585,6 @@ static void AddStaticDevices()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
||||||
_assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized");
|
_assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized");
|
||||||
Device::ES::m_ContentFile = "";
|
|
||||||
|
|
||||||
num_devices = 0;
|
num_devices = 0;
|
||||||
|
|
||||||
|
@ -706,20 +704,10 @@ bool Reload(const u64 ios_title_id)
|
||||||
|
|
||||||
AddStaticDevices();
|
AddStaticDevices();
|
||||||
|
|
||||||
if (s_title_to_launch != 0)
|
Device::ES::Init();
|
||||||
{
|
|
||||||
NOTICE_LOG(IOS, "Re-launching title after IOS reload.");
|
|
||||||
s_es_handles[0]->LaunchTitle(s_title_to_launch, true);
|
|
||||||
s_title_to_launch = 0;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTitleToLaunch(const u64 title_id)
|
|
||||||
{
|
|
||||||
s_title_to_launch = title_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC.
|
// This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC.
|
||||||
// Unlike 0x42, IOS will set up some constants in memory before booting the PPC.
|
// Unlike 0x42, IOS will set up some constants in memory before booting the PPC.
|
||||||
bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader)
|
bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader)
|
||||||
|
@ -749,18 +737,6 @@ bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDefaultContentFile(const std::string& file_name)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
|
||||||
for (const auto& es : s_es_handles)
|
|
||||||
es->LoadWAD(file_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ES_DIVerify(const ES::TMDReader& tmd)
|
|
||||||
{
|
|
||||||
Device::ES::ES_DIVerify(tmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDIO_EventNotify()
|
void SDIO_EventNotify()
|
||||||
{
|
{
|
||||||
// TODO: Potential race condition: If IsRunning() becomes false after
|
// TODO: Potential race condition: If IsRunning() becomes false after
|
||||||
|
|
|
@ -21,11 +21,6 @@ class CNANDContentLoader;
|
||||||
|
|
||||||
namespace IOS
|
namespace IOS
|
||||||
{
|
{
|
||||||
namespace ES
|
|
||||||
{
|
|
||||||
class TMDReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace HLE
|
namespace HLE
|
||||||
{
|
{
|
||||||
namespace Device
|
namespace Device
|
||||||
|
@ -67,16 +62,10 @@ bool Reload(u64 ios_title_id);
|
||||||
u32 GetVersion();
|
u32 GetVersion();
|
||||||
|
|
||||||
bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader);
|
bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader);
|
||||||
// This sets a title to launch after IOS has been reset and reloaded (similar to /sys/launch.sys).
|
|
||||||
void SetTitleToLaunch(u64 title_id);
|
|
||||||
|
|
||||||
// Do State
|
// Do State
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
// Set default content file
|
|
||||||
void SetDefaultContentFile(const std::string& file_name);
|
|
||||||
void ES_DIVerify(const ES::TMDReader& tmd);
|
|
||||||
|
|
||||||
void SDIO_EventNotify();
|
void SDIO_EventNotify();
|
||||||
|
|
||||||
std::shared_ptr<Device::Device> GetDeviceByName(const std::string& device_name);
|
std::shared_ptr<Device::Device> GetDeviceByName(const std::string& device_name);
|
||||||
|
|
|
@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
||||||
static std::thread g_save_thread;
|
static std::thread g_save_thread;
|
||||||
|
|
||||||
// Don't forget to increase this after doing changes on the savestate system
|
// Don't forget to increase this after doing changes on the savestate system
|
||||||
static const u32 STATE_VERSION = 78; // Last changed in PR 49XX
|
static const u32 STATE_VERSION = 79; // Last changed in PR 4981
|
||||||
|
|
||||||
// Maps savestate versions to Dolphin versions.
|
// Maps savestate versions to Dolphin versions.
|
||||||
// Versions after 42 don't need to be added to this list,
|
// Versions after 42 don't need to be added to this list,
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool GetTitleID(u64*) const { return false; }
|
virtual bool GetTitleID(u64*) const { return false; }
|
||||||
|
virtual IOS::ES::TicketReader GetTicket() const { return {}; }
|
||||||
virtual IOS::ES::TMDReader GetTMD() const { return {}; }
|
virtual IOS::ES::TMDReader GetTMD() const { return {}; }
|
||||||
virtual u64 PartitionOffsetToRawOffset(u64 offset) const { return offset; }
|
virtual u64 PartitionOffsetToRawOffset(u64 offset) const { return offset; }
|
||||||
virtual std::string GetGameID() const = 0;
|
virtual std::string GetGameID() const = 0;
|
||||||
|
|
|
@ -114,6 +114,13 @@ bool CVolumeWiiCrypted::GetTitleID(u64* buffer) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOS::ES::TicketReader CVolumeWiiCrypted::GetTicket() const
|
||||||
|
{
|
||||||
|
std::vector<u8> buffer(0x2a4);
|
||||||
|
Read(m_VolumeOffset, buffer.size(), buffer.data(), false);
|
||||||
|
return IOS::ES::TicketReader{std::move(buffer)};
|
||||||
|
}
|
||||||
|
|
||||||
IOS::ES::TMDReader CVolumeWiiCrypted::GetTMD() const
|
IOS::ES::TMDReader CVolumeWiiCrypted::GetTMD() const
|
||||||
{
|
{
|
||||||
u32 tmd_size;
|
u32 tmd_size;
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
~CVolumeWiiCrypted();
|
~CVolumeWiiCrypted();
|
||||||
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override;
|
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override;
|
||||||
bool GetTitleID(u64* buffer) const override;
|
bool GetTitleID(u64* buffer) const override;
|
||||||
|
IOS::ES::TicketReader GetTicket() const override;
|
||||||
IOS::ES::TMDReader GetTMD() const override;
|
IOS::ES::TMDReader GetTMD() const override;
|
||||||
u64 PartitionOffsetToRawOffset(u64 offset) const override;
|
u64 PartitionOffsetToRawOffset(u64 offset) const override;
|
||||||
std::string GetGameID() const override;
|
std::string GetGameID() const override;
|
||||||
|
|
Loading…
Reference in New Issue