diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 9381ee809e..fd1633ba30 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -37,6 +37,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); @@ -44,7 +45,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/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 836d635e58..a11b1658d5 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -278,7 +278,7 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable Memory::Write_U32(0x00000000, 0x000030f0); // Apploader - if (!IOS::HLE::SetupMemory(ios_title_id)) + if (!IOS::HLE::Reload(ios_title_id)) { return false; } diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index d88bf2097b..770f27e548 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -103,7 +103,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); @@ -133,6 +133,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 6a886761e4..e3d7c257a8 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -40,7 +40,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 e123989f7b..5d7b1da8d3 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -528,9 +528,11 @@ void EmuThread() Wiimote::LoadConfig(); // Activate Wiimotes which don't have source set to "None" + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); for (unsigned int i = 0; i != MAX_BBMOTES; ++i) - if (g_wiimote_sources[i]) - IOS::HLE::GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true); + if (g_wiimote_sources[i] && bt) + bt->AccessWiiMote(i | 0x100)->Activate(true); } AudioCommon::InitSoundStream(); @@ -632,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/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 803cd76fec..0780d93ca4 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -364,6 +364,16 @@ void LogPendingEvents() } } +// Should only be called from the CPU thread after the PPC clock has changed +void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) +{ + for (Event& ev : s_event_queue) + { + const s64 ticks = (ev.time - g_global_timer) * new_ppc_clock / old_ppc_clock; + ev.time = g_global_timer + ticks; + } +} + void Idle() { if (SConfig::GetInstance().bSyncGPUOnSkipIdleHack) diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 28263be94c..2cdee0c6cf 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -91,6 +91,8 @@ void LogPendingEvents(); std::string GetScheduledEventsSummary(); +void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock); + u32 GetFakeDecStartValue(); void SetFakeDecStartValue(u32 val); u64 GetFakeDecStartTicks(); 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..4b3a9fda8a 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -223,10 +223,17 @@ 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) +{ + const u32 previous_clock = s_cpu_core_clock; + if (mode == Mode::Wii) s_cpu_core_clock = 729000000u; else s_cpu_core_clock = 486000000u; + CoreTiming::AdjustEventQueueTimes(s_cpu_core_clock, previous_clock); } void Init() 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 abe00c215a..9274866b08 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -317,6 +317,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) return Decrypt(request); case IOCTL_ES_LAUNCH: return Launch(request); + case IOCTL_ES_LAUNCHBC: + return LaunchBC(request); case IOCTL_ES_CHECKKOREAREGION: return CheckKoreaRegion(request); case IOCTL_ES_GETDEVICECERT: @@ -1103,7 +1105,6 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) { _dbg_assert_(IOS_ES, request.in_vectors.size() == 2); bool bSuccess = false; - bool bReset = false; u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u32 view = Memory::Read_U32(request.in_vectors[1].address); @@ -1112,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). @@ -1168,63 +1172,65 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request) } else { - bool* wiiMoteConnected = new bool[MAX_BBMOTES]; - if (!SConfig::GetInstance().m_bt_passthrough_enabled) - { - BluetoothEmu* s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < MAX_BBMOTES; i++) - wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); - } - - Reset(true); - Reinit(); - SetupMemory(ios_to_load); - bReset = true; - - if (!SConfig::GetInstance().m_bt_passthrough_enabled) - { - BluetoothEmu* s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < MAX_BBMOTES; i++) - { - if (wiiMoteConnected[i]) - { - s_Usb->m_WiiMotes[i].Activate(false); - s_Usb->m_WiiMotes[i].Activate(true); - } - else - { - s_Usb->m_WiiMotes[i].Activate(false); - } - } - } - delete[] wiiMoteConnected; + ResetAfterLaunch(ios_to_load); SetDefaultContentFile(tContentFile); } - // Note: If we just reset the PPC, don't write anything to the command buffer. This - // could clobber the DOL we just loaded. - - ERROR_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", - TitleID, view, ticketid, devicetype, titleid, access); - // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 - // 0001000248414341 ffff - - // This is necessary because Reset(true) above deleted this object. Ew. - - if (!bReset) - { - // The command type is overwritten with the reply type. - Memory::Write_U32(IPC_REPLY, request.address); - // IOS also writes back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTLV, request.address + 8); - } - // 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 + // could clobber the DOL we just loaded. EnqueueCommandAcknowledgement(request.address, 0); return GetNoReply(); } +IPCCommandResult ES::LaunchBC(const IOCtlVRequest& request) +{ + if (request.in_vectors.size() != 0 || request.io_vectors.size() != 0) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + // Here, IOS checks the clock speed and prevents ioctlv 0x25 from being used in GC mode. + // An alternative way to do this is to check whether the current active IOS is MIOS. + if (GetVersion() == 0x101) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + ResetAfterLaunch(0x00000001'00000100); + EnqueueCommandAcknowledgement(request.address, 0); + return GetNoReply(); +} + +void ES::ResetAfterLaunch(const u64 ios_to_load) const +{ + auto bt = std::static_pointer_cast(GetDeviceByName("/dev/usb/oh1/57e/305")); + bool* wiiMoteConnected = new bool[MAX_BBMOTES]; + if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt) + { + for (unsigned int i = 0; i < MAX_BBMOTES; i++) + wiiMoteConnected[i] = bt->m_WiiMotes[i].IsConnected(); + } + + Reload(ios_to_load); + + // Get the new Bluetooth device. Note that it is not guaranteed to exist. + bt = std::static_pointer_cast(GetDeviceByName("/dev/usb/oh1/57e/305")); + if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt) + { + for (unsigned int i = 0; i < MAX_BBMOTES; i++) + { + if (wiiMoteConnected[i]) + { + bt->m_WiiMotes[i].Activate(false); + bt->m_WiiMotes[i].Activate(true); + } + else + { + bt->m_WiiMotes[i].Activate(false); + } + } + } + delete[] wiiMoteConnected; +} + IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request) { // note by DacoTaco : name is unknown, I just tried to name it SOMETHING. diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 83acd77865..2fbce4d7f1 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -90,7 +90,7 @@ private: IOCTL_ES_DELETETITLECONTENT = 0x22, IOCTL_ES_SEEKCONTENT = 0x23, IOCTL_ES_OPENTITLECONTENT = 0x24, - // IOCTL_ES_LAUNCHBC = 0x25, + IOCTL_ES_LAUNCHBC = 0x25, // IOCTL_ES_EXPORTTITLEINIT = 0x26, // IOCTL_ES_EXPORTCONTENTBEGIN = 0x27, // IOCTL_ES_EXPORTCONTENTDATA = 0x28, @@ -182,6 +182,7 @@ private: IPCCommandResult Encrypt(const IOCtlVRequest& request); IPCCommandResult Decrypt(const IOCtlVRequest& request); IPCCommandResult Launch(const IOCtlVRequest& request); + IPCCommandResult LaunchBC(const IOCtlVRequest& request); IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request); IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request); IPCCommandResult Sign(const IOCtlVRequest& request); @@ -189,6 +190,8 @@ private: IPCCommandResult DIGetTicketView(const IOCtlVRequest& request); IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request); + void ResetAfterLaunch(u64 ios_to_load) const; + const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id); u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index); diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index 1580791a80..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) @@ -421,7 +424,7 @@ u32 GetVersion() return static_cast(s_active_title_id); } -bool SetupMemory(u64 ios_title_id) +static bool SetupMemory(u64 ios_title_id) { auto target_imv = std::find_if( ios_memory_values.begin(), ios_memory_values.end(), @@ -433,8 +436,6 @@ bool SetupMemory(u64 ios_title_id) return false; } - s_active_title_id = ios_title_id; - Memory::Write_U32(target_imv->mem1_physical_size, ADDR_MEM1_SIZE); Memory::Write_U32(target_imv->mem1_simulated_size, ADDR_MEM1_SIM_SIZE); Memory::Write_U32(target_imv->mem1_end, ADDR_MEM1_END); @@ -461,7 +462,7 @@ 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; } @@ -477,7 +478,7 @@ std::shared_ptr AddDevice(const char* device_name) return device; } -void Reinit() +static void AddStaticDevices() { std::lock_guard lock(s_device_map_mutex); _assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized"); @@ -519,13 +520,11 @@ void Reinit() void Init() { - Reinit(); - s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread); } -void Reset(bool hard) +void Reset(const bool clear_devices) { CoreTiming::RemoveAllEvents(s_event_enqueue); @@ -538,7 +537,7 @@ void Reset(bool hard) device.reset(); } - if (hard) + if (clear_devices) { std::lock_guard lock(s_device_map_mutex); s_device_map.clear(); @@ -555,6 +554,35 @@ 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; +} + void SetDefaultContentFile(const std::string& file_name) { std::lock_guard lock(s_device_map_mutex); @@ -618,6 +646,10 @@ void DoState(PointerWrap& p) p.Do(s_request_queue); p.Do(s_reply_queue); 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 diff --git a/Source/Core/Core/IOS/IPC.h b/Source/Core/Core/IOS/IPC.h index 7508be12f9..09b3c1179c 100644 --- a/Source/Core/Core/IOS/IPC.h +++ b/Source/Core/Core/IOS/IPC.h @@ -45,21 +45,16 @@ enum IPCCommandType : u32 IPC_REPLY = 8, }; -// Init +// Init events and devices void Init(); - -// Needs to be called after Reset(true) to recreate the device tree -void Reinit(); - -u32 GetVersion(); - -bool SetupMemory(u64 ios_title_id); - +// Reset all events and devices (and optionally clear them) +void Reset(bool clear_devices = false); // Shutdown void Shutdown(); -// Reset -void Reset(bool hard = false); +// Reload IOS (to a possibly different version); set up memory and devices. +bool Reload(u64 ios_title_id); +u32 GetVersion(); // Do State void DoState(PointerWrap& p); 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/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index 69a12cdd8d..f167d1ae23 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -50,7 +50,6 @@ BluetoothEmu::BluetoothEmu(u32 device_id, const std::string& device_name) // Activate only first Wii Remote by default _conf_pads BT_DINF; - SetUsbPointer(this); if (!sysconf.GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) { PanicAlertT("Trying to read from invalid SYSCONF\nWii Remote Bluetooth IDs are not available"); @@ -103,8 +102,8 @@ BluetoothEmu::BluetoothEmu(u32 device_id, const std::string& device_name) BluetoothEmu::~BluetoothEmu() { + Host_SetWiiMoteConnectionState(0); m_WiiMotes.clear(); - SetUsbPointer(nullptr); } template diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp index dddd3feb64..d374ba7451 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp @@ -25,18 +25,6 @@ namespace IOS { namespace HLE { -static Device::BluetoothEmu* s_Usb = nullptr; - -Device::BluetoothEmu* GetUsbPointer() -{ - return s_Usb; -} - -void SetUsbPointer(Device::BluetoothEmu* ptr) -{ - s_Usb = ptr; -} - WiimoteDevice::WiimoteDevice(Device::BluetoothEmu* host, int number, bdaddr_t bd, bool ready) : m_BD(bd), m_Name(number == WIIMOTE_BALANCE_BOARD ? "Nintendo RVL-WBC-01" : "Nintendo RVL-CNT-01"), @@ -943,6 +931,9 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _ DEBUG_LOG(WIIMOTE, " Data: %s", ArrayToString(pData, _Size, 50).c_str()); DEBUG_LOG(WIIMOTE, " Channel: %x", _channelID); - IOS::HLE::s_Usb->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + if (bt) + bt->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size); } } diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h index c7e1066d5f..3937a0c777 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h @@ -23,9 +23,6 @@ namespace Device class BluetoothEmu; } -Device::BluetoothEmu* GetUsbPointer(); -void SetUsbPointer(Device::BluetoothEmu* ptr); - class CBigEndianBuffer { public: diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 2f5c071f00..d47d8b1ac9 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -521,11 +521,13 @@ void ChangeWiiPads(bool instantly) if (instantly && (s_controllers >> 4) == controllers) return; + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); for (int i = 0; i < MAX_WIIMOTES; ++i) { g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE; - if (!SConfig::GetInstance().m_bt_passthrough_enabled) - IOS::HLE::GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); + if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt) + bt->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); } } 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 7714659954..e2ce058903 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 76; // Last changed in PR 4829 +static const u32 STATE_VERSION = 77; // Last changed in PR 4784 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, @@ -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); diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp index 732b770ce6..4c001c6310 100644 --- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp @@ -16,6 +16,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/HW/SystemTimers.h" #include "DolphinWX/DolphinSlider.h" #include "DolphinWX/WxEventUtils.h" @@ -181,12 +182,12 @@ void AdvancedConfigPane::OnCustomRTCTimeChanged(wxCommandEvent& event) void AdvancedConfigPane::UpdateCPUClock() { - bool wii = SConfig::GetInstance().bWii; - int percent = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * 100.f)); - int clock = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * (wii ? 729.f : 486.f))); + int core_clock = SystemTimers::GetTicksPerSecond() / pow(10, 6); + int percent = static_cast(std::round(SConfig::GetInstance().m_OCFactor * 100.f)); + int clock = static_cast(std::round(SConfig::GetInstance().m_OCFactor * core_clock)); m_clock_override_text->SetLabel( - SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d mhz)", percent, clock) : ""); + SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d MHz)", percent, clock) : ""); } void AdvancedConfigPane::LoadCustomRTC() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index c40e6d0916..94b91179c5 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1245,7 +1245,10 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect) !SConfig::GetInstance().m_bt_passthrough_enabled) { bool was_unpaused = Core::PauseAndLock(true); - IOS::HLE::GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + if (bt) + bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect); const char* message = connect ? "Wii Remote %i connected" : "Wii Remote %i disconnected"; Core::DisplayMessage(StringFromFormat(message, wm_idx + 1), 3000); Host_UpdateMainFrame(); @@ -1258,10 +1261,11 @@ void CFrame::OnConnectWiimote(wxCommandEvent& event) if (SConfig::GetInstance().m_bt_passthrough_enabled) return; bool was_unpaused = Core::PauseAndLock(true); - ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, - !IOS::HLE::GetUsbPointer() - ->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100) - ->IsConnected()); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + const bool is_connected = + bt && bt->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)->IsConnected(); + ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !is_connected); Core::PauseAndLock(false, was_unpaused); } @@ -1416,8 +1420,9 @@ void CFrame::UpdateGUI() // Tools GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats); - bool ShouldEnableWiimotes = - Running && SConfig::GetInstance().bWii && !SConfig::GetInstance().m_bt_passthrough_enabled; + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + bool ShouldEnableWiimotes = Running && bt && !SConfig::GetInstance().m_bt_passthrough_enabled; GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(ShouldEnableWiimotes); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(ShouldEnableWiimotes); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(ShouldEnableWiimotes); @@ -1426,21 +1431,13 @@ void CFrame::UpdateGUI() if (ShouldEnableWiimotes) { bool was_unpaused = Core::PauseAndLock(true); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE1) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0100)->IsConnected()); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE2) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0101)->IsConnected()); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE3) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0102)->IsConnected()); - GetMenuBar() - ->FindItem(IDM_CONNECT_WIIMOTE4) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0103)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(bt->AccessWiiMote(0x0100)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Check(bt->AccessWiiMote(0x0101)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Check(bt->AccessWiiMote(0x0102)->IsConnected()); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Check(bt->AccessWiiMote(0x0103)->IsConnected()); GetMenuBar() ->FindItem(IDM_CONNECT_BALANCEBOARD) - ->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0104)->IsConnected()); + ->Check(bt->AccessWiiMote(0x0104)->IsConnected()); Core::PauseAndLock(false, was_unpaused); } diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp index 1613fa62ac..7cc814d05b 100644 --- a/Source/Core/DolphinWX/MainNoGUI.cpp +++ b/Source/Core/DolphinWX/MainNoGUI.cpp @@ -143,7 +143,10 @@ void Host_ConnectWiimote(int wm_idx, bool connect) { Core::QueueHostJob([=] { bool was_unpaused = Core::PauseAndLock(true); - IOS::HLE::GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); + const auto bt = std::static_pointer_cast( + IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305")); + if (bt) + bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect); Host_UpdateMainFrame(); Core::PauseAndLock(false, was_unpaused); });