diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index b969d9d142..141b797be7 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -203,7 +203,7 @@ - + @@ -408,7 +408,7 @@ - + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 185642dc3e..7d498e2f03 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -559,7 +559,7 @@ HW %28Flipper/Hollywood%29\GCMemcard - + Boot @@ -1045,7 +1045,7 @@ IPC HLE %28IOS/Starlet%29\Net - + Boot diff --git a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp index 0353351cc1..45a010d13a 100644 --- a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp @@ -1,429 +1,445 @@ -// Copyright (C) 2003 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 "Common.h" -#include "CommonPaths.h" -#include "FileUtil.h" -#include "NandPaths.h" - -#include "../PowerPC/PowerPC.h" -#include "../Core.h" -#include "../HW/EXI_DeviceIPL.h" -#include "../HW/Memmap.h" -#include "../HW/DVDInterface.h" -#include "../HW/CPU.h" - -#include "../Host.h" -#include "../VolumeHandler.h" -#include "../PatchEngine.h" -#include "../MemTools.h" - -#include "../ConfigManager.h" -#include "VolumeCreator.h" -#include "Boot.h" -#include "HLE/HLE.h" -#include "SettingsGenerator.h" - -void CBoot::RunFunction(u32 _iAddr) -{ - PC = _iAddr; - LR = 0x00; - - while (PC != 0x00) - PowerPC::SingleStep(); -} - -// __________________________________________________________________________________________________ -// GameCube Bootstrap 2 HLE: -// copy the apploader to 0x81200000 -// execute the apploader, function by function, using the above utility. -bool CBoot::EmulatedBS2_GC() -{ - INFO_LOG(BOOT, "Faking GC BS2..."); - - UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - m_MSR.FP = 1; - - // Clear ALL memory - Memory::Clear(); - - // Write necessary values - // Here we write values to memory that the apploader does not take care of. Game info goes - // to 0x80000000 according to yagcd 4.2. - DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20); // write disc info - - Memory::Write_U32(0x0D15EA5E, 0x80000020); // booted from bootrom. 0xE5207C22 = booted from jtag - Memory::Write_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail) - // TODO determine why some games fail when using a retail id. (Seem to take different EXI paths, see ikaruga for example) - Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see yagcd 4.2.1.1.2 - - Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC - ? 0 : 1, 0x800000CC); // fake the VI Init of the IPL (yagcd 4.2.1.4) - - Memory::Write_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM) - - Memory::Write_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed - Memory::Write_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed - - Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi - Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi - Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi - - Memory::Write_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // preset time base ticks - // HIO checks this - //Memory::Write_U16(0x8200, 0x000030e6); // Console type - - HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader - - // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc, - // but the size can differ between discs. Compare with yagcd chap 13. - u32 iAppLoaderOffset = 0x2440; - u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10); - u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14) + VolumeHandler::Read32(iAppLoaderOffset + 0x18); - if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1)) - { - INFO_LOG(BOOT, "GC BS2: Not running apploader!"); - return false; - } - VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize); - - // Setup pointers like real BS2 does - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC) - { - PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0 - PowerPC::ppcState.gpr[2] = 0x81465cc0; // global pointer to Small Data Area 2 Base (haven't seen anything use it...meh) - PowerPC::ppcState.gpr[13] = 0x81465320; // global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) - } - else - { - PowerPC::ppcState.gpr[1] = 0x815edca8; - PowerPC::ppcState.gpr[2] = 0x814b5b20; - PowerPC::ppcState.gpr[13] = 0x814b4fc0; - } - - // TODO - Make Apploader(or just RunFunction()) debuggable!!! - - // Call iAppLoaderEntry. - DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry"); - u32 iAppLoaderFuncAddr = 0x80003100; - PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; - PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; - PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; - RunFunction(iAppLoaderEntry); - u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 0); - u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 4); - u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 8); - - // iAppLoaderInit - DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit"); - PowerPC::ppcState.gpr[3] = 0x81300000; - RunFunction(iAppLoaderInit); - - // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem). - // To give you an idea about where the stuff is located on the disc take a look at yagcd - // ch 13. - DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain"); - do - { - PowerPC::ppcState.gpr[3] = 0x81300004; - PowerPC::ppcState.gpr[4] = 0x81300008; - PowerPC::ppcState.gpr[5] = 0x8130000c; - - RunFunction(iAppLoaderMain); - - u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004); - u32 iLength = Memory::ReadUnchecked_U32(0x81300008); - u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c); - - INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength); - DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength); - - } while(PowerPC::ppcState.gpr[3] != 0x00); - - // iAppLoaderClose - DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose"); - RunFunction(iAppLoaderClose); - - // return - PC = PowerPC::ppcState.gpr[3]; - - // Load patches - std::string gameID = VolumeHandler::GetVolume()->GetUniqueID(); - PatchEngine::LoadPatches(gameID.c_str()); - - PowerPC::ppcState.DebugCount = 0; - - // If we have any patches that need to be applied very early, here's a good place - PatchEngine::ApplyFramePatches(); - - return true; -} - -bool CBoot::SetupWiiMemory(unsigned int _CountryCode) -{ - INFO_LOG(BOOT, "Setup Wii Memory..."); - - // Write the 256 byte setting.txt to memory. This may not be needed as - // most or all games read the setting.txt file from - // \title\00000001\00000002\data\setting.txt directly after the read the - // SYSCONF file. The games also read it to 0x3800, what is a little strange - // however is that it only reads the first 100 bytes of it. - std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_SETTING); - std::string area, model, code, video, game; - - - switch((DiscIO::IVolume::ECountry)_CountryCode) - { - case DiscIO::IVolume::COUNTRY_KOREA: - case DiscIO::IVolume::COUNTRY_TAIWAN: - // TODO: Determine if Korea / Taiwan have their own specific settings. - case DiscIO::IVolume::COUNTRY_JAPAN: - area = "JPN"; - video = "NTSC"; - break; - - case DiscIO::IVolume::COUNTRY_USA: - area = "USA"; - video = "NTSC"; - break; - - case DiscIO::IVolume::COUNTRY_EUROPE: - area = "EUR"; - video = "PAL"; - break; - - default: - // PanicAlertT("SetupWiiMem: Unknown country. Wii boot process will be switched to European settings."); - area = "EUR"; - video = "PAL"; - break; - } - - model = "RVL-001(" + area + ")"; - code = "L" + area.substr(0,1); - game = area.substr(0,2); - - SettingsGenerator gen; +// Copyright (C) 2003 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 "Common.h" +#include "CommonPaths.h" +#include "FileUtil.h" +#include "NandPaths.h" + +#include "../PowerPC/PowerPC.h" +#include "../Core.h" +#include "../HW/EXI_DeviceIPL.h" +#include "../HW/Memmap.h" +#include "../HW/DVDInterface.h" +#include "../HW/CPU.h" + +#include "../Host.h" +#include "../VolumeHandler.h" +#include "../PatchEngine.h" +#include "../MemTools.h" + +#include "../ConfigManager.h" +#include "VolumeCreator.h" +#include "Boot.h" +#include "HLE/HLE.h" +#include "SettingsHandler.h" + +void CBoot::RunFunction(u32 _iAddr) +{ + PC = _iAddr; + LR = 0x00; + + while (PC != 0x00) + PowerPC::SingleStep(); +} + +// __________________________________________________________________________________________________ +// GameCube Bootstrap 2 HLE: +// copy the apploader to 0x81200000 +// execute the apploader, function by function, using the above utility. +bool CBoot::EmulatedBS2_GC() +{ + INFO_LOG(BOOT, "Faking GC BS2..."); + + UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); + m_MSR.FP = 1; + + // Clear ALL memory + Memory::Clear(); + + // Write necessary values + // Here we write values to memory that the apploader does not take care of. Game info goes + // to 0x80000000 according to yagcd 4.2. + DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20); // write disc info + + Memory::Write_U32(0x0D15EA5E, 0x80000020); // booted from bootrom. 0xE5207C22 = booted from jtag + Memory::Write_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail) + // TODO determine why some games fail when using a retail id. (Seem to take different EXI paths, see ikaruga for example) + Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see yagcd 4.2.1.1.2 + + Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC + ? 0 : 1, 0x800000CC); // fake the VI Init of the IPL (yagcd 4.2.1.4) + + Memory::Write_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM) + + Memory::Write_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed + Memory::Write_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed + + Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi + Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi + Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi + + Memory::Write_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // preset time base ticks + // HIO checks this + //Memory::Write_U16(0x8200, 0x000030e6); // Console type + + HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader + + // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc, + // but the size can differ between discs. Compare with yagcd chap 13. + u32 iAppLoaderOffset = 0x2440; + u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10); + u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14) + VolumeHandler::Read32(iAppLoaderOffset + 0x18); + if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1)) + { + INFO_LOG(BOOT, "GC BS2: Not running apploader!"); + return false; + } + VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize); + + // Setup pointers like real BS2 does + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC) + { + PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0 + PowerPC::ppcState.gpr[2] = 0x81465cc0; // global pointer to Small Data Area 2 Base (haven't seen anything use it...meh) + PowerPC::ppcState.gpr[13] = 0x81465320; // global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) + } + else + { + PowerPC::ppcState.gpr[1] = 0x815edca8; + PowerPC::ppcState.gpr[2] = 0x814b5b20; + PowerPC::ppcState.gpr[13] = 0x814b4fc0; + } + + // TODO - Make Apploader(or just RunFunction()) debuggable!!! + + // Call iAppLoaderEntry. + DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry"); + u32 iAppLoaderFuncAddr = 0x80003100; + PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; + PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; + PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; + RunFunction(iAppLoaderEntry); + u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 0); + u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 4); + u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 8); + + // iAppLoaderInit + DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit"); + PowerPC::ppcState.gpr[3] = 0x81300000; + RunFunction(iAppLoaderInit); + + // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem). + // To give you an idea about where the stuff is located on the disc take a look at yagcd + // ch 13. + DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain"); + do + { + PowerPC::ppcState.gpr[3] = 0x81300004; + PowerPC::ppcState.gpr[4] = 0x81300008; + PowerPC::ppcState.gpr[5] = 0x8130000c; + + RunFunction(iAppLoaderMain); + + u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004); + u32 iLength = Memory::ReadUnchecked_U32(0x81300008); + u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c); + + INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength); + DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength); + + } while(PowerPC::ppcState.gpr[3] != 0x00); + + // iAppLoaderClose + DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose"); + RunFunction(iAppLoaderClose); + + // return + PC = PowerPC::ppcState.gpr[3]; + + // Load patches + std::string gameID = VolumeHandler::GetVolume()->GetUniqueID(); + PatchEngine::LoadPatches(gameID.c_str()); + + PowerPC::ppcState.DebugCount = 0; + + // If we have any patches that need to be applied very early, here's a good place + PatchEngine::ApplyFramePatches(); + + return true; +} + +bool CBoot::SetupWiiMemory(unsigned int _CountryCode) +{ + INFO_LOG(BOOT, "Setup Wii Memory..."); + + // Write the 256 byte setting.txt to memory. This may not be needed as + // most or all games read the setting.txt file from + // \title\00000001\00000002\data\setting.txt directly after the read the + // SYSCONF file. The games also read it to 0x3800, what is a little strange + // however is that it only reads the first 100 bytes of it. + std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_SETTING); + std::string area, model, code, video, game; + + + switch((DiscIO::IVolume::ECountry)_CountryCode) + { + case DiscIO::IVolume::COUNTRY_KOREA: + case DiscIO::IVolume::COUNTRY_TAIWAN: + // TODO: Determine if Korea / Taiwan have their own specific settings. + case DiscIO::IVolume::COUNTRY_JAPAN: + area = "JPN"; + video = "NTSC"; + break; + + case DiscIO::IVolume::COUNTRY_USA: + area = "USA"; + video = "NTSC"; + break; + + case DiscIO::IVolume::COUNTRY_EUROPE: + area = "EUR"; + video = "PAL"; + break; + + default: + // PanicAlertT("SetupWiiMem: Unknown country. Wii boot process will be switched to European settings."); + area = "EUR"; + video = "PAL"; + break; + } + + model = "RVL-001(" + area + ")"; + code = "L" + area.substr(0,1); + game = area.substr(0,2); + + + SettingsHandler gen; + std::string serno = ""; + if (File::Exists(settings_Filename)) + { + File::IOFile settingsFileHandle(settings_Filename, "rb"); + if(settingsFileHandle.ReadBytes((void*)gen.GetData(), SETTINGS_SIZE)){ + gen.Decrypt(); + serno = gen.GetValue("SERNO"); + gen.Reset(); + } + File::Delete(settings_Filename); + } + + if(serno.empty() || serno == "000000000"){ + serno = gen.generateSerialNumber(); + INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str()); + }else{ + INFO_LOG(BOOT, "Using serial number: %s", serno.c_str()); + } + gen.AddSetting("AREA", area.c_str()); gen.AddSetting("MODEL", model.c_str()); gen.AddSetting("DVD", "0"); gen.AddSetting("MPCH", "0x7FFE"); gen.AddSetting("CODE", code.c_str()); - gen.AddSetting("SERNO", "000000000"); + gen.AddSetting("SERNO", serno.c_str()); gen.AddSetting("VIDEO", video.c_str()); - gen.AddSetting("GAME", game.c_str()); - - - if (File::Exists(settings_Filename)) - { - File::Delete(settings_Filename); - } - File::CreateFullPath(settings_Filename); - - { - File::IOFile settingsFileHandle(settings_Filename, "wb"); - - if (!settingsFileHandle.WriteBytes(gen.GetData(), SETTINGS_SIZE)) - { - PanicAlertT("SetupWiiMem: Cant create setting file"); - return false; - } - Memory::WriteBigEData(gen.GetData(), 0x3800, SETTINGS_SIZE); - } - - /* - Set hardcoded global variables to Wii memory. These are partly collected from - Wiibrew. These values are needed for the games to function correctly. A few - values in this region will also be placed here by the game as it boots. - They are: - 0x80000038 Start of FST - 0x8000003c Size of FST Size - 0x80000060 Copyright code - */ - - DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20); // Game Code - Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word - Memory::Write_U32(0x00000001, 0x00000024); // Unknown - Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB - Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model - Memory::Write_U32(0x00000000, 0x00000030); // Init - Memory::Write_U32(0x817FEC60, 0x00000034); // Init - // 38, 3C should get start, size of FST through apploader - Memory::Write_U32(0x38a00040, 0x00000060); // Exception init - Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init - Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?) - Memory::Write_U32(0x8179b500, 0x000000f4); // __start - Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed - Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed - Memory::Write_U16(0x0000, 0x000030e6); // Console type - Memory::Write_U32(0x00000000, 0x000030c0); // EXI - Memory::Write_U32(0x00000000, 0x000030c4); // EXI - Memory::Write_U32(0x00000000, 0x000030dc); // Time - Memory::Write_U32(0x00000000, 0x000030d8); // Time - Memory::Write_U32(0x00000000, 0x000030f0); // Apploader - Memory::Write_U32(0x01800000, 0x00003100); // BAT - Memory::Write_U32(0x01800000, 0x00003104); // BAT - Memory::Write_U32(0x00000000, 0x0000310c); // Init - Memory::Write_U32(0x8179d500, 0x00003110); // Init - Memory::Write_U32(0x04000000, 0x00003118); // Unknown - Memory::Write_U32(0x04000000, 0x0000311c); // BAT - Memory::Write_U32(0x93400000, 0x00003120); // BAT - Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low - Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high - Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low - Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high - Memory::Write_U32(0x00000011, 0x00003138); // Console type - // 40 is copied from 88 after running apploader - Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4) - Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007) - Memory::Write_U16(0x0113, 0x0000315e); // Apploader - Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code - Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear) - Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision - - Memory::Write_U8(0x80, 0x0000315c); // OSInit - Memory::Write_U16(0x0000, 0x000030e0); // PADInit - Memory::Write_U32(0x80000000, 0x00003184); // GameID Address - - // Fake the VI Init of the IPL - Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC ? 0 : 1, 0x000000CC); - - // Clear exception handler. Why? Don't we begin with only zeros? - for (int i = 0x3000; i <= 0x3038; i += 4) - { - Memory::Write_U32(0x00000000, 0x80000000 + i); - } - return true; -} - -// __________________________________________________________________________________________________ -// Wii Bootstrap 2 HLE: -// copy the apploader to 0x81200000 -// execute the apploader -bool CBoot::EmulatedBS2_Wii() -{ - INFO_LOG(BOOT, "Faking Wii BS2..."); - - // setup wii memory - DiscIO::IVolume::ECountry CountryCode = DiscIO::IVolume::COUNTRY_UNKNOWN; - if (VolumeHandler::IsValid()) - CountryCode = VolumeHandler::GetVolume()->GetCountry(); - if (SetupWiiMemory(CountryCode) == false) - return false; - - // This is some kind of consistency check that is compared to the 0x00 - // values as the game boots. This location keep the 4 byte ID for as long - // as the game is running. The 6 byte ID at 0x00 is overwritten sometime - // after this check during booting. - VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4); - - // Execute the apploader - bool apploaderRan = false; - if (VolumeHandler::IsValid() && VolumeHandler::IsWii()) - { - UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - m_MSR.FP = 1; - - Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi - Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi - Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi - - HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader - - PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer - - u32 iAppLoaderOffset = 0x2440; // 0x1c40; - - // Load Apploader to Memory - u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10); - u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14); - if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1)) - { - ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted."); - return false; - } - VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize); - - //call iAppLoaderEntry - DEBUG_LOG(BOOT, "Call iAppLoaderEntry"); - - u32 iAppLoaderFuncAddr = 0x80004000; - PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; - PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; - PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; - RunFunction(iAppLoaderEntry); - u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0); - u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4); - u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8); - - // iAppLoaderInit - DEBUG_LOG(BOOT, "Run iAppLoaderInit"); - PowerPC::ppcState.gpr[3] = 0x81300000; - RunFunction(iAppLoaderInit); - - // Let the apploader load the exe to memory. At this point I get an unknown IPC command - // (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"); - do - { - PowerPC::ppcState.gpr[3] = 0x81300004; - PowerPC::ppcState.gpr[4] = 0x81300008; - PowerPC::ppcState.gpr[5] = 0x8130000c; - - RunFunction(iAppLoaderMain); - - u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004); - u32 iLength = Memory::ReadUnchecked_U32(0x81300008); - u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2; - - INFO_LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength); - DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength); - } while(PowerPC::ppcState.gpr[3] != 0x00); - - // iAppLoaderClose - DEBUG_LOG(BOOT, "Run iAppLoaderClose"); - RunFunction(iAppLoaderClose); - - apploaderRan = true; - - // Pass the "#002 check" - // Apploader writes the IOS version and revision here, we copy it - // Fake IOSv9 r2.4 if no version is found (elf loading) - u32 firmwareVer = Memory::Read_U32(0x80003188); - Memory::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x00003140); - - // Load patches and run startup patches - std::string gameID = VolumeHandler::GetVolume()->GetUniqueID(); - PatchEngine::LoadPatches(gameID.c_str()); - - // return - PC = PowerPC::ppcState.gpr[3]; - } - - PowerPC::ppcState.DebugCount = 0; - - return apploaderRan; -} - -// Returns true if apploader has run successfully -bool CBoot::EmulatedBS2(bool _bIsWii) -{ - return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC(); -} + gen.AddSetting("GAME", game.c_str()); + + + File::CreateFullPath(settings_Filename); + + { + File::IOFile settingsFileHandle(settings_Filename, "wb"); + + if (!settingsFileHandle.WriteBytes(gen.GetData(), SETTINGS_SIZE)) + { + PanicAlertT("SetupWiiMem: Cant create setting file"); + return false; + } + Memory::WriteBigEData(gen.GetData(), 0x3800, SETTINGS_SIZE); + } + + /* + Set hardcoded global variables to Wii memory. These are partly collected from + Wiibrew. These values are needed for the games to function correctly. A few + values in this region will also be placed here by the game as it boots. + They are: + 0x80000038 Start of FST + 0x8000003c Size of FST Size + 0x80000060 Copyright code + */ + + DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20); // Game Code + Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word + Memory::Write_U32(0x00000001, 0x00000024); // Unknown + Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB + Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model + Memory::Write_U32(0x00000000, 0x00000030); // Init + Memory::Write_U32(0x817FEC60, 0x00000034); // Init + // 38, 3C should get start, size of FST through apploader + Memory::Write_U32(0x38a00040, 0x00000060); // Exception init + Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init + Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?) + Memory::Write_U32(0x8179b500, 0x000000f4); // __start + Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed + Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed + Memory::Write_U16(0x0000, 0x000030e6); // Console type + Memory::Write_U32(0x00000000, 0x000030c0); // EXI + Memory::Write_U32(0x00000000, 0x000030c4); // EXI + Memory::Write_U32(0x00000000, 0x000030dc); // Time + Memory::Write_U32(0x00000000, 0x000030d8); // Time + Memory::Write_U32(0x00000000, 0x000030f0); // Apploader + Memory::Write_U32(0x01800000, 0x00003100); // BAT + Memory::Write_U32(0x01800000, 0x00003104); // BAT + Memory::Write_U32(0x00000000, 0x0000310c); // Init + Memory::Write_U32(0x8179d500, 0x00003110); // Init + Memory::Write_U32(0x04000000, 0x00003118); // Unknown + Memory::Write_U32(0x04000000, 0x0000311c); // BAT + Memory::Write_U32(0x93400000, 0x00003120); // BAT + Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low + Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high + Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low + Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high + Memory::Write_U32(0x00000011, 0x00003138); // Console type + // 40 is copied from 88 after running apploader + Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4) + Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007) + Memory::Write_U16(0x0113, 0x0000315e); // Apploader + Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code + Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear) + Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision + + Memory::Write_U8(0x80, 0x0000315c); // OSInit + Memory::Write_U16(0x0000, 0x000030e0); // PADInit + Memory::Write_U32(0x80000000, 0x00003184); // GameID Address + + // Fake the VI Init of the IPL + Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC ? 0 : 1, 0x000000CC); + + // Clear exception handler. Why? Don't we begin with only zeros? + for (int i = 0x3000; i <= 0x3038; i += 4) + { + Memory::Write_U32(0x00000000, 0x80000000 + i); + } + return true; +} + +// __________________________________________________________________________________________________ +// Wii Bootstrap 2 HLE: +// copy the apploader to 0x81200000 +// execute the apploader +bool CBoot::EmulatedBS2_Wii() +{ + INFO_LOG(BOOT, "Faking Wii BS2..."); + + // setup wii memory + DiscIO::IVolume::ECountry CountryCode = DiscIO::IVolume::COUNTRY_UNKNOWN; + if (VolumeHandler::IsValid()) + CountryCode = VolumeHandler::GetVolume()->GetCountry(); + if (SetupWiiMemory(CountryCode) == false) + return false; + + // This is some kind of consistency check that is compared to the 0x00 + // values as the game boots. This location keep the 4 byte ID for as long + // as the game is running. The 6 byte ID at 0x00 is overwritten sometime + // after this check during booting. + VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4); + + // Execute the apploader + bool apploaderRan = false; + if (VolumeHandler::IsValid() && VolumeHandler::IsWii()) + { + UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); + m_MSR.FP = 1; + + Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi + Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi + Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi + + HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader + + PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer + + u32 iAppLoaderOffset = 0x2440; // 0x1c40; + + // Load Apploader to Memory + u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10); + u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14); + if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1)) + { + ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted."); + return false; + } + VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize); + + //call iAppLoaderEntry + DEBUG_LOG(BOOT, "Call iAppLoaderEntry"); + + u32 iAppLoaderFuncAddr = 0x80004000; + PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; + PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; + PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; + RunFunction(iAppLoaderEntry); + u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0); + u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4); + u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8); + + // iAppLoaderInit + DEBUG_LOG(BOOT, "Run iAppLoaderInit"); + PowerPC::ppcState.gpr[3] = 0x81300000; + RunFunction(iAppLoaderInit); + + // Let the apploader load the exe to memory. At this point I get an unknown IPC command + // (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"); + do + { + PowerPC::ppcState.gpr[3] = 0x81300004; + PowerPC::ppcState.gpr[4] = 0x81300008; + PowerPC::ppcState.gpr[5] = 0x8130000c; + + RunFunction(iAppLoaderMain); + + u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004); + u32 iLength = Memory::ReadUnchecked_U32(0x81300008); + u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2; + + INFO_LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength); + DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength); + } while(PowerPC::ppcState.gpr[3] != 0x00); + + // iAppLoaderClose + DEBUG_LOG(BOOT, "Run iAppLoaderClose"); + RunFunction(iAppLoaderClose); + + apploaderRan = true; + + // Pass the "#002 check" + // Apploader writes the IOS version and revision here, we copy it + // Fake IOSv9 r2.4 if no version is found (elf loading) + u32 firmwareVer = Memory::Read_U32(0x80003188); + Memory::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x00003140); + + // Load patches and run startup patches + std::string gameID = VolumeHandler::GetVolume()->GetUniqueID(); + PatchEngine::LoadPatches(gameID.c_str()); + + // return + PC = PowerPC::ppcState.gpr[3]; + } + + PowerPC::ppcState.DebugCount = 0; + + return apploaderRan; +} + +// Returns true if apploader has run successfully +bool CBoot::EmulatedBS2(bool _bIsWii) +{ + return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC(); +} diff --git a/Source/Core/Core/Src/Boot/SettingsHandler.cpp b/Source/Core/Core/Src/Boot/SettingsHandler.cpp new file mode 100644 index 0000000000..9d115e373d --- /dev/null +++ b/Source/Core/Core/Src/Boot/SettingsHandler.cpp @@ -0,0 +1,136 @@ +// Copyright (C) 2003 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/ + +// Thanks to Treeki for writing the original class - 29/01/2012 + +#include "Common.h" +#include "CommonPaths.h" +#include "Timer.h" +#include "SettingsHandler.h" + +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#endif + +SettingsHandler::SettingsHandler() +{ + Reset(); +} + +const u8* SettingsHandler::GetData() const +{ + return m_buffer; +} + +const std::string SettingsHandler::GetValue(std::string key) +{ + std::string delim = std::string("\r\n"); + std::string toFind = delim + key + "="; + size_t found = decoded.find(toFind); + if (found!=std::string::npos){ + size_t delimFound = decoded.find(delim, found+toFind.length()); + if (delimFound == std::string::npos) + delimFound = decoded.length()-1; + return decoded.substr(found+toFind.length(), delimFound - (found+toFind.length())); + }else{ + toFind = key + "="; + size_t found = decoded.find(toFind); + if (found==0){ + size_t delimFound = decoded.find(delim, found+toFind.length()); + if (delimFound == std::string::npos) + delimFound = decoded.length()-1; + return decoded.substr(found+toFind.length(), delimFound - (found+toFind.length())); + } + } + + return ""; +} + + +void SettingsHandler::Decrypt() +{ + const u8 *str = m_buffer; + while(*str != 0){ + + if (m_position >= SETTINGS_SIZE) + return; + decoded.push_back((u8)(m_buffer[m_position] ^ m_key)); + m_position++; + str++; + m_key = ((m_key >> 31) | (m_key << 1)); + } +} + +void SettingsHandler::Reset() +{ + decoded = ""; + m_position = 0; + m_key = 0x73B5DBFA; + memset(m_buffer, 0, SETTINGS_SIZE); +} + +void SettingsHandler::AddSetting(const char *key, const char *value) +{ + while (*key != 0) + { + WriteByte(*key); + key++; + } + + WriteByte('='); + + while (*value != 0) + { + WriteByte(*value); + value++; + } + + WriteByte(13); + WriteByte(10); +} + +void SettingsHandler::WriteByte(u8 b) +{ + if (m_position >= SETTINGS_SIZE) + return; + + m_buffer[m_position] = b ^ m_key; + m_position++; + m_key = ((m_key >> 31) | (m_key << 1)); +} + +std::string SettingsHandler::generateSerialNumber() +{ + time_t rawtime; + struct tm * timeinfo; + char buffer [12]; + char serialNumber [12]; + + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + strftime (buffer,11,"%j%H%M%S",timeinfo); + + snprintf(serialNumber,11, "%s%i", buffer, (Common::Timer::GetTimeMs()>>1)&0xF); + serialNumber[10] = 0; + return std::string(serialNumber); +} \ No newline at end of file diff --git a/Source/Core/Core/Src/Boot/SettingsHandler.h b/Source/Core/Core/Src/Boot/SettingsHandler.h new file mode 100644 index 0000000000..55295ece17 --- /dev/null +++ b/Source/Core/Core/Src/Boot/SettingsHandler.h @@ -0,0 +1,50 @@ +// Copyright (C) 2003 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/ + +// Thanks to Treeki for writing the original class - 29/01/2012 + +#ifndef _SETTINGS_HANDLER_H +#define _SETTINGS_HANDLER_H + +#include + +#include "Common.h" +#include "../CoreParameter.h" +#define SETTINGS_SIZE 0x100 + +class SettingsHandler +{ +public: + SettingsHandler(); + + void AddSetting(const char *key, const char *value); + + const u8 *GetData() const; + const std::string GetValue(std::string key); + + void Decrypt(); + void Reset(); + std::string generateSerialNumber(); +private: + void WriteByte(u8 b); + + u8 m_buffer[SETTINGS_SIZE]; + u32 m_position, m_key; + std::string decoded; +}; + +#endif