2014-04-11 23:44:21 +01:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
2014-12-17 05:38:14 +00:00
|
|
|
// Licensed under GPLv2 or any later version
|
2014-04-11 23:44:21 +01:00
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2018-08-09 20:10:11 +01:00
|
|
|
#include <array>
|
2015-06-21 15:44:11 +01:00
|
|
|
#include <cstddef>
|
2018-08-09 20:10:11 +01:00
|
|
|
#include <functional>
|
2019-03-23 21:09:02 +00:00
|
|
|
#include <memory>
|
2014-04-11 23:44:21 +01:00
|
|
|
#include <string>
|
2015-01-30 18:56:49 +00:00
|
|
|
#include <boost/container/flat_map.hpp>
|
2019-12-24 22:39:02 +00:00
|
|
|
#include <boost/serialization/assume_abstract.hpp>
|
2019-12-24 23:17:24 +00:00
|
|
|
#include <boost/serialization/shared_ptr.hpp>
|
|
|
|
#include <boost/serialization/base_object.hpp>
|
2015-05-06 08:06:12 +01:00
|
|
|
#include "common/common_types.h"
|
2019-12-24 22:39:02 +00:00
|
|
|
#include "common/construct.h"
|
2017-06-05 05:52:19 +01:00
|
|
|
#include "core/hle/kernel/hle_ipc.h"
|
2018-08-02 03:40:00 +01:00
|
|
|
#include "core/hle/kernel/object.h"
|
2018-08-25 13:05:59 +01:00
|
|
|
#include "core/hle/service/sm/sm.h"
|
2016-12-01 03:50:13 +00:00
|
|
|
|
2018-10-05 15:59:43 +01:00
|
|
|
namespace Core {
|
|
|
|
class System;
|
|
|
|
}
|
2014-04-11 23:44:21 +01:00
|
|
|
|
2017-06-06 09:29:46 +01:00
|
|
|
namespace Kernel {
|
2018-10-13 00:00:16 +01:00
|
|
|
class KernelSystem;
|
2017-06-06 09:29:46 +01:00
|
|
|
class ClientPort;
|
2017-06-07 05:20:52 +01:00
|
|
|
class ServerPort;
|
2017-06-06 09:29:46 +01:00
|
|
|
class ServerSession;
|
2018-02-22 15:46:31 +00:00
|
|
|
} // namespace Kernel
|
2017-06-06 09:29:46 +01:00
|
|
|
|
2014-04-11 23:44:21 +01:00
|
|
|
namespace Service {
|
|
|
|
|
2017-06-07 05:20:52 +01:00
|
|
|
namespace SM {
|
|
|
|
class ServiceManager;
|
|
|
|
}
|
|
|
|
|
2014-12-14 05:30:11 +00:00
|
|
|
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
|
2016-12-14 17:33:49 +00:00
|
|
|
/// Arbitrary default number of maximum connections to an HLE service.
|
|
|
|
static const u32 DefaultMaxSessions = 10;
|
2014-05-08 02:04:55 +01:00
|
|
|
|
2017-06-07 05:20:52 +01:00
|
|
|
/**
|
|
|
|
* This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it
|
|
|
|
* is not meant to be used directly.
|
|
|
|
*
|
|
|
|
* @see ServiceFramework
|
|
|
|
*/
|
|
|
|
class ServiceFrameworkBase : public Kernel::SessionRequestHandler {
|
|
|
|
public:
|
|
|
|
/// Returns the string identifier used to connect to the service.
|
|
|
|
std::string GetServiceName() const {
|
|
|
|
return service_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the maximum number of sessions that can be connected to this service at the same
|
|
|
|
* time.
|
|
|
|
*/
|
|
|
|
u32 GetMaxSessions() const {
|
|
|
|
return max_sessions;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a port pair and registers this service with the given ServiceManager.
|
|
|
|
void InstallAsService(SM::ServiceManager& service_manager);
|
|
|
|
/// Creates a port pair and registers it on the kernel's global port registry.
|
2018-10-13 00:00:16 +01:00
|
|
|
void InstallAsNamedPort(Kernel::KernelSystem& kernel);
|
2017-06-07 05:20:52 +01:00
|
|
|
|
2019-02-02 20:18:01 +00:00
|
|
|
void HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
2017-06-07 05:20:52 +01:00
|
|
|
|
2019-07-22 13:24:01 +01:00
|
|
|
/// Retrieves name of a function based on the header code. For IPC Recorder.
|
|
|
|
std::string GetFunctionName(u32 header) const;
|
|
|
|
|
2017-06-07 05:20:52 +01:00
|
|
|
protected:
|
|
|
|
/// Member-function pointer type of SyncRequest handlers.
|
|
|
|
template <typename Self>
|
|
|
|
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
|
|
|
|
|
|
|
private:
|
2017-12-13 18:56:53 +00:00
|
|
|
template <typename T, typename SessionData>
|
2017-06-07 05:20:52 +01:00
|
|
|
friend class ServiceFramework;
|
|
|
|
|
|
|
|
struct FunctionInfoBase {
|
|
|
|
u32 expected_header;
|
|
|
|
HandlerFnP<ServiceFrameworkBase> handler_callback;
|
|
|
|
const char* name;
|
|
|
|
};
|
|
|
|
|
|
|
|
using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
|
|
|
|
Kernel::HLERequestContext& ctx);
|
|
|
|
|
2019-12-24 17:49:56 +00:00
|
|
|
// TODO: Replace all these with virtual functions!
|
2017-06-07 05:20:52 +01:00
|
|
|
ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker);
|
Port various minor changes from yuzu PRs (#4725)
* common/thread: Remove unused functions
Many of these functions are carried over from Dolphin (where they aren't
used anymore). Given these have no use (and we really shouldn't be
screwing around with OS-specific thread scheduler handling from the
emulator, these can be removed.
The function for setting the thread name is left, however, since it can
have debugging utility usages.
* input_common/sdl: Use a type alias to shorten declaration of GetPollers
Just makes the definitions a little bit more tidy.
* input_common/sdl: Correct return values within implementations of GetPollers()
In both cases, we weren't actually returning anything, which is
undefined behavior.
* yuzu/debugger/graphics_surface: Fill in missing surface format listings
Fills in the missing surface types that were marked as unknown. The
order corresponds with the TextureFormat enum within
video_core/texture.h.
We also don't need to all of these strings as translatable (only the
first string, as it's an English word).
* yuzu/debugger/graphics_surface: Clean up connection overload deduction
We can utilize qOverload with the signal connections to make the
function deducing a little less ugly.
* yuzu/debugger/graphics_surface: Tidy up SaveSurface
- Use QStringLiteral where applicable.
- Use const where applicable
- Remove unnecessary precondition check (we already assert the pixbuf
being non null)
* yuzu/debugger/graphics_surface: Display error messages for file I/O errors
* core: Add missing override specifiers where applicable
Applies the override specifier where applicable. In the case of
destructors that are defaulted in their definition, they can
simply be removed.
This also removes the unnecessary inclusions being done in audin_u and
audrec_u, given their close proximity.
* kernel/thread: Make parameter of GetWaitObjectIndex() const qualified
The pointed to member is never actually modified, so it can be made
const.
* kernel/thread: Avoid sign conversion within GetCommandBufferAddress()
Previously this was performing a u64 + int sign conversion. When dealing
with addresses, we should generally be keeping the arithmetic in the
same signedness type.
This also gets rid of the static lifetime of the constant, as there's no
need to make a trivial type like this potentially live for the entire
duration of the program.
* kernel/codeset: Make CodeSet's memory data member a regular std::vector
The use of a shared_ptr is an implementation detail of the VMManager
itself when mapping memory. Because of that, we shouldn't require all
users of the CodeSet to have to allocate the shared_ptr ahead of time.
It's intended that CodeSet simply pass in the required direct data, and
that the memory manager takes care of it from that point on.
This means we just do the shared pointer allocation in a single place,
when loading modules, as opposed to in each loader.
* kernel/wait_object: Make ShouldWait() take thread members by pointer-to-const
Given this is intended as a querying function, it doesn't make sense to
allow the implementer to modify the state of the given thread.
2019-05-01 13:28:49 +01:00
|
|
|
~ServiceFrameworkBase() override;
|
2017-06-07 05:20:52 +01:00
|
|
|
|
2018-09-06 21:03:28 +01:00
|
|
|
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
|
2017-06-07 05:20:52 +01:00
|
|
|
void ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info);
|
|
|
|
|
|
|
|
/// Identifier string used to connect to the service.
|
|
|
|
std::string service_name;
|
|
|
|
/// Maximum number of concurrent sessions that this service can handle.
|
|
|
|
u32 max_sessions;
|
|
|
|
|
|
|
|
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
|
|
|
InvokerFn* handler_invoker;
|
|
|
|
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Framework for implementing HLE services. Dispatches on the header id of incoming SyncRequests
|
|
|
|
* based on a table mapping header ids to handler functions. Service implementations should inherit
|
|
|
|
* from ServiceFramework using the CRTP (`class Foo : public ServiceFramework<Foo> { ... };`) and
|
|
|
|
* populate it with handlers by calling #RegisterHandlers.
|
|
|
|
*
|
|
|
|
* In order to avoid duplicating code in the binary and exposing too many implementation details in
|
|
|
|
* the header, this class is split into a non-templated base (ServiceFrameworkBase) and a template
|
|
|
|
* deriving from it (ServiceFramework). The functions in this class will mostly only erase the type
|
|
|
|
* of the passed in function pointers and then delegate the actual work to the implementation in the
|
|
|
|
* base class.
|
|
|
|
*/
|
2017-12-13 18:56:53 +00:00
|
|
|
template <typename Self, typename SessionData = Kernel::SessionRequestHandler::SessionDataBase>
|
2017-06-07 05:20:52 +01:00
|
|
|
class ServiceFramework : public ServiceFrameworkBase {
|
|
|
|
protected:
|
|
|
|
/// Contains information about a request type which is handled by the service.
|
|
|
|
struct FunctionInfo : FunctionInfoBase {
|
|
|
|
// TODO(yuriks): This function could be constexpr, but clang is the only compiler that
|
|
|
|
// doesn't emit an ICE or a wrong diagnostic because of the static_cast.
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a FunctionInfo for a function.
|
|
|
|
*
|
|
|
|
* @param expected_header request header in the command buffer which will trigger dispatch
|
|
|
|
* to this handler
|
|
|
|
* @param handler_callback member function in this service which will be called to handle
|
|
|
|
* the request
|
|
|
|
* @param name human-friendly name for the request. Used mostly for logging purposes.
|
|
|
|
*/
|
|
|
|
FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name)
|
|
|
|
: FunctionInfoBase{
|
|
|
|
expected_header,
|
|
|
|
// Type-erase member function pointer by casting it down to the base class.
|
|
|
|
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the handler with no functions installed.
|
|
|
|
* @param max_sessions Maximum number of sessions that can be
|
|
|
|
* connected to this service at the same time.
|
|
|
|
*/
|
2018-07-24 04:10:48 +01:00
|
|
|
explicit ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions)
|
2017-06-07 05:20:52 +01:00
|
|
|
: ServiceFrameworkBase(service_name, max_sessions, Invoker) {}
|
|
|
|
|
|
|
|
/// Registers handlers in the service.
|
2018-09-06 21:03:28 +01:00
|
|
|
template <std::size_t N>
|
2017-06-07 05:20:52 +01:00
|
|
|
void RegisterHandlers(const FunctionInfo (&functions)[N]) {
|
|
|
|
RegisterHandlers(functions, N);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers handlers in the service. Usually prefer using the other RegisterHandlers
|
|
|
|
* overload in order to avoid needing to specify the array size.
|
|
|
|
*/
|
2018-09-06 21:03:28 +01:00
|
|
|
void RegisterHandlers(const FunctionInfo* functions, std::size_t n) {
|
2017-06-07 05:20:52 +01:00
|
|
|
RegisterHandlersBase(functions, n);
|
|
|
|
}
|
|
|
|
|
2019-06-23 19:07:14 +01:00
|
|
|
std::unique_ptr<SessionDataBase> MakeSessionData() override {
|
2017-12-13 18:56:53 +00:00
|
|
|
return std::make_unique<SessionData>();
|
|
|
|
}
|
|
|
|
|
2019-03-23 20:04:19 +00:00
|
|
|
SessionData* GetSessionData(std::shared_ptr<Kernel::ServerSession> server_session) {
|
2017-12-13 18:56:53 +00:00
|
|
|
return ServiceFrameworkBase::GetSessionData<SessionData>(server_session);
|
|
|
|
}
|
|
|
|
|
2017-06-07 05:20:52 +01:00
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* This function is used to allow invocation of pointers to handlers stored in the base class
|
|
|
|
* without needing to expose the type of this derived class. Pointers-to-member may require a
|
|
|
|
* fixup when being up or downcast, and thus code that does that needs to know the concrete type
|
|
|
|
* of the derived class in order to invoke one of it's functions through a pointer.
|
|
|
|
*/
|
|
|
|
static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
|
|
|
|
Kernel::HLERequestContext& ctx) {
|
|
|
|
// Cast back up to our original types and call the member function
|
|
|
|
(static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-13 02:55:36 +01:00
|
|
|
/// Initialize ServiceManager
|
2018-10-12 21:11:51 +01:00
|
|
|
void Init(Core::System& system);
|
2014-04-13 02:55:36 +01:00
|
|
|
|
2018-08-09 20:10:11 +01:00
|
|
|
struct ServiceModuleInfo {
|
|
|
|
std::string name;
|
|
|
|
u64 title_id;
|
2018-10-05 15:59:43 +01:00
|
|
|
std::function<void(Core::System&)> init_function;
|
2018-08-09 20:10:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
extern const std::array<ServiceModuleInfo, 40> service_module_map;
|
|
|
|
|
2018-02-22 15:46:31 +00:00
|
|
|
} // namespace Service
|
2019-12-24 22:39:02 +00:00
|
|
|
|
|
|
|
#define SERVICE_SERIALIZATION(T, MFIELD) \
|
|
|
|
template <class Archive> \
|
|
|
|
void save_construct(Archive& ar, const unsigned int file_version) const \
|
|
|
|
{ \
|
|
|
|
ar << MFIELD; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
template <class Archive> \
|
|
|
|
static void load_construct(Archive& ar, T* t, const unsigned int file_version) \
|
|
|
|
{ \
|
|
|
|
std::shared_ptr<Module> MFIELD; \
|
|
|
|
ar >> MFIELD; \
|
|
|
|
::new(t)T(MFIELD); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
template <class Archive> \
|
|
|
|
void serialize(Archive& ar, const unsigned int) \
|
|
|
|
{ \
|
|
|
|
ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this); \
|
|
|
|
} \
|
|
|
|
friend class boost::serialization::access; \
|
|
|
|
friend class construct_access;
|