mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 09:20:18 +00:00
WIP (#17)
This commit is contained in:
parent
074ad7e9ef
commit
d159f43cf3
@ -35,8 +35,8 @@ enum KernelHandle : Handle {
|
|||||||
|
|
||||||
enum class HandleType : u32 {
|
enum class HandleType : u32 {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Port = 1,
|
ServerPort = 1,
|
||||||
Session = 2,
|
ClientSession = 2,
|
||||||
Event = 3,
|
Event = 3,
|
||||||
Mutex = 4,
|
Mutex = 4,
|
||||||
SharedMemory = 5,
|
SharedMemory = 5,
|
||||||
@ -48,6 +48,7 @@ enum class HandleType : u32 {
|
|||||||
Timer = 11,
|
Timer = 11,
|
||||||
ResourceLimit = 12,
|
ResourceLimit = 12,
|
||||||
CodeSet = 13,
|
CodeSet = 13,
|
||||||
|
ServerSession = 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -71,7 +72,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool IsWaitable() const {
|
bool IsWaitable() const {
|
||||||
switch (GetHandleType()) {
|
switch (GetHandleType()) {
|
||||||
case HandleType::Session:
|
case HandleType::ClientSession:
|
||||||
case HandleType::Event:
|
case HandleType::Event:
|
||||||
case HandleType::Mutex:
|
case HandleType::Mutex:
|
||||||
case HandleType::Thread:
|
case HandleType::Thread:
|
||||||
@ -80,13 +81,14 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case HandleType::Unknown:
|
case HandleType::Unknown:
|
||||||
case HandleType::Port:
|
case HandleType::ServerPort:
|
||||||
case HandleType::SharedMemory:
|
case HandleType::SharedMemory:
|
||||||
case HandleType::Redirection:
|
case HandleType::Redirection:
|
||||||
case HandleType::Process:
|
case HandleType::Process:
|
||||||
case HandleType::AddressArbiter:
|
case HandleType::AddressArbiter:
|
||||||
case HandleType::ResourceLimit:
|
case HandleType::ResourceLimit:
|
||||||
case HandleType::CodeSet:
|
case HandleType::CodeSet:
|
||||||
|
case HandleType::ServerSession:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,55 @@
|
|||||||
// Copyright 2015 Citra Emulator Project
|
// Copyright 2016 Citra Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "core/hle/kernel/session.h"
|
#include "core/hle/kernel/session.h"
|
||||||
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
Session::Session() {}
|
SharedPtr<ServerPort> ServerPort::Create(const std::string& name, u32 max_sessions) {
|
||||||
Session::~Session() {}
|
SharedPtr<ServerPort> server_port(new ServerPort);
|
||||||
|
server_port->name = name;
|
||||||
|
server_port->owner_process = g_current_process;
|
||||||
|
server_port->max_sessions = max_sessions;
|
||||||
|
|
||||||
|
return server_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<ClientSession> ServerPort::CreateSession() {
|
||||||
|
SharedPtr<ClientSession> client_session(new ClientSession);
|
||||||
|
if (IsHLE()) {
|
||||||
|
client_session->hle_port = this;
|
||||||
|
} else {
|
||||||
|
SharedPtr<ServerSession> server_session(new ServerSession);
|
||||||
|
client_session->server_session = server_session;
|
||||||
|
pending_sessions.push_back(server_session);
|
||||||
|
// Set the register to the value of the triggered index from svcReplyAndReceive
|
||||||
|
WakeupAllWaitingThreads();
|
||||||
|
}
|
||||||
|
// TODO(Subv): Schedule to the thread waiting on svcReplyAndReceive
|
||||||
|
return client_session;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientSession::ClientSession() {}
|
||||||
|
ClientSession::~ClientSession() {}
|
||||||
|
|
||||||
|
ResultVal<bool> ClientSession::SyncRequest() {
|
||||||
|
if (hle_port) {
|
||||||
|
hle_port->SyncRequest();
|
||||||
|
} else {
|
||||||
|
server_session->data_ready = true;
|
||||||
|
server_session->waiting_thread = Kernel::GetCurrentThread();
|
||||||
|
// TODO(Subv): Sleep the current thread until the response is ready
|
||||||
|
// TODO(Subv): Immediately schedule the handler thread
|
||||||
|
}
|
||||||
|
return MakeResult<bool>(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultVal<bool> ServerPort::SyncRequest() {
|
||||||
|
|
||||||
|
return MakeResult<bool>(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
@ -64,6 +65,28 @@ inline static u32* GetCommandBuffer(const int offset = 0) {
|
|||||||
return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset);
|
return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ServerSession : public WaitObject {
|
||||||
|
public:
|
||||||
|
std::string GetTypeName() const override { return "ServerSession"; }
|
||||||
|
|
||||||
|
static const HandleType HANDLE_TYPE = HandleType::ServerSession;
|
||||||
|
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||||
|
|
||||||
|
bool ShouldWait() override {
|
||||||
|
return !data_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Acquire() override {
|
||||||
|
data_ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool data_ready;
|
||||||
|
SharedPtr<Thread> handler_thread;
|
||||||
|
SharedPtr<Thread> waiting_thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ServerPort;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
|
* Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
|
||||||
* primitive for communication between different processes, and are used to implement service calls
|
* primitive for communication between different processes, and are used to implement service calls
|
||||||
@ -86,21 +109,21 @@ inline static u32* GetCommandBuffer(const int offset = 0) {
|
|||||||
* CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
|
* CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
|
||||||
* opposed to HLE simulations.
|
* opposed to HLE simulations.
|
||||||
*/
|
*/
|
||||||
class Session : public WaitObject {
|
class ClientSession : public WaitObject {
|
||||||
public:
|
public:
|
||||||
Session();
|
ClientSession();
|
||||||
~Session() override;
|
~ClientSession() override;
|
||||||
|
|
||||||
std::string GetTypeName() const override { return "Session"; }
|
std::string GetTypeName() const override { return "ClientSession"; }
|
||||||
|
|
||||||
static const HandleType HANDLE_TYPE = HandleType::Session;
|
static const HandleType HANDLE_TYPE = HandleType::ClientSession;
|
||||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
|
* Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
|
||||||
* aren't supported yet.
|
* aren't supported yet.
|
||||||
*/
|
*/
|
||||||
virtual ResultVal<bool> SyncRequest() = 0;
|
virtual ResultVal<bool> SyncRequest();
|
||||||
|
|
||||||
// TODO(bunnei): These functions exist to satisfy a hardware test with a Session object
|
// TODO(bunnei): These functions exist to satisfy a hardware test with a Session object
|
||||||
// passed into WaitSynchronization. Figure out the meaning of them.
|
// passed into WaitSynchronization. Figure out the meaning of them.
|
||||||
@ -112,6 +135,50 @@ public:
|
|||||||
void Acquire() override {
|
void Acquire() override {
|
||||||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedPtr<ServerSession> server_session;
|
||||||
|
SharedPtr<ServerPort> hle_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ServerPort : public WaitObject {
|
||||||
|
public:
|
||||||
|
std::string GetTypeName() const override { return "ServerPort"; }
|
||||||
|
|
||||||
|
static const HandleType HANDLE_TYPE = HandleType::ServerPort;
|
||||||
|
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string name used by CTROS for a service
|
||||||
|
* @return Port name of service
|
||||||
|
*/
|
||||||
|
virtual std::string GetPortName() const {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ResultVal<bool> SyncRequest();
|
||||||
|
|
||||||
|
std::string GetName() const override { return GetPortName(); }
|
||||||
|
|
||||||
|
static SharedPtr<ServerPort> Create(const std::string& name, u32 max_sessions);
|
||||||
|
|
||||||
|
SharedPtr<ClientSession> CreateSession();
|
||||||
|
|
||||||
|
virtual bool IsHLE() const { return false; }
|
||||||
|
|
||||||
|
bool ShouldWait() override {
|
||||||
|
return pending_sessions.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Acquire() override {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
SharedPtr<Process> owner_process;
|
||||||
|
u32 max_sessions;
|
||||||
|
|
||||||
|
std::vector<SharedPtr<ServerSession>> pending_sessions;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ enum class MediaType : u32 {
|
|||||||
|
|
||||||
typedef u64 ArchiveHandle;
|
typedef u64 ArchiveHandle;
|
||||||
|
|
||||||
class File : public Kernel::Session {
|
class File : public Kernel::ClientSession {
|
||||||
public:
|
public:
|
||||||
File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
|
File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
|
||||||
~File();
|
~File();
|
||||||
@ -59,7 +59,7 @@ public:
|
|||||||
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
|
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
|
||||||
};
|
};
|
||||||
|
|
||||||
class Directory : public Kernel::Session {
|
class Directory : public Kernel::ClientSession {
|
||||||
public:
|
public:
|
||||||
Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
|
Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
|
||||||
~Directory();
|
~Directory();
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
// Namespace FS_User
|
// Namespace FS_User
|
||||||
|
|
||||||
using Kernel::SharedPtr;
|
using Kernel::SharedPtr;
|
||||||
using Kernel::Session;
|
using Kernel::ClientSession;
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace FS {
|
namespace FS {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
|
||||||
|
#include "core/hle/kernel/session.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hle/service/ac_u.h"
|
#include "core/hle/service/ac_u.h"
|
||||||
#include "core/hle/service/act_u.h"
|
#include "core/hle/service/act_u.h"
|
||||||
@ -42,8 +43,8 @@
|
|||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
|
||||||
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
|
std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ServerPort>> g_kernel_named_ports;
|
||||||
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
|
std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ServerPort>> g_srv_services;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a function string for logging, complete with the name (or header code, depending
|
* Creates a function string for logging, complete with the name (or header code, depending
|
||||||
@ -90,11 +91,11 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Module interface
|
// Module interface
|
||||||
|
|
||||||
static void AddNamedPort(Interface* interface_) {
|
static void AddNamedPort(Kernel::ServerPort* interface_) {
|
||||||
g_kernel_named_ports.emplace(interface_->GetPortName(), interface_);
|
g_kernel_named_ports.emplace(interface_->GetPortName(), interface_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddService(Interface* interface_) {
|
void AddService(Kernel::ServerPort* interface_) {
|
||||||
g_srv_services.emplace(interface_->GetPortName(), interface_);
|
g_srv_services.emplace(interface_->GetPortName(), interface_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,13 +23,11 @@ namespace Service {
|
|||||||
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
|
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
|
||||||
|
|
||||||
/// Interface to a CTROS service
|
/// Interface to a CTROS service
|
||||||
class Interface : public Kernel::Session {
|
class Interface : public Kernel::ServerPort {
|
||||||
// TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
|
// TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
|
||||||
// just something that encapsulates a session and acts as a helper to implement service
|
// just something that encapsulates a session and acts as a helper to implement service
|
||||||
// processes.
|
// processes.
|
||||||
public:
|
public:
|
||||||
std::string GetName() const override { return GetPortName(); }
|
|
||||||
|
|
||||||
typedef void (*Function)(Interface*);
|
typedef void (*Function)(Interface*);
|
||||||
|
|
||||||
struct FunctionInfo {
|
struct FunctionInfo {
|
||||||
@ -38,16 +36,10 @@ public:
|
|||||||
const char* name;
|
const char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the string name used by CTROS for a service
|
|
||||||
* @return Port name of service
|
|
||||||
*/
|
|
||||||
virtual std::string GetPortName() const {
|
|
||||||
return "[UNKNOWN SERVICE PORT]";
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<bool> SyncRequest() override;
|
ResultVal<bool> SyncRequest() override;
|
||||||
|
|
||||||
|
bool IsHLE() const override { return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,11 +64,11 @@ void Init();
|
|||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
|
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
|
||||||
extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
|
extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ServerPort>> g_kernel_named_ports;
|
||||||
/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
|
/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
|
||||||
extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
|
extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ServerPort>> g_srv_services;
|
||||||
|
|
||||||
/// Adds a service to the services table
|
/// Adds a service to the services table
|
||||||
void AddService(Interface* interface_);
|
void AddService(Kernel::ServerPort* interface_);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -40,7 +40,8 @@ static void GetServiceHandle(Service::Interface* self) {
|
|||||||
auto it = Service::g_srv_services.find(port_name);
|
auto it = Service::g_srv_services.find(port_name);
|
||||||
|
|
||||||
if (it != Service::g_srv_services.end()) {
|
if (it != Service::g_srv_services.end()) {
|
||||||
cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom();
|
auto client_session = it->second->CreateSession();
|
||||||
|
cmd_buff[3] = Kernel::g_handle_table.Create(client_session).MoveFrom();
|
||||||
LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
|
LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
|
LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
|
||||||
@ -49,10 +50,31 @@ static void GetServiceHandle(Service::Interface* self) {
|
|||||||
cmd_buff[1] = res.raw;
|
cmd_buff[1] = res.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RegisterService(Service::Interface* self) {
|
||||||
|
ResultCode res = RESULT_SUCCESS;
|
||||||
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
|
u32 max_sessions = cmd_buff[4];
|
||||||
|
std::string port_name = std::string((const char*)&cmd_buff[1], 0, std::min<u32>(cmd_buff[3], Service::kMaxPortSize));
|
||||||
|
auto it = Service::g_srv_services.find(port_name);
|
||||||
|
|
||||||
|
if (it != Service::g_srv_services.end()) {
|
||||||
|
LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s already exists", port_name.c_str());
|
||||||
|
res = UnimplementedFunction(ErrorModule::SRV);
|
||||||
|
} else {
|
||||||
|
LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
|
||||||
|
auto server_port = Kernel::ServerPort::Create(port_name, max_sessions);
|
||||||
|
Service::g_srv_services.emplace(port_name, server_port);
|
||||||
|
cmd_buff[3] = Kernel::g_handle_table.Create(server_port).MoveFrom();
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_buff[1] = res.raw;
|
||||||
|
}
|
||||||
|
|
||||||
const Interface::FunctionInfo FunctionTable[] = {
|
const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00010002, Initialize, "Initialize"},
|
{0x00010002, Initialize, "Initialize"},
|
||||||
{0x00020000, GetProcSemaphore, "GetProcSemaphore"},
|
{0x00020000, GetProcSemaphore, "GetProcSemaphore"},
|
||||||
{0x00030100, nullptr, "RegisterService"},
|
{0x00030100, RegisterService, "RegisterService"},
|
||||||
{0x000400C0, nullptr, "UnregisterService"},
|
{0x000400C0, nullptr, "UnregisterService"},
|
||||||
{0x00050100, GetServiceHandle, "GetServiceHandle"},
|
{0x00050100, GetServiceHandle, "GetServiceHandle"},
|
||||||
{0x000600C2, nullptr, "RegisterHandle"},
|
{0x000600C2, nullptr, "RegisterHandle"},
|
||||||
|
@ -215,13 +215,15 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
|
|||||||
return ERR_NOT_FOUND;
|
return ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second));
|
// TODO(Subv): This should return a ClientPort, not a ClientSession
|
||||||
|
auto session = it->second->CreateSession();
|
||||||
|
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(session));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronize to an OS service
|
/// Synchronize to an OS service
|
||||||
static ResultCode SendSyncRequest(Handle handle) {
|
static ResultCode SendSyncRequest(Handle handle) {
|
||||||
SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
|
SharedPtr<Kernel::ClientSession> session = Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);
|
||||||
if (session == nullptr) {
|
if (session == nullptr) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user