Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix loading DLC using IOCTL_ES_OPENTITLECONTENT & /dev/es state save.
(Intertwined enough that's it's easier to do in one patch.)

(1) /dev/es did not support state save, which could cause crashes and
    incorrect behavior after loading.

(2) NANDContentLoader tried to read all of a title's contents into
    memory when it was first opened.  Two issues:

- If any contents were missing, it bailed out.  However, with DLC,
  only some of the contents may be downloaded, as determined by the
  permission bits in the ticket.  Instead, return an appropriate error
  when a content is accessed that doesn't exist on the filesystem
  (don't bother checking the permission bits though).

- Everything was loaded into memory - even if it consisted of 3 GB of
  songs, which caused Dolphin to lag out for quite a while (and would
  fail on 32-bit).  Instead, open content on demand.
  • Loading branch information
comex committed Aug 31, 2013
1 parent 4d6d4a9 commit 04c41c1
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 65 deletions.
6 changes: 1 addition & 5 deletions Source/Core/Common/Src/FileUtil.h
Expand Up @@ -143,7 +143,7 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str);
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
// and make forgetting an fclose() harder
class IOFile
class IOFile : public NonCopyable
{
public:
IOFile();
Expand Down Expand Up @@ -209,10 +209,6 @@ class IOFile
// clear error state
void Clear() { m_good = true; std::clearerr(m_file); }

private:
IOFile(const IOFile&) /*= delete*/;
IOFile& operator=(const IOFile&) /*= delete*/;

std::FILE* m_file;
bool m_good;
};
Expand Down
144 changes: 116 additions & 28 deletions Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
Expand Up @@ -60,7 +60,7 @@ CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string&
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
, m_pContentLoader(NULL)
, m_TitleID(-1)
, AccessIdentID(0x6000000)
, m_AccessIdentID(0x6000000)
{
}

Expand Down Expand Up @@ -91,7 +91,7 @@ void CWII_IPC_HLE_Device_es::LoadWAD(const std::string& _rContentFile)
m_ContentFile = _rContentFile;
}

bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
void CWII_IPC_HLE_Device_es::OpenInternal()
{
m_pContentLoader = &DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);

Expand Down Expand Up @@ -119,6 +119,57 @@ bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
}

INFO_LOG(WII_IPC_ES, "Set default title to %08x/%08x", (u32)(m_TitleID>>32), (u32)m_TitleID);
}

void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p)
{
IWII_IPC_HLE_Device::DoState(p);
p.Do(m_ContentFile);
OpenInternal();
p.Do(m_AccessIdentID);
p.Do(m_TitleIDs);

u32 Count = m_ContentAccessMap.size();
p.Do(Count);

u32 CFD, Position;
u64 TitleID;
u16 Index;
if (p.GetMode() == PointerWrap::MODE_READ)
{
for (u32 i = 0; i < Count; i++)
{
p.Do(CFD);
p.Do(Position);
p.Do(TitleID);
p.Do(Index);
CFD = OpenTitleContent(CFD, TitleID, Index);
if (CFD != 0xffffffff)
{
m_ContentAccessMap[CFD].m_Position = Position;
}
}
}
else
{
for (auto itr = m_ContentAccessMap.begin(); itr != m_ContentAccessMap.end(); ++itr)
{
CFD = itr->first;
SContentAccess& Access = itr->second;
Position = Access.m_Position;
TitleID = Access.m_TitleID;
Index = Access.m_pContent->m_Index;
p.Do(CFD);
p.Do(Position);
p.Do(TitleID);
p.Do(Index);
}
}
}

bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
{
OpenInternal();

Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
if (m_Active)
Expand All @@ -135,7 +186,7 @@ bool CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
m_pContentLoader = NULL;
m_TitleIDs.clear();
m_TitleID = -1;
AccessIdentID = 0x6000000;
m_AccessIdentID = 0x6000000;

INFO_LOG(WII_IPC_ES, "ES: Close");
if (!_bForce)
Expand All @@ -144,6 +195,37 @@ bool CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
return true;
}

u32 CWII_IPC_HLE_Device_es::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
{
const DiscIO::SNANDContent* pContent = AccessContentDevice(TitleID).GetContentByIndex(Index);

if (pContent == NULL)
{
return 0xffffffff; //TODO: what is the correct error value here?
}

SContentAccess Access;
Access.m_Position = 0;
Access.m_pContent = pContent;
Access.m_TitleID = TitleID;

if (!pContent->m_pData)
{
std::string Filename = pContent->m_Filename;
INFO_LOG(WII_IPC_ES, "ES: load %s", Filename.c_str());

Access.m_File.Open(Filename, "rb");
if (!Access.m_File.IsGood())
{
WARN_LOG(WII_IPC_ES, "ES: couldn't load %s", Filename.c_str());
return 0xffffffff;
}
}

m_ContentAccessMap[CFD] = std::move(Access);
return CFD;
}

bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
{
SIOCtlVBuffer Buffer(_CommandAddress);
Expand Down Expand Up @@ -242,16 +324,11 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
u32 Index = Memory::Read_U32(Buffer.InBuffer[2].m_Address);

u32 CFD = AccessIdentID++;
m_ContentAccessMap[CFD].m_Position = 0;
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(TitleID).GetContentByIndex(Index);
_dbg_assert_msg_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL, "No Content for TitleID: %08x/%08x at Index %x", (u32)(TitleID>>32), (u32)TitleID, Index);
// Fix for DLC by itsnotmailmail
if (m_ContentAccessMap[CFD].m_pContent == NULL)
CFD = 0xffffffff; //TODO: what is the correct error value here?
u32 CFD = OpenTitleContent(m_AccessIdentID++, TitleID, Index);
Memory::Write_U32(CFD, _CommandAddress + 0x4);

INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x", (u32)(TitleID>>32), (u32)TitleID, Index, CFD);

return true;
}
break;
Expand All @@ -260,19 +337,12 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
{
_dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
_dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);

u32 CFD = AccessIdentID++;
u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);

m_ContentAccessMap[CFD].m_Position = 0;
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);

if (m_ContentAccessMap[CFD].m_pContent == NULL)
CFD = 0xffffffff; //TODO: what is the correct error value here?

u32 CFD = OpenTitleContent(m_AccessIdentID++, m_TitleID, Index);
Memory::Write_U32(CFD, _CommandAddress + 0x4);

INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);

return true;
}
break;
Expand All @@ -286,12 +356,16 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u32 Size = Buffer.PayloadBuffer[0].m_Size;
u32 Addr = Buffer.PayloadBuffer[0].m_Address;

_dbg_assert_(WII_IPC_ES, m_ContentAccessMap.find(CFD) != m_ContentAccessMap.end());
SContentAccess& rContent = m_ContentAccessMap[CFD];
auto itr = m_ContentAccessMap.find(CFD);
if (itr == m_ContentAccessMap.end())
{
Memory::Write_U32(-1, _CommandAddress + 0x4);
return true;
}
SContentAccess& rContent = itr->second;

_dbg_assert_(WII_IPC_ES, rContent.m_pContent->m_pData != NULL);

u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position];
u8* pDest = Memory::GetPointer(Addr);

if (rContent.m_Position + Size > rContent.m_pContent->m_Size)
Expand All @@ -302,7 +376,17 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
if (Size > 0)
{
if (pDest) {
memcpy(pDest, pSrc, Size);
if (rContent.m_pContent->m_pData)
{
u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position];
memcpy(pDest, pSrc, Size);
}
else
{
File::IOFile* pFile = &rContent.m_File;
pFile->Seek(rContent.m_Position, SEEK_SET);
pFile->ReadBytes(pDest, Size);
}
rContent.m_Position += Size;
} else {
PanicAlertT("IOCTL_ES_READCONTENT - bad destination");
Expand All @@ -323,8 +407,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)

u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);

CContentAccessMap::iterator itr = m_ContentAccessMap.find(CFD);
m_ContentAccessMap.erase(itr);
m_ContentAccessMap.erase(CFD);

INFO_LOG(WII_IPC_ES, "IOCTL_ES_CLOSECONTENT: CFD %x", CFD);

Expand All @@ -342,8 +425,13 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address);

_dbg_assert_(WII_IPC_ES, m_ContentAccessMap.find(CFD) != m_ContentAccessMap.end());
SContentAccess& rContent = m_ContentAccessMap[CFD];
auto itr = m_ContentAccessMap.find(CFD);
if (itr == m_ContentAccessMap.end())
{
Memory::Write_U32(-1, _CommandAddress + 0x4);
return true;
}
SContentAccess& rContent = itr->second;

switch (Mode)
{
Expand Down Expand Up @@ -908,7 +996,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 _TitleID)
{
if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
return* m_pContentLoader;
return *m_pContentLoader;

CTitleToContentMap::iterator itr = m_NANDContent.find(_TitleID);
if (itr != m_NANDContent.end())
Expand Down
11 changes: 9 additions & 2 deletions Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h
Expand Up @@ -19,6 +19,10 @@ class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device

void LoadWAD(const std::string& _rContentFile);

void OpenInternal();

virtual void DoState(PointerWrap& p);

virtual bool Open(u32 _CommandAddress, u32 _Mode);

virtual bool Close(u32 _CommandAddress, bool _bForce);
Expand Down Expand Up @@ -108,10 +112,12 @@ class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device
ES_HASH_SIZE_WRONG = -2014, // HASH !=20
};

struct SContentAccess
struct SContentAccess : public NonCopyable
{
u32 m_Position;
u64 m_TitleID;
const DiscIO::SNANDContent* m_pContent;
File::IOFile m_File;
};

typedef std::map<u32, SContentAccess> CContentAccessMap;
Expand All @@ -124,13 +130,14 @@ class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device

std::vector<u64> m_TitleIDs;
u64 m_TitleID;
u32 AccessIdentID;
u32 m_AccessIdentID;

static u8 *keyTable[11];

u64 GetCurrentTitleID() const;

const DiscIO::INANDContentLoader& AccessContentDevice(u64 _TitleID);
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);

bool IsValid(u64 _TitleID) const;

Expand Down
41 changes: 13 additions & 28 deletions Source/Core/DiscIO/Src/NANDContentLoader.cpp
Expand Up @@ -5,7 +5,7 @@
#include "NANDContentLoader.h"

#include <algorithm>
#include <cctype>
#include <cctype>
#include "Crypto/aes.h"
#include "MathUtil.h"
#include "FileUtil.h"
Expand Down Expand Up @@ -42,7 +42,7 @@ void CSharedContent::UpdateLocation()
CSharedContent::~CSharedContent()
{}

std::string CSharedContent::GetFilenameFromSHA1(u8* _pHash)
std::string CSharedContent::GetFilenameFromSHA1(const u8* _pHash)
{
for (size_t i=0; i<m_Elements.size(); i++)
{
Expand All @@ -58,7 +58,7 @@ std::string CSharedContent::GetFilenameFromSHA1(u8* _pHash)
return "unk";
}

std::string CSharedContent::AddSharedContent(u8* _pHash)
std::string CSharedContent::AddSharedContent(const u8* _pHash)
{
std::string szFilename = GetFilenameFromSHA1(_pHash);
if (strcasecmp(szFilename.c_str(), "unk") == 0)
Expand Down Expand Up @@ -170,8 +170,11 @@ const SNANDContent* CNANDContentLoader::GetContentByIndex(int _Index) const
{
for (size_t i=0; i<m_Content.size(); i++)
{
if (m_Content[i].m_Index == _Index)
return &m_Content[i];
const SNANDContent* pContent = &m_Content[i];
if (pContent->m_Index == _Index)
{
return pContent;
}
}
return NULL;
}
Expand Down Expand Up @@ -262,36 +265,18 @@ bool CNANDContentLoader::Initialize(const std::string& _rName)
}

rContent.m_pData = NULL;
char szFilename[1024];

if (rContent.m_Type & 0x8000) // shared app
{
std::string Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(rContent.m_SHA1Hash);
strcpy(szFilename, Filename.c_str());
rContent.m_Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(rContent.m_SHA1Hash);
}
else
{
sprintf(szFilename, "%s/%08x.app", m_Path.c_str(), rContent.m_ContentID);
rContent.m_Filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), rContent.m_ContentID);
}

INFO_LOG(DISCIO, "NANDContentLoader: load %s", szFilename);

File::IOFile pFile(szFilename, "rb");
if (pFile)
{
const u64 ContentSize = File::GetSize(szFilename);
rContent.m_pData = new u8[(u32)ContentSize];

_dbg_assert_msg_(BOOT, rContent.m_Size==ContentSize, "TMDLoader: Incorrect filesize (%s %i). Your NAND dump may be corrupt.", szFilename, i);

pFile.ReadBytes(rContent.m_pData, (size_t)ContentSize);
}
else
{
ERROR_LOG(DISCIO, "NANDContentLoader: error opening %s", szFilename);
delete [] pTMD;
return false;
}
// Be graceful about incorrect tmds.
rContent.m_Size = (u32) File::GetSize(rContent.m_Filename);
}

delete [] pTMD;
Expand Down Expand Up @@ -493,7 +478,7 @@ u64 CNANDContentManager::Install_WiiWAD(std::string &fileName)

for (u32 i = 0; i < ContentLoader.GetContentSize(); i++)
{
SNANDContent Content = ContentLoader.GetContent()[i];
const SNANDContent& Content = ContentLoader.GetContent()[i];

pTMDFile.WriteBytes(Content.m_Header, INANDContentLoader::CONTENT_HEADER_SIZE);

Expand Down

0 comments on commit 04c41c1

Please sign in to comment.