From 5c2694a6297361f6a5f251c3ca64cd3c24cdc99f Mon Sep 17 00:00:00 2001 From: "fires.gc" Date: Sun, 22 Feb 2009 00:40:52 +0000 Subject: [PATCH] added support to load WAD files of the WII the WiiWAD loader encrypts the WAD, loads the NAND AppLoader and executes it. The NAND Loader will load more parts of the WAD to memory and execute them. Some WADs show the loading screen but hanging because the BT devices cant be initialized. Dolphin is not able to connect to devices that arnt validates per SYSCONF. Perhaps a global flag is wrong or missing or we have to preload the SYSCONF by hand (or fix/improve the BT handling :)) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2348 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/Common.h | 5 + Source/Core/Common/Src/MathUtil.h | 2 + Source/Core/Core/Core.vcproj | 8 + Source/Core/Core/Src/Boot/Boot.cpp | 7 + Source/Core/Core/Src/Boot/Boot.h | 11 +- Source/Core/Core/Src/Boot/Boot_DOL.cpp | 97 +++--- Source/Core/Core/Src/Boot/Boot_DOL.h | 5 + Source/Core/Core/Src/Boot/Boot_ELF.cpp | 1 + Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp | 279 ++++++++++++++++++ Source/Core/Core/Src/Boot/Boot_WiiWAD.h | 35 +++ Source/Core/Core/Src/CoreParameter.cpp | 8 + Source/Core/Core/Src/CoreParameter.h | 1 + .../Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h | 103 +++++++ .../Interpreter/Interpreter_LoadStore.cpp | 8 + .../Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp | 2 + Source/Core/Core/Src/SConscript | 1 + Source/Core/DolphinWX/Src/FrameTools.cpp | 2 +- 17 files changed, 517 insertions(+), 58 deletions(-) create mode 100644 Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp create mode 100644 Source/Core/Core/Src/Boot/Boot_WiiWAD.h diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h index ac8f57e772..c46e6219e3 100644 --- a/Source/Core/Common/Src/Common.h +++ b/Source/Core/Common/Src/Common.h @@ -218,6 +218,11 @@ inline u32 swap32(u32 data) {return((swap16(data) << 16) | swap16(data >> 16));} inline u64 swap64(u64 data) {return(((u64)swap32(data) << 32) | swap32(data >> 32));} #endif +inline u16 swap16(u8* _pData) {return(swap16(*(u16*)_pData));} +inline u32 swap32(u8* _pData) {return(swap32(*(u32*)_pData));} +inline u64 swap64(u8* _pData) {return(swap64(*(u64*)_pData));} + + } // end of namespace Common /////////////////////////////////// diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index 6edaffb2ca..6e55b4a789 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -34,4 +34,6 @@ void SaveSSEState(); void LoadSSEState(); void LoadDefaultSSEState(); +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + #endif diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index f0bb0a466c..6a95657e88 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -2247,6 +2247,14 @@ RelativePath=".\Src\Boot\Boot_ELF.h" > + + + + diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 13ab8fe007..f9ec920058 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -290,6 +290,13 @@ bool CBoot::BootUp() } break; + // Wii WAD + // =================================================================================== + case SCoreStartupParameter::BOOT_WIIWAD: + Boot_WiiWAD(_StartupPara.m_strFilename.c_str()); + break; + + // BIOS // =================================================================================== case SCoreStartupParameter::BOOT_BIOS: diff --git a/Source/Core/Core/Src/Boot/Boot.h b/Source/Core/Core/Src/Boot/Boot.h index 6388e802da..8461e5fe91 100644 --- a/Source/Core/Core/Src/Boot/Boot.h +++ b/Source/Core/Core/Src/Boot/Boot.h @@ -27,17 +27,9 @@ class CBoot { public: - enum TBootFileType - { - BOOT_ERROR, - BOOT_DOL, - BOOT_ELF, - BOOT_ISO, - BOOT_BIOS - }; - static bool BootUp(); static bool IsElfWii(const char *filename); + static bool IsWiiWAD(const char *filename); static std::string GenerateMapFilename(); @@ -50,6 +42,7 @@ private: static bool LoadMapFromFilename(const std::string& _rFilename, const char* _gameID = NULL); static bool Boot_ELF(const char *filename); + static bool Boot_WiiWAD(const char *filename); static void EmulatedBIOS(bool _bDebug); static bool EmulatedBIOS_Wii(bool _bDebug); diff --git a/Source/Core/Core/Src/Boot/Boot_DOL.cpp b/Source/Core/Core/Src/Boot/Boot_DOL.cpp index c864c787c3..fc0345a9b9 100644 --- a/Source/Core/Core/Src/Boot/Boot_DOL.cpp +++ b/Source/Core/Core/Src/Boot/Boot_DOL.cpp @@ -16,62 +16,63 @@ // http://code.google.com/p/dolphin-emu/ #include "Boot_DOL.h" +#include "FileUtil.h" #include "../HW/Memmap.h" -CDolLoader::CDolLoader(const char* _szFilename) : m_bInit(false) + +CDolLoader::CDolLoader(u8* _pBuffer, u32 _Size) + : m_bInit(false) { - // try to open file - FILE* pStream = fopen(_szFilename, "rb"); - if (pStream) + m_bInit = Initialize(_pBuffer, _Size); +} + +CDolLoader::CDolLoader(const char* _szFilename) + : m_bInit(false) +{ + u64 size = File::GetSize(_szFilename); + u8* tmpBuffer = new u8[(size_t)size]; + + FILE* pStream = fopen(_szFilename, "rb"); + fread(tmpBuffer, size, 1, pStream); + fclose(pStream); + + m_bInit = Initialize(tmpBuffer, size); + delete [] tmpBuffer; +} + +bool CDolLoader::Initialize(u8* _pBuffer, u32 _Size) +{ + memcpy(&m_dolheader, _pBuffer, sizeof(SDolHeader)); + + // swap memory + u32* p = (u32*)&m_dolheader; + for (size_t i=0; i<(sizeof(SDolHeader)>>2); i++) + p[i] = Common::swap32(p[i]); + + // load all text (code) sections + for(int i = 0; i < DOL_NUM_TEXT; i++) { - fread(&m_dolheader, 1, sizeof(SDolHeader), pStream); - - // swap memory - u32* p = (u32*)&m_dolheader; - for (size_t i=0; i<(sizeof(SDolHeader)>>2); i++) - p[i] = Common::swap32(p[i]); - - // load all text (code) sections - for(int i = 0; i < DOL_NUM_TEXT; i++) + if(m_dolheader.textOffset[i] != 0) { - if(m_dolheader.textOffset[i] != 0) - { - u8* pTemp = new u8[m_dolheader.textSize[i]]; - - fseek(pStream, m_dolheader.textOffset[i], SEEK_SET); - fread(pTemp, 1, m_dolheader.textSize[i], pStream); - - for (u32 num = 0; num < m_dolheader.textSize[i]; num++) - Memory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num); - - delete [] pTemp; - } + u8* pTemp = &_pBuffer[m_dolheader.textOffset[i]]; + for (u32 num = 0; num < m_dolheader.textSize[i]; num++) + Memory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num); } - - // load all data sections - for(int i = 0; i < DOL_NUM_DATA; i++) - { - if(m_dolheader.dataOffset[i] != 0) - { - u8* pTemp = new u8[m_dolheader.dataSize[i]]; - - fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET); - fread(pTemp, 1, m_dolheader.dataSize[i], pStream); - - for (u32 num = 0; num < m_dolheader.dataSize[i]; num++) - Memory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num); - - delete [] pTemp; - } - } - - //TODO - we know where there is code, and where there is data - //Make use of this! - - fclose(pStream); - m_bInit = true; } + + // load all data sections + for(int i = 0; i < DOL_NUM_DATA; i++) + { + if(m_dolheader.dataOffset[i] != 0) + { + u8* pTemp = &_pBuffer[m_dolheader.dataOffset[i]]; + for (u32 num = 0; num < m_dolheader.dataSize[i]; num++) + Memory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num); + } + } + + return true; } u32 CDolLoader::GetEntryPoint() diff --git a/Source/Core/Core/Src/Boot/Boot_DOL.h b/Source/Core/Core/Src/Boot/Boot_DOL.h index 730d65506c..cfebb13756 100644 --- a/Source/Core/Core/Src/Boot/Boot_DOL.h +++ b/Source/Core/Core/Src/Boot/Boot_DOL.h @@ -24,9 +24,12 @@ class CDolLoader { public: CDolLoader(const char* _szFilename); + CDolLoader(u8* _pBuffer, u32 _Size); + u32 GetEntryPoint(); static bool IsDolWii(const char* filename); + private: enum { @@ -51,6 +54,8 @@ private: }; SDolHeader m_dolheader; bool m_bInit; + + bool Initialize(u8* _pBuffer, u32 _Size); }; #endif diff --git a/Source/Core/Core/Src/Boot/Boot_ELF.cpp b/Source/Core/Core/Src/Boot/Boot_ELF.cpp index 087c2dbe16..c560c660a2 100644 --- a/Source/Core/Core/Src/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Src/Boot/Boot_ELF.cpp @@ -19,6 +19,7 @@ #include "Boot.h" #include "../HLE/HLE.h" #include "Boot_ELF.h" +#include "Boot_WiiWAD.h" #include "ElfReader.h" #include "MappedFile.h" diff --git a/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp new file mode 100644 index 0000000000..396367245d --- /dev/null +++ b/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp @@ -0,0 +1,279 @@ +// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Boot.h" +#include "../PowerPC/PowerPC.h" +#include "../HLE/HLE.h" +#include "../HW/Memmap.h" +#include "../ConfigManager.h" +#include "Blob.h" +#include "MappedFile.h" +#include "Boot_DOL.h" +#include "Boot_WiiWAD.h" +#include "AES/aes.h" +#include "MathUtil.h" + +class CBlobBigEndianReader +{ +public: + CBlobBigEndianReader(DiscIO::IBlobReader& _rReader) : m_rReader(_rReader) {} + + u32 Read32(u64 _Offset) + { + u32 Temp; + m_rReader.Read(_Offset, 4, (u8*)&Temp); + return(Common::swap32(Temp)); + } + +private: + DiscIO::IBlobReader& m_rReader; +}; + +std::vector m_TileMetaContent; +u16 m_BootIndex = -1; + +void AESDecode(u8* _pKey, u8* _IV, u8* _pSrc, u32 _Size, u8* _pDest) +{ + AES_KEY AESKey; + + AES_set_decrypt_key(_pKey, 128, &AESKey); + AES_cbc_encrypt(_pSrc, _pDest, _Size, &AESKey, _IV, AES_DECRYPT); +} + +u8* CreateWADEntry(DiscIO::IBlobReader& _rReader, u32 _Size, u64 _Offset) +{ + if (_Size > 0) + { + u8* pTmpBuffer = new u8[_Size]; + _dbg_assert_msg_(BOOT, pTmpBuffer!=0, "WiiWAD: Cant allocate memory for WAD entry"); + + if (!_rReader.Read(_Offset, _Size, pTmpBuffer)) + { + PanicAlert("WiiWAD: Could not read from file"); + } + return pTmpBuffer; + } + return NULL; +} + +void GetKeyFromTicket(u8* pTicket, u8* pTicketKey) +{ + u8 CommonKey[16]; + FILE* pMasterKeyFile = fopen(WII_MASTERKEY_FILE, "rb"); + _dbg_assert_msg_(BOOT, pMasterKeyFile!=0x0, "WiiWAD: Cant open MasterKeyFile for WII"); + + if (pMasterKeyFile) + { + fread(CommonKey, 16, 1, pMasterKeyFile); + fclose(pMasterKeyFile); + + u8 IV[16]; + memset(IV, 0, sizeof IV); + memcpy(IV, pTicket + 0x01dc, 8); + AESDecode(CommonKey, IV, pTicket + 0x01bf, 16, pTicketKey); + } +} + +bool ParseTMD(u8* pDataApp, u32 pDataAppSize, u8* pTicket, u8* pTMD) +{ + u8 DecryptTitleKey[16]; + u8 IV[16]; + + GetKeyFromTicket(pTicket, DecryptTitleKey); + + u32 numEntries = Common::swap16(pTMD + 0x01de); + m_BootIndex = Common::swap16(pTMD + 0x01e0); + u8* p = pDataApp; + + m_TileMetaContent.resize(numEntries); + + for (u32 i=0; i + +struct STileMetaContent +{ + u32 m_ContentID; + u16 m_Index; + u16 m_Type; + u32 m_Size; + + u8* m_pData; +}; + + +// [TODO]: this global internal stuff sux... the whole data should be inside the ES +// but this is the easiest way atm +extern std::vector m_TileMetaContent; \ No newline at end of file diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index c205bfe79e..ed3136cccf 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -125,6 +125,14 @@ bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios) m_BootType = BOOT_ELF; bNTSC = true; } + else if ((!strcasecmp(Extension.c_str(), ".wad")) && + CBoot::IsWiiWAD(m_strFilename.c_str())) + { + bWii = true; + Region = EUR_DIR; + m_BootType = BOOT_WIIWAD; + bNTSC = false; + } else if (!strcasecmp(Extension.c_str(), ".dol")) { bWii = CDolLoader::IsDolWii(m_strFilename.c_str()); diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index f71d13fed5..33138122fe 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -89,6 +89,7 @@ struct SCoreStartupParameter BOOT_ISO, BOOT_ELF, BOOT_DOL, + BOOT_WIIWAD, BOOT_BIOS }; EBootType m_BootType; diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h index 3c13b6f05d..459e0b87d2 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -54,6 +54,23 @@ #include "WII_IPC_HLE_Device.h" #include "../VolumeHandler.h" +#include "../boot/Boot_WiiWAD.h" + + +struct SContentAccess +{ + u32 m_Position; + STileMetaContent* m_pContent; +}; + +typedef std::map CContenAccessMap; +CContenAccessMap m_ContenAccessMap; +u32 AccessIdentID = 0x60000000; + + + + + // http://wiibrew.org/index.php?title=/dev/es class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device @@ -130,6 +147,90 @@ public: switch(Buffer.Parameter) { + case IOCTL_ES_OPENCONTENT: // 0x09 + { + u32 CFD = AccessIdentID++; + u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + m_ContenAccessMap[CFD].m_Position = 0; + m_ContenAccessMap[CFD].m_pContent = &m_TileMetaContent[Index]; + + Memory::Write_U32(CFD, _CommandAddress + 0x4); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD); + return true; + } + break; + + case IOCTL_ES_READCONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u32 Size = Buffer.PayloadBuffer[0].m_Size; + u32 Addr = Buffer.PayloadBuffer[0].m_Address; + + _dbg_assert_(WII_IPC_ES, m_ContenAccessMap.find(CFD) != m_ContenAccessMap.end()); + SContentAccess& rContent = m_ContenAccessMap[CFD]; + + u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position]; + u8* pDest = Memory::GetPointer(Addr); + + memcpy(pDest,pSrc, Size); + rContent.m_Position += Size; + + LOG(WII_IPC_ES, "ES: IOCTL_ES_READCONTENT: CFD %x, Addr 0x%x, Size %i -> stream pos %i", CFD, Addr, Size, rContent.m_Position); + + Memory::Write_U32(Size, _CommandAddress + 0x4); + return true; + } + break; + + case IOCTL_ES_CLOSECONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + CContenAccessMap::iterator itr = m_ContenAccessMap.find(CFD); + m_ContenAccessMap.erase(itr); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_CLOSECONTENT: CFD %x", CFD); + + Memory::Write_U32(0, _CommandAddress + 0x4); + return true; + } + break; + + case IOCTL_ES_SEEKCONTENT: + { + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + 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_ContenAccessMap.find(CFD) != m_ContenAccessMap.end()); + SContentAccess& rContent = m_ContenAccessMap[CFD]; + + switch(Mode) + { + case 0: // SET + rContent.m_Position = Addr; + break; + + case 1: // CUR + break; + + case 2: // END + rContent.m_Position = rContent.m_pContent->m_Size; + break; + } + + LOG(WII_IPC_ES, "ES: IOCTL_ES_SEEKCONTENT: CFD %x, Addr 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position); + + Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4); + return true; + } + break; + case IOCTL_ES_GETTITLEDIR: // 0x1d { /* I changed reading the TitleID from disc to reading from the @@ -166,7 +267,9 @@ public: case IOCTL_ES_GETVIEWCNT: // 0x12 (Input: 8 bytes, Output: 4 bytes) { if(Buffer.NumberInBuffer) + { u32 InBuffer = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + } // Should we write something here? //Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp index 2653771c35..c21de268d4 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -310,6 +310,14 @@ void dcbtst(UGeckoInstruction _inst) // TODO(ector) check docs void dcbz(UGeckoInstruction _inst) { + // !!! after the dcbz follows a dcbf... dont clear the memory in this case !!! + // 0x81330c2c + u32 NextOpcode = Memory::Read_U32(PC+4); + if (NextOpcode == 0x7C0400AC) + { + return; + } + // HACK but works... we think Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp index 7ed0ed84df..f0b28f797e 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp @@ -255,6 +255,8 @@ // Zero cache line. void Jit64::dcbz(UGeckoInstruction inst) { + Default(inst); return; + if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff) {Default(inst); return;} // turn off from debugger INSTRUCTION_START; diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index d4538c4183..3c53bcd8d7 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -21,6 +21,7 @@ files = ["Console.cpp", "Boot/Boot_BIOSEmu.cpp", "Boot/Boot_DOL.cpp", "Boot/Boot_ELF.cpp", + "Boot/Boot_WiiWAD.cpp", "Boot/ElfReader.cpp", "Debugger/Debugger_BreakPoints.cpp", "Debugger/Debugger_SymbolMap.cpp", diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 401349f43a..15745e00cd 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -409,7 +409,7 @@ void CFrame::DoOpen(bool Boot) wxEmptyString, wxEmptyString, wxEmptyString, wxString::Format ( - _T("All GC/Wii files (elf, dol, gcm, iso)|*.elf;*.dol;*.gcm;*.iso;*.gcz|All files (%s)|%s"), + _T("All GC/Wii files (elf, dol, gcm, iso, wad)|*.elf;*.dol;*.gcm;*.iso;*.gcz;*.wad|All files (%s)|%s"), wxFileSelectorDefaultWildcardStr, wxFileSelectorDefaultWildcardStr ),