diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 6618036e3c..7f27014a4d 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -35,6 +35,7 @@ public: // Returns true if a map file exists, false if none could be found. static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file, std::string* title_id = nullptr); + static bool LoadMapFromFilename(); private: static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt); @@ -42,7 +43,6 @@ private: static void UpdateDebugger_MapLoaded(); - static bool LoadMapFromFilename(); static bool Boot_ELF(const std::string& filename); static bool Boot_WiiWAD(const std::string& filename); diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index 77885649dd..b174ff4c92 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -102,7 +102,7 @@ const char* ElfReader::GetSectionName(int section) const } // This is just a simple elf loader, good enough to load elfs generated by devkitPPC -bool ElfReader::LoadIntoMemory() +bool ElfReader::LoadIntoMemory(bool only_in_mem1) { INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); @@ -132,6 +132,9 @@ bool ElfReader::LoadIntoMemory() u32 srcSize = p->p_filesz; u32 dstSize = p->p_memsz; + if (only_in_mem1 && p->p_vaddr >= Memory::REALRAM_SIZE) + continue; + Memory::CopyToEmu(writeAddr, src, srcSize); if (srcSize < dstSize) Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); // zero out bss diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index 92392e2bc0..4580cf0715 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -39,7 +39,7 @@ public: ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } u32 GetEntryPoint() const { return entryPoint; } u32 GetFlags() const { return (u32)(header->e_flags); } - bool LoadIntoMemory(); + bool LoadIntoMemory(bool only_in_mem1 = false); bool LoadSymbols(); int GetNumSegments() const { return (int)(header->e_phnum); } diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 68eacfc3ed..4c31353f8b 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -140,6 +140,7 @@ set(SRCS ActionReplay.cpp IOS/Device.cpp IOS/DeviceStub.cpp IOS/IPC.cpp + IOS/MIOS.cpp IOS/DI/DI.cpp IOS/ES/ES.cpp IOS/ES/Formats.cpp diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 4221dc10d4..3974de3dfe 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -188,6 +188,7 @@ struct SConfig : NonCopyable BOOT_ELF, BOOT_DOL, BOOT_WII_NAND, + BOOT_MIOS, BOOT_BS2, BOOT_DFF }; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 711e74a12f..5d7b1da8d3 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -634,10 +634,6 @@ void EmuThread() FileMon::Close(); - // Stop audio thread - Actually this does nothing when using HLE - // emulation, but stops the DSP Interpreter when using LLE emulation. - DSP::GetDSPEmulator()->DSP_StopSoundStream(); - // We must set up this flag before executing HW::Shutdown() s_hardware_initialized = false; INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index dc6bcd4a36..60a6de3fd5 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -172,6 +172,7 @@ + @@ -408,6 +409,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 109608d2bb..b96b206c0f 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -752,6 +752,9 @@ IOS + + IOS + IOS\Network @@ -1419,6 +1422,9 @@ IOS + + IOS + diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index 9210f73f6a..38fb513875 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -177,6 +177,13 @@ DSPEmulator* GetDSPEmulator() } void Init(bool hle) +{ + Reinit(hle); + s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); + s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); +} + +void Reinit(bool hle) { s_dsp_emulator = CreateDSPEmulator(hle); s_dsp_is_lle = s_dsp_emulator->IsLLE(); @@ -206,9 +213,6 @@ void Init(bool hle) s_ARAM_Info.Hex = 0; s_AR_MODE = 1; // ARAM Controller has init'd s_AR_REFRESH = 156; // 156MHz - - s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); - s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); } void Shutdown() diff --git a/Source/Core/Core/HW/DSP.h b/Source/Core/Core/HW/DSP.h index 502233fe43..f189b00b72 100644 --- a/Source/Core/Core/HW/DSP.h +++ b/Source/Core/Core/HW/DSP.h @@ -60,6 +60,7 @@ union UDSPControl }; void Init(bool hle); +void Reinit(bool hle); void Shutdown(); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp index ca6e28acb8..fbb763c978 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp @@ -37,6 +37,12 @@ static bool s_request_disable_thread; DSPLLE::DSPLLE() = default; +DSPLLE::~DSPLLE() +{ + DSPCore_Shutdown(); + DSP_StopSoundStream(); +} + void DSPLLE::DoState(PointerWrap& p) { bool is_hle = false; diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.h b/Source/Core/Core/HW/DSPLLE/DSPLLE.h index dc951d52a7..be55b17a82 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.h +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.h @@ -22,6 +22,7 @@ class DSPLLE : public DSPEmulator { public: DSPLLE(); + ~DSPLLE(); bool Initialize(bool wii, bool dsp_thread) override; void Shutdown() override; diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index e338e76698..de9d2c726d 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -419,8 +419,24 @@ void Init() { DVDThread::Start(); - s_DISR.Hex = 0; + Reset(); s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted + s_disc_inside = false; + + s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); + s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); + + s_finish_executing_command = + CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); + + u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT); + CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata); +} + +// This doesn't reset any inserted disc or the cover state. +void Reset() +{ + s_DISR.Hex = 0; s_DICMDBUF[0].Hex = 0; s_DICMDBUF[1].Hex = 0; s_DICMDBUF[2].Hex = 0; @@ -441,7 +457,6 @@ void Init() s_pending_samples = 0; s_error_code = 0; - s_disc_inside = false; // The buffer is empty at start s_read_buffer_start_offset = 0; @@ -450,15 +465,6 @@ void Init() s_read_buffer_end_time = 0; s_disc_path_to_insert.clear(); - - s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); - s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); - - s_finish_executing_command = - CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); - - u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT); - CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata); } void Shutdown() diff --git a/Source/Core/Core/HW/DVDInterface.h b/Source/Core/Core/HW/DVDInterface.h index 90c534ea24..410aee8f3e 100644 --- a/Source/Core/Core/HW/DVDInterface.h +++ b/Source/Core/Core/HW/DVDInterface.h @@ -102,6 +102,7 @@ enum class ReplyType : u32 }; void Init(); +void Reset(); void Shutdown(); void DoState(PointerWrap& p); diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp index 71618d257f..69511aa946 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp @@ -232,7 +232,10 @@ void CEXIIPL::SetCS(int _iCS) void CEXIIPL::UpdateRTC() { - u32 epoch = SConfig::GetInstance().bWii ? WII_EPOCH : GC_EPOCH; + u32 epoch = + (SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS) ? + WII_EPOCH : + GC_EPOCH; u32 rtc = Common::swap32(GetEmulatedTime(epoch)); std::memcpy(m_RTC, &rtc, sizeof(u32)); } diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 63b0ddd2d2..3137a8ed85 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -61,12 +61,11 @@ void Init() void Shutdown() { + // IOS should always be shut down regardless of bWii because it can be running in GC mode (MIOS). + IOS::HLE::Shutdown(); // Depends on Memory + IOS::Shutdown(); if (SConfig::GetInstance().bWii) - { - IOS::HLE::Shutdown(); // Depends on Memory - IOS::Shutdown(); Core::ShutdownWiiRoot(); - } SystemTimers::Shutdown(); CPU::Shutdown(); diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index 0fa2ffe7fc..eb72f6de47 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -223,7 +223,12 @@ static void ThrottleCallback(u64 last_time, s64 cyclesLate) // SystemTimers::Init void PreInit() { - if (SConfig::GetInstance().bWii) + ChangePPCClock(SConfig::GetInstance().bWii ? Mode::Wii : Mode::GC); +} + +void ChangePPCClock(Mode mode) +{ + if (mode == Mode::Wii) s_cpu_core_clock = 729000000u; else s_cpu_core_clock = 486000000u; diff --git a/Source/Core/Core/HW/SystemTimers.h b/Source/Core/Core/HW/SystemTimers.h index ba060993d0..5ab65c809b 100644 --- a/Source/Core/Core/HW/SystemTimers.h +++ b/Source/Core/Core/HW/SystemTimers.h @@ -33,10 +33,17 @@ enum TIMER_RATIO = 12 }; +enum class Mode +{ + GC, + Wii, +}; + u32 GetTicksPerSecond(); void PreInit(); void Init(); void Shutdown(); +void ChangePPCClock(Mode mode); // Notify timing system that somebody wrote to the decrementer void DecrementerSet(); diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 419f5844b9..9274866b08 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -1113,6 +1113,9 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) u64 titleid = Memory::Read_U64(request.in_vectors[1].address + 16); u16 access = Memory::Read_U16(request.in_vectors[1].address + 24); + NOTICE_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", + TitleID, view, ticketid, devicetype, titleid, access); + // 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). @@ -1173,9 +1176,6 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) SetDefaultContentFile(tContentFile); } - ERROR_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", - TitleID, view, ticketid, devicetype, titleid, access); - // Generate a "reply" to the IPC command. ES_LAUNCH is unique because it // involves restarting IOS; IOS generates two acknowledgements in a row. // Note: If we just reset the PPC, don't write anything to the command buffer. This diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index cb0876527e..7abb1717ce 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -42,6 +42,7 @@ #include "Core/IOS/FS/FS.h" #include "Core/IOS/FS/FileIO.h" #include "Core/IOS/IPC.h" +#include "Core/IOS/MIOS.h" #include "Core/IOS/Network/Net.h" #include "Core/IOS/Network/SSL.h" #include "Core/IOS/Network/Socket.h" @@ -111,6 +112,7 @@ struct IosMemoryValues u32 ram_vendor; u32 unknown_begin; u32 unknown_end; + u32 sysmenu_sync; }; constexpr u32 ADDR_MEM1_SIZE = 0x3100; @@ -162,210 +164,210 @@ constexpr std::array ios_memory_values = { MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 12, 0xc020e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 13, 0xd0408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 14, 0xe0408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 15, 0xf0408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 17, 0x110408, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 21, 0x15040f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 22, 0x16050e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN, 0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION, - RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, + RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0, }, { 28, 0x1c070f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93800000, MEM2_ARENA_BEGIN, 0x937E0000, 0x937E0000, 0x93800000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93800000, 0x93820000, + RAM_VENDOR, 0x93800000, 0x93820000, 0, }, { 31, 0x1f0e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 33, 0x210e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 34, 0x220e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 35, 0x230e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 36, 0x240e18, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 37, 0x25161f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 38, 0x26101c, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 41, 0x290e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 43, 0x2b0e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 45, 0x2d0e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 46, 0x2e0e17, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 48, 0x30101c, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 53, 0x35161f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 55, 0x37161f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 56, 0x38161e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 57, 0x39171f, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 58, 0x3a1820, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 59, 0x3b1c21, 0x101811, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 61, 0x3d161e, 0x030110, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 62, 0x3e191e, 0x022712, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 80, 0x501b20, 0x030310, MEM1_SIZE, MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END, MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN, 0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION, - RAM_VENDOR, 0x93600000, 0x93620000, + RAM_VENDOR, 0x93600000, 0x93620000, 0, }, { 257, @@ -387,6 +389,7 @@ constexpr std::array ios_memory_values = { RAM_VENDOR_MIOS, PLACEHOLDER, PLACEHOLDER, + PLACEHOLDER, }}}; static void EnqueueEvent(u64 userdata, s64 cycles_late = 0) @@ -459,7 +462,7 @@ static bool SetupMemory(u64 ios_title_id) Memory::Write_U8(0xDE, ADDR_BOOT_FLAG); Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG); Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION); - Memory::Write_U32(0x00000000, ADDR_SYSMENU_SYNC); + Memory::Write_U32(target_imv->sysmenu_sync, ADDR_SYSMENU_SYNC); return true; } @@ -517,7 +520,6 @@ static void AddStaticDevices() void Init() { - AddStaticDevices(); s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread); } @@ -552,14 +554,31 @@ void Shutdown() Reset(true); } +constexpr u64 BC_TITLE_ID = 0x0000000100000100; +constexpr u64 MIOS_TITLE_ID = 0x0000000100000101; + bool Reload(const u64 ios_title_id) { + // A real Wii goes through several steps before getting to MIOS. + // + // * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game. + // * BC (similar to boot1) lowers the clock speed to the Flipper's and then launches boot2. + // * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu. + // + // Because we currently don't have boot1 and boot2, and BC is only ever used to launch MIOS + // (indirectly via boot2), we can just launch MIOS when BC is launched. + if (ios_title_id == BC_TITLE_ID) + return Reload(MIOS_TITLE_ID); + if (!SetupMemory(ios_title_id)) return false; s_active_title_id = ios_title_id; Reset(true); + if (ios_title_id == MIOS_TITLE_ID) + return MIOS::Load(); + AddStaticDevices(); return true; } @@ -629,6 +648,9 @@ void DoState(PointerWrap& p) p.Do(s_last_reply_time); p.Do(s_active_title_id); + if (s_active_title_id == MIOS_TITLE_ID) + return; + // We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can // successfully save or re-create /tmp for (auto& descriptor : s_fdmap) diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp new file mode 100644 index 0000000000..6fa93f6d68 --- /dev/null +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -0,0 +1,195 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/NandPaths.h" +#include "Core/Boot/Boot.h" +#include "Core/Boot/ElfReader.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/DSPEmulator.h" +#include "Core/HLE/HLE.h" +#include "Core/HW/DSP.h" +#include "Core/HW/DVDInterface.h" +#include "Core/HW/DVDThread.h" +#include "Core/HW/Memmap.h" +#include "Core/HW/SystemTimers.h" +#include "Core/IOS/MIOS.h" +#include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" +#include "DiscIO/NANDContentLoader.h" +#include "DiscIO/Volume.h" + +namespace IOS +{ +namespace HLE +{ +namespace MIOS +{ +constexpr u64 MIOS_TITLE_ID = 0x0000000100000101; + +// Source: https://wiibrew.org/wiki/ARM_Binaries +struct ARMBinary final +{ + explicit ARMBinary(const std::vector& bytes); + explicit ARMBinary(std::vector&& bytes); + + bool IsValid() const; + std::vector GetElf() const; + u32 GetHeaderSize() const; + u32 GetElfOffset() const; + u32 GetElfSize() const; + +private: + std::vector m_bytes; +}; + +ARMBinary::ARMBinary(const std::vector& bytes) : m_bytes(bytes) +{ +} + +ARMBinary::ARMBinary(std::vector&& bytes) : m_bytes(std::move(bytes)) +{ +} + +bool ARMBinary::IsValid() const +{ + // The header is at least 0x10. + if (m_bytes.size() < 0x10) + return false; + return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize()); +} + +std::vector ARMBinary::GetElf() const +{ + const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset(); + return std::vector(iterator, iterator + GetElfSize()); +} + +u32 ARMBinary::GetHeaderSize() const +{ + return Common::swap32(m_bytes.data()); +} + +u32 ARMBinary::GetElfOffset() const +{ + return Common::swap32(m_bytes.data() + 0x4); +} + +u32 ARMBinary::GetElfSize() const +{ + return Common::swap32(m_bytes.data() + 0x8); +} + +static std::vector GetMIOSBinary() +{ + const auto& loader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(MIOS_TITLE_ID, Common::FROM_SESSION_ROOT); + if (!loader.IsValid()) + return {}; + + const auto* content = loader.GetContentByIndex(loader.GetBootIndex()); + if (!content) + return {}; + + return content->m_Data->Get(); +} + +static void ReinitHardware() +{ + SConfig::GetInstance().bWii = false; + + // IOS clears mem2 and overwrites it with pseudo-random data (for security). + std::memset(Memory::m_pEXRAM, 0, Memory::EXRAM_SIZE); + // MIOS appears to only reset the DI and the PPC. + DVDInterface::Reset(); + PowerPC::Reset(); + // Note: this is specific to Dolphin and is required because we initialised it in Wii mode. + DSP::Reinit(SConfig::GetInstance().bDSPHLE); + DSP::GetDSPEmulator()->Initialize(SConfig::GetInstance().bWii, SConfig::GetInstance().bDSPThread); + + SystemTimers::ChangePPCClock(SystemTimers::Mode::GC); +} + +static void UpdateRunningGame() +{ + DVDThread::WaitUntilIdle(); + const DiscIO::IVolume& volume = DVDInterface::GetVolume(); + SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS; + SConfig::GetInstance().m_strName = volume.GetInternalName(); + SConfig::GetInstance().m_strGameID = volume.GetGameID(); + SConfig::GetInstance().m_revision = volume.GetRevision(); + + g_symbolDB.Clear(); + CBoot::LoadMapFromFilename(); + ::HLE::Clear(); + ::HLE::PatchFunctions(); + + NOTICE_LOG(IOS, "Running game: %s (%s)", SConfig::GetInstance().m_strName.c_str(), + SConfig::GetInstance().m_strGameID.c_str()); +} + +constexpr u32 ADDRESS_INIT_SEMAPHORE = 0x30f8; + +bool Load() +{ + Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); + Memory::Write_U32(0x09142001, 0x3180); + + ARMBinary mios{GetMIOSBinary()}; + if (!mios.IsValid()) + { + PanicAlertT("Failed to load MIOS. It is required for launching GameCube titles from Wii mode."); + Core::QueueHostJob(Core::Stop); + return false; + } + + std::vector elf_bytes = mios.GetElf(); + ElfReader elf{elf_bytes.data()}; + if (!elf.LoadIntoMemory(true)) + { + PanicAlertT("Failed to load MIOS ELF into memory."); + Core::QueueHostJob(Core::Stop); + return false; + } + + ReinitHardware(); + NOTICE_LOG(IOS, "Reinitialised hardware."); + + // Load symbols for the IPL if they exist. + g_symbolDB.Clear(); + if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) + { + ::HLE::Clear(); + ::HLE::PatchFunctions(); + } + + const PowerPC::CoreMode core_mode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::CoreMode::Interpreter); + MSR = 0; + PC = 0x3400; + NOTICE_LOG(IOS, "Loaded MIOS and bootstrapped PPC."); + + // IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes + // 0xdeadbeef there, then waits for it to be cleared by IOS before continuing. + while (Memory::Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef) + PowerPC::SingleStep(); + PowerPC::SetMode(core_mode); + + Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); + NOTICE_LOG(IOS, "IPL ready."); + UpdateRunningGame(); + return true; +} +} // namespace MIOS +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/MIOS.h b/Source/Core/Core/IOS/MIOS.h new file mode 100644 index 0000000000..f0be9d4ed3 --- /dev/null +++ b/Source/Core/Core/IOS/MIOS.h @@ -0,0 +1,16 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +namespace IOS +{ +namespace HLE +{ +namespace MIOS +{ +bool Load(); +} // namespace MIOS +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 67ed02601b..2beeb37517 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -189,11 +189,7 @@ void Init(int cpu_core) s_invalidate_cache_thread_safe = CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe); - ppcState.pagetable_base = 0; - ppcState.pagetable_hashmask = 0; - ppcState.tlb = {}; - - ResetRegisters(); + Reset(); InitializeCPUCore(cpu_core); ppcState.iCache.Init(); @@ -202,6 +198,16 @@ void Init(int cpu_core) breakpoints.ClearAllTemporary(); } +void Reset() +{ + ppcState.pagetable_base = 0; + ppcState.pagetable_hashmask = 0; + ppcState.tlb = {}; + + ResetRegisters(); + ppcState.iCache.Reset(); +} + void ScheduleInvalidateCacheThreadSafe(u32 address) { if (CPU::GetState() == CPU::State::CPU_RUNNING) diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 83647602dd..bdf883a4e0 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -136,6 +136,7 @@ extern MemChecks memchecks; extern PPCDebugInterface debug_interface; void Init(int cpu_core); +void Reset(); void Shutdown(); void DoState(PointerWrap& p); void ScheduleInvalidateCacheThreadSafe(u32 address); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 0073b9ea4b..e2ce058903 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -156,6 +156,19 @@ static std::string DoState(PointerWrap& p) return version_created_by; } + bool is_wii = + SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS; + const bool is_wii_currently = is_wii; + p.Do(is_wii); + if (is_wii != is_wii_currently) + { + OSD::AddMessage(StringFromFormat("Cannot load a savestate created under %s mode in %s mode", + is_wii ? "Wii" : "GC", is_wii_currently ? "Wii" : "GC"), + OSD::Duration::NORMAL, OSD::Color::RED); + p.SetMode(PointerWrap::MODE_MEASURE); + return version_created_by; + } + // Begin with video backend, so that it gets a chance to clear its caches and writeback modified // things to RAM g_video_backend->DoState(p);