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.
This commit is contained in:
Léo Lam 2017-05-07 17:58:26 +02:00
parent f4e115b322
commit 12801fd722
5 changed files with 92 additions and 38 deletions

View File

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

View File

@ -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<Kernel> s_ios;
static std::unique_ptr<EmulationKernel> 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<std::mutex> 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<u32>(m_title_id);
}
std::shared_ptr<Device::FS> Kernel::GetFS()
{
return std::static_pointer_cast<Device::FS>(m_device_map.at("/dev/fs"));
}
std::shared_ptr<Device::ES> Kernel::GetES()
{
return std::static_pointer_cast<Device::ES>(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<Kernel>(ios_title_id);
s_ios = std::make_unique<EmulationKernel>(ios_title_id);
return true;
}
@ -299,10 +328,16 @@ void Kernel::AddDevice(std::unique_ptr<Device::Device> device)
m_device_map[device->GetDeviceName()] = std::move(device);
}
void Kernel::AddCoreDevices()
{
std::lock_guard<std::mutex> lock(m_device_map_mutex);
AddDevice(std::make_unique<Device::FS>(*this, "/dev/fs"));
AddDevice(std::make_unique<Device::ES>(*this, "/dev/es"));
}
void Kernel::AddStaticDevices()
{
std::lock_guard<std::mutex> 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<Device::BluetoothEmu>(*this, "/dev/usb/oh1/57e/305"));
@ -311,8 +346,6 @@ void Kernel::AddStaticDevices()
AddDevice(std::make_unique<Device::STMImmediate>(*this, "/dev/stm/immediate"));
AddDevice(std::make_unique<Device::STMEventHook>(*this, "/dev/stm/eventhook"));
AddDevice(std::make_unique<Device::FS>(*this, "/dev/fs"));
AddDevice(std::make_unique<Device::ES>(*this, "/dev/es"));
AddDevice(std::make_unique<Device::DI>(*this, "/dev/di"));
AddDevice(std::make_unique<Device::NetKDRequest>(*this, "/dev/net/kd/request"));
AddDevice(std::make_unique<Device::NetKDTime>(*this, "/dev/net/kd/time"));
@ -351,6 +384,11 @@ std::shared_ptr<Device::Device> Kernel::GetDeviceByName(const std::string& devic
return iterator != m_device_map.end() ? iterator->second : nullptr;
}
std::shared_ptr<Device::Device> 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<Kernel>(IOS80_TITLE_ID);
s_ios = std::make_unique<EmulationKernel>(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();
}

View File

@ -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<Device::Device> 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<Device::FS> GetFS();
std::shared_ptr<Device::ES> 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::Device> device);
void AddCoreDevices();
void AddStaticDevices();
std::shared_ptr<Device::Device> 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<Device::Device> 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

View File

@ -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<OH0>(m_ios.GetDeviceByName("/dev/usb/oh0"));
m_oh0 = std::static_pointer_cast<OH0>(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<OH0>(m_ios.GetDeviceByName("/dev/usb/oh0"));
m_oh0 = std::static_pointer_cast<OH0>(GetIOS()->GetDeviceByName("/dev/usb/oh0"));
ReturnCode return_code;
std::tie(return_code, m_device_id) = m_oh0->DeviceOpen(m_vid, m_pid);

View File

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