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);