Merge pull request #3736 from BhaaLseN/issue-9135

Rewrite NAND Content handling in ES to fix Issue 9135
This commit is contained in:
Pierre Bourdon committed 2016-03-26 05:00:08 +01:00
commit bd200bd195
5 files changed
+218 -177

No files matched your search

+1 -9
View File
@@ -101,15 +101,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
std::unique_ptr<CDolLoader> pDolLoader;
if (pContent->m_data.empty())
{
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
}
else
{
pDolLoader = std::make_unique<CDolLoader>(pContent->m_data);
}
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
if (!pDolLoader->IsValid())
return false;
@@ -64,7 +64,6 @@ std::string CWII_IPC_HLE_Device_es::m_ContentFile;
CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
, m_pContentLoader(nullptr)
, m_TitleID(-1)
, m_AccessIdentID(0x6000000)
{
@@ -99,12 +98,12 @@ void CWII_IPC_HLE_Device_es::LoadWAD(const std::string& _rContentFile)
void CWII_IPC_HLE_Device_es::OpenInternal()
{
m_pContentLoader = &DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
auto& contentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
// check for cd ...
if (m_pContentLoader->IsValid())
if (contentLoader.IsValid())
{
m_TitleID = m_pContentLoader->GetTitleID();
m_TitleID = contentLoader.GetTitleID();
m_TitleIDs.clear();
DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs);
@@ -164,7 +163,7 @@ void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p)
SContentAccess& Access = pair.second;
Position = Access.m_Position;
TitleID = Access.m_TitleID;
Index = Access.m_pContent->m_Index;
Index = Access.m_Index;
p.Do(CFD);
p.Do(Position);
p.Do(TitleID);
@@ -186,14 +185,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
IPCCommandResult CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
{
// Leave deletion of the CNANDContentLoader objects to CNANDContentManager, don't do it here!
m_NANDContent.clear();
for (auto& pair : m_ContentAccessMap)
{
delete pair.second.m_pFile;
}
m_ContentAccessMap.clear();
m_pContentLoader = nullptr;
m_TitleIDs.clear();
m_TitleID = -1;
m_AccessIdentID = 0x6000000;
@@ -202,6 +194,8 @@ IPCCommandResult CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce
if (!_bForce)
Memory::Write_U32(0, _CommandAddress + 4);
m_Active = false;
// clear the NAND content cache to make sure nothing remains open.
DiscIO::CNANDContentManager::Access().ClearCache();
return GetDefaultReply();
}
@@ -224,22 +218,11 @@ u32 CWII_IPC_HLE_Device_es::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
SContentAccess Access;
Access.m_Position = 0;
Access.m_pContent = pContent;
Access.m_Index = pContent->m_Index;
Access.m_Size = pContent->m_Size;
Access.m_TitleID = TitleID;
Access.m_pFile = nullptr;
if (pContent->m_data.empty())
{
std::string Filename = pContent->m_Filename;
INFO_LOG(WII_IPC_ES, "ES: load %s", Filename.c_str());
Access.m_pFile = new File::IOFile(Filename, "rb");
if (!Access.m_pFile->IsGood())
{
WARN_LOG(WII_IPC_ES, "ES: couldn't load %s", Filename.c_str());
return 0xffffffff;
}
}
pContent->m_Data->Open();
m_ContentAccessMap[CFD] = Access;
return CFD;
@@ -323,21 +306,21 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
const DiscIO::CNANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
{
for (u16 i = 0; i < rNANDCOntent.GetNumEntries(); i++)
for (u16 i = 0; i < rNANDContent.GetNumEntries(); i++)
{
Memory::Write_U32(rNANDCOntent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDCOntent.GetContentByIndex(i)->m_ContentID);
Memory::Write_U32(rNANDContent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDContent.GetContentByIndex(i)->m_ContentID);
}
Memory::Write_U32(0, _CommandAddress + 0x4);
}
else
{
Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Unable to open content %zu",
rNANDCOntent.GetContentSize());
rNANDContent.GetContentSize());
}
return GetDefaultReply();
@@ -395,32 +378,22 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u8* pDest = Memory::GetPointer(Addr);
if (rContent.m_Position + Size > rContent.m_pContent->m_Size)
if (rContent.m_Position + Size > rContent.m_Size)
{
Size = rContent.m_pContent->m_Size-rContent.m_Position;
Size = rContent.m_Size - rContent.m_Position;
}
if (Size > 0)
{
if (pDest)
{
if (rContent.m_pContent->m_data.empty())
const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(rContent.m_TitleID);
// ContentLoader should never be invalid; rContent has been created by it.
if (ContentLoader.IsValid())
{
auto& pFile = rContent.m_pFile;
if (!pFile->Seek(rContent.m_Position, SEEK_SET))
{
ERROR_LOG(WII_IPC_ES, "ES: couldn't seek!");
}
WARN_LOG(WII_IPC_ES, "2 %p", pFile->GetHandle());
if (!pFile->ReadBytes(pDest, Size))
{
ERROR_LOG(WII_IPC_ES, "ES: short read; returning uninitialized data!");
}
}
else
{
const u8* src = &rContent.m_pContent->m_data[rContent.m_Position];
memcpy(pDest, src, Size);
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(rContent.m_Index);
if (!pContent->m_Data->GetRange(rContent.m_Position, Size, pDest))
ERROR_LOG(WII_IPC_ES, "ES: failed to read %u bytes from %u!", Size, rContent.m_Position);
}
rContent.m_Position += Size;
@@ -431,7 +404,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
}
}
INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_pContent->m_Index);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_Index);
Memory::Write_U32(Size, _CommandAddress + 0x4);
return GetDefaultReply();
@@ -454,7 +427,14 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
return GetDefaultReply();
}
delete itr->second.m_pFile;
const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(itr->second.m_TitleID);
// ContentLoader should never be invalid; we shouldn't be here if ES_OPENCONTENT failed before.
if (ContentLoader.IsValid())
{
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(itr->second.m_Index);
pContent->m_Data->Close();
}
m_ContentAccessMap.erase(itr);
Memory::Write_U32(0, _CommandAddress + 0x4);
@@ -490,7 +470,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
break;
case 2: // END
rContent.m_Position = rContent.m_pContent->m_Size + Addr;
rContent.m_Position = rContent.m_Size + Addr;
break;
}
@@ -906,6 +886,11 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16);
u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24);
// ES_LAUNCH should probably reset thw whole state, which at least means closing all open files.
// leaving them open through ES_LAUNCH may cause hangs and other funky behavior
// (supposedly when trying to re-open those files).
DiscIO::CNANDContentManager::Access().ClearCache();
std::string tContentFile;
if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU)
{
@@ -917,15 +902,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
if (pContent)
{
tContentFile = Common::GetTitleContentPath(TitleID, Common::FROM_SESSION_ROOT);
std::unique_ptr<CDolLoader> pDolLoader;
if (pContent->m_data.empty())
{
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
}
else
{
pDolLoader = std::make_unique<CDolLoader>(pContent->m_data);
}
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
if (pDolLoader->IsValid())
{
@@ -1077,31 +1054,17 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
return GetDefaultReply();
}
// TODO: This cache is redundant with the one in CNANDContentManager.h
const DiscIO::CNANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 _TitleID)
const DiscIO::CNANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 title_id)
{
if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
return *m_pContentLoader;
// for WADs, the passed title id and the stored title id match; along with m_ContentFile being set to the
// actual WAD file name. We cannot simply get a NAND Loader for the title id in those cases, since the WAD
// need not be installed in the NAND, but it could be opened directly from a WAD file anywhere on disk.
if (m_TitleID == title_id && !m_ContentFile.empty())
return DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
CTitleToContentMap::iterator itr = m_NANDContent.find(_TitleID);
if (itr != m_NANDContent.end())
return *itr->second;
m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID, Common::FROM_SESSION_ROOT);
_dbg_assert_msg_(WII_IPC_ES, ((u32)(_TitleID >> 32) == 0x00010000) || m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
return *m_NANDContent[_TitleID];
return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT);
}
bool CWII_IPC_HLE_Device_es::IsValid(u64 _TitleID) const
{
if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
return true;
return false;
}
u32 CWII_IPC_HLE_Device_es::ES_DIVerify(const std::vector<u8>& tmd)
{
u64 title_id = 0xDEADBEEFDEADBEEFull;
@@ -1168,6 +1131,8 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(const std::vector<u8>& tmd)
ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND.");
}
DiscIO::cUIDsys::AccessInstance().AddTitle(tmd_title_id);
// DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager.
// clear the cache to avoid content access mismatches.
DiscIO::CNANDContentManager::Access().ClearCache();
return 0;
}
@@ -125,30 +125,22 @@ private:
{
u32 m_Position;
u64 m_TitleID;
const DiscIO::SNANDContent* m_pContent;
// This is a (raw) pointer to work around a MSVC bug.
File::IOFile* m_pFile;
u16 m_Index;
u32 m_Size;
};
typedef std::map<u32, SContentAccess> CContentAccessMap;
CContentAccessMap m_ContentAccessMap;
typedef std::map<u64, const DiscIO::CNANDContentLoader*> CTitleToContentMap;
CTitleToContentMap m_NANDContent;
const DiscIO::CNANDContentLoader* m_pContentLoader;
std::vector<u64> m_TitleIDs;
u64 m_TitleID;
u32 m_AccessIdentID;
static u8 *keyTable[11];
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 _TitleID);
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id);
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
bool IsValid(u64 _TitleID) const;
struct ecc_cert_t
{
u32 sig_type ;