From 12801fd722e4f4038722fc35de4edcb1f5d1b3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 7 May 2017 17:58:26 +0200 Subject: [PATCH] IOS: Allow instances that are not tied to emulation This enables constructing an IOS instance that is not tied to emulation and that can be simply used for internal purposes (ES, FS). NAND root initialisation was moved to IOS since we cannot rely on HW doing that for us anymore, and technically the NAND is entirely managed by IOS anyway. --- Source/Core/Core/HW/HW.cpp | 4 - Source/Core/Core/IOS/IOS.cpp | 88 ++++++++++++++++------ Source/Core/Core/IOS/IOS.h | 30 ++++++-- Source/Core/Core/IOS/USB/OH0/OH0Device.cpp | 4 +- Source/Core/Core/IOS/WFS/WFSI.cpp | 4 +- 5 files changed, 92 insertions(+), 38 deletions(-) diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index b9017b9f21..253883d9b1 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -24,7 +24,6 @@ #include "Core/IOS/IOS.h" #include "Core/Movie.h" #include "Core/State.h" -#include "Core/WiiRoot.h" namespace HW { @@ -50,7 +49,6 @@ void Init() if (SConfig::GetInstance().bWii) { - Core::InitializeWiiRoot(Core::WantsDeterminism()); IOS::Init(); IOS::HLE::Init(); // Depends on Memory } @@ -61,8 +59,6 @@ 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) - Core::ShutdownWiiRoot(); SystemTimers::Shutdown(); CPU::Shutdown(); diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 8720882bac..eaf2fa605b 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -51,13 +51,14 @@ #include "Core/IOS/WFS/WFSI.h" #include "Core/IOS/WFS/WFSSRV.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/WiiRoot.h" #include "DiscIO/NANDContentLoader.h" namespace IOS { namespace HLE { -static std::unique_ptr s_ios; +static std::unique_ptr s_ios; constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; @@ -172,29 +173,17 @@ constexpr u64 IOS80_TITLE_ID = 0x0000000100000050; constexpr u64 BC_TITLE_ID = 0x0000000100000100; constexpr u64 MIOS_TITLE_ID = 0x0000000100000101; -Kernel::Kernel(u64 title_id) : m_title_id(title_id) +Kernel::Kernel() { - INFO_LOG(IOS, "Starting IOS %016" PRIx64, title_id); - - if (!SetupMemory(title_id, MemorySetupType::IOSReload)) - WARN_LOG(IOS, "No information about this IOS -- cannot set up memory values"); - - if (title_id == MIOS_TITLE_ID) - { - MIOS::Load(); - return; - } - - // IOS re-inits IPC and sends a dummy ack during its boot process. - EnqueueIPCAcknowledgement(0); - - AddStaticDevices(); + // Until the Wii root and NAND path stuff is entirely managed by IOS and made non-static, + // using more than one IOS instance at a time is not supported. + _assert_(GetIOS() == nullptr); + Core::InitializeWiiRoot(false); + AddCoreDevices(); } Kernel::~Kernel() { - CoreTiming::RemoveAllEvents(s_event_enqueue); - // Close all devices that were opened for (auto& device : m_fdmap) { @@ -207,6 +196,36 @@ Kernel::~Kernel() std::lock_guard lock(m_device_map_mutex); m_device_map.clear(); } + + Core::ShutdownWiiRoot(); +} + +EmulationKernel::EmulationKernel(u64 title_id) +{ + m_title_id = title_id; + INFO_LOG(IOS, "Starting IOS %016" PRIx64, title_id); + + if (!SetupMemory(title_id, MemorySetupType::IOSReload)) + WARN_LOG(IOS, "No information about this IOS -- cannot set up memory values"); + + Core::InitializeWiiRoot(Core::WantsDeterminism()); + + if (title_id == MIOS_TITLE_ID) + { + MIOS::Load(); + return; + } + + // IOS re-inits IPC and sends a dummy ack during its boot process. + EnqueueIPCAcknowledgement(0); + + AddCoreDevices(); + AddStaticDevices(); +} + +EmulationKernel::~EmulationKernel() +{ + CoreTiming::RemoveAllEvents(s_event_enqueue); } // The title ID is a u64 where the first 32 bits are used for the title type. @@ -217,6 +236,16 @@ u32 Kernel::GetVersion() const return static_cast(m_title_id); } +std::shared_ptr Kernel::GetFS() +{ + return std::static_pointer_cast(m_device_map.at("/dev/fs")); +} + +std::shared_ptr Kernel::GetES() +{ + return std::static_pointer_cast(m_device_map.at("/dev/es")); +} + // Since we don't have actual processes, we keep track of only the PPC's UID/GID. // These functions roughly correspond to syscalls 0x2b, 0x2c, 0x2d, 0x2e (though only for the PPC). void Kernel::SetUidForPPC(u32 uid) @@ -289,7 +318,7 @@ bool Kernel::BootIOS(const u64 ios_title_id) // Shut down the active IOS first before switching to the new one. s_ios.reset(); - s_ios = std::make_unique(ios_title_id); + s_ios = std::make_unique(ios_title_id); return true; } @@ -299,10 +328,16 @@ void Kernel::AddDevice(std::unique_ptr device) m_device_map[device->GetDeviceName()] = std::move(device); } +void Kernel::AddCoreDevices() +{ + std::lock_guard lock(m_device_map_mutex); + AddDevice(std::make_unique(*this, "/dev/fs")); + AddDevice(std::make_unique(*this, "/dev/es")); +} + void Kernel::AddStaticDevices() { std::lock_guard lock(m_device_map_mutex); - _assert_msg_(IOS, m_device_map.empty(), "Reinit called while already initialized"); if (!SConfig::GetInstance().m_bt_passthrough_enabled) AddDevice(std::make_unique(*this, "/dev/usb/oh1/57e/305")); @@ -311,8 +346,6 @@ void Kernel::AddStaticDevices() AddDevice(std::make_unique(*this, "/dev/stm/immediate")); AddDevice(std::make_unique(*this, "/dev/stm/eventhook")); - AddDevice(std::make_unique(*this, "/dev/fs")); - AddDevice(std::make_unique(*this, "/dev/es")); AddDevice(std::make_unique(*this, "/dev/di")); AddDevice(std::make_unique(*this, "/dev/net/kd/request")); AddDevice(std::make_unique(*this, "/dev/net/kd/time")); @@ -351,6 +384,11 @@ std::shared_ptr Kernel::GetDeviceByName(const std::string& devic return iterator != m_device_map.end() ? iterator->second : nullptr; } +std::shared_ptr EmulationKernel::GetDeviceByName(const std::string& device_name) +{ + return Kernel::GetDeviceByName(device_name); +} + // Returns the FD for the newly opened device (on success) or an error code. s32 Kernel::OpenDevice(OpenRequest& request) { @@ -639,7 +677,7 @@ void Init() }); // Start with IOS80 to simulate part of the Wii boot process. - s_ios = std::make_unique(IOS80_TITLE_ID); + s_ios = std::make_unique(IOS80_TITLE_ID); // On a Wii, boot2 launches the system menu IOS, which then launches the system menu // (which bootstraps the PPC). Bootstrapping the PPC results in memory values being set up. // This means that the constants in the 0x3100 region are always set up by the time @@ -653,7 +691,7 @@ void Shutdown() s_ios.reset(); } -Kernel* GetIOS() +EmulationKernel* GetIOS() { return s_ios.get(); } diff --git a/Source/Core/Core/IOS/IOS.h b/Source/Core/Core/IOS/IOS.h index ffc469c882..b9d540b7ba 100644 --- a/Source/Core/Core/IOS/IOS.h +++ b/Source/Core/Core/IOS/IOS.h @@ -31,6 +31,8 @@ namespace HLE namespace Device { class Device; +class ES; +class FS; } struct Request; @@ -84,8 +86,8 @@ enum ProcessId : u32 class Kernel { public: - explicit Kernel(u64 ios_title_id); - ~Kernel(); + Kernel(); + virtual ~Kernel(); void DoState(PointerWrap& p); void HandleIPCEvent(u64 userdata); @@ -93,7 +95,11 @@ public: void UpdateDevices(); void UpdateWantDeterminism(bool new_want_determinism); - std::shared_ptr GetDeviceByName(const std::string& device_name); + // These are *always* part of the IOS kernel and always available. + // They are also the only available resource managers even before loading any module. + std::shared_ptr GetFS(); + std::shared_ptr GetES(); + void SDIO_EventNotify(); void EnqueueIPCRequest(u32 address); @@ -111,13 +117,15 @@ public: IOSC& GetIOSC(); -private: +protected: void ExecuteIPCCommand(u32 address); IPCCommandResult HandleIPCCommand(const Request& request); void EnqueueIPCAcknowledgement(u32 address, int cycles_in_future = 0); void AddDevice(std::unique_ptr device); + void AddCoreDevices(); void AddStaticDevices(); + std::shared_ptr GetDeviceByName(const std::string& device_name); s32 GetFreeDeviceID(); s32 OpenDevice(OpenRequest& request); @@ -140,10 +148,22 @@ private: IOSC m_iosc; }; +// HLE for an IOS tied to emulation: base kernel which may have additional modules loaded. +class EmulationKernel : public Kernel +{ +public: + explicit EmulationKernel(u64 ios_title_id); + ~EmulationKernel(); + + // Get a resource manager by name. + // This only works for devices which are part of the device map. + std::shared_ptr GetDeviceByName(const std::string& device_name); +}; + // Used for controlling and accessing an IOS instance that is tied to emulation. void Init(); void Shutdown(); -Kernel* GetIOS(); +EmulationKernel* GetIOS(); } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp b/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp index 390a266e41..e72de9cdfe 100644 --- a/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp +++ b/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp @@ -45,7 +45,7 @@ OH0Device::OH0Device(Kernel& ios, const std::string& name) : Device(ios, name, D void OH0Device::DoState(PointerWrap& p) { - m_oh0 = std::static_pointer_cast(m_ios.GetDeviceByName("/dev/usb/oh0")); + m_oh0 = std::static_pointer_cast(GetIOS()->GetDeviceByName("/dev/usb/oh0")); p.Do(m_name); p.Do(m_vid); p.Do(m_pid); @@ -61,7 +61,7 @@ ReturnCode OH0Device::Open(const OpenRequest& request) if (m_vid == 0 && m_pid == 0) return IPC_ENOENT; - m_oh0 = std::static_pointer_cast(m_ios.GetDeviceByName("/dev/usb/oh0")); + m_oh0 = std::static_pointer_cast(GetIOS()->GetDeviceByName("/dev/usb/oh0")); ReturnCode return_code; std::tie(return_code, m_device_id) = m_oh0->DeviceOpen(m_vid, m_pid); diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index c6d26640f7..a5464151b6 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -109,7 +109,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) Memory::CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size); m_tmd.SetBytes(std::move(tmd_bytes)); - ES::TicketReader ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId()); + IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId()); if (!ticket.IsValid()) { return_error_code = -11028; @@ -134,7 +134,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) // Initializes the IV from the index of the content in the TMD contents. u32 content_id = Memory::Read_U32(request.buffer_in + 8); - ES::Content content_info; + IOS::ES::Content content_info; if (!m_tmd.FindContentById(content_id, &content_info)) { WARN_LOG(IOS, "%s: Content id %08x not found", ioctl_name, content_id);