aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/ipc_helpers.h129
-rw-r--r--src/core/hle/kernel/client_session.h6
-rw-r--r--src/core/hle/kernel/domain.cpp63
-rw-r--r--src/core/hle/kernel/domain.h45
-rw-r--r--src/core/hle/kernel/handle_table.cpp10
-rw-r--r--src/core/hle/kernel/handle_table.h7
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp11
-rw-r--r--src/core/hle/kernel/hle_ipc.h27
-rw-r--r--src/core/hle/kernel/kernel.h16
-rw-r--r--src/core/hle/kernel/server_session.cpp47
-rw-r--r--src/core/hle/kernel/server_session.h18
-rw-r--r--src/core/hle/kernel/svc.cpp3
-rw-r--r--src/core/hle/kernel/sync_object.h35
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp12
-rw-r--r--src/core/hle/service/am/am.cpp5
-rw-r--r--src/core/hle/service/am/am.h8
-rw-r--r--src/core/hle/service/am/applet_oe.cpp96
-rw-r--r--src/core/hle/service/am/applet_oe.h9
-rw-r--r--src/core/hle/service/apm/apm.cpp6
-rw-r--r--src/core/hle/service/audio/audin_u.cpp41
-rw-r--r--src/core/hle/service/audio/audin_u.h23
-rw-r--r--src/core/hle/service/audio/audio.cpp8
-rw-r--r--src/core/hle/service/audio/audout_u.cpp184
-rw-r--r--src/core/hle/service/audio/audout_u.h20
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp38
-rw-r--r--src/core/hle/service/audio/audrec_u.h23
-rw-r--r--src/core/hle/service/audio/audren_u.cpp44
-rw-r--r--src/core/hle/service/audio/audren_u.h23
-rw-r--r--src/core/hle/service/audio/codecctl.cpp33
-rw-r--r--src/core/hle/service/audio/codecctl.h23
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp54
-rw-r--r--src/core/hle/service/filesystem/filesystem.h50
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp138
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h34
-rw-r--r--src/core/hle/service/hid/hid.cpp21
-rw-r--r--src/core/hle/service/lm/lm.cpp21
-rw-r--r--src/core/hle/service/lm/lm.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp46
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h48
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp13
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h12
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp17
-rw-r--r--src/core/hle/service/nvdrv/interface.h2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp31
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h23
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp96
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h82
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp161
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h84
-rw-r--r--src/core/hle/service/pctl/pctl_a.cpp2
-rw-r--r--src/core/hle/service/service.cpp12
-rw-r--r--src/core/hle/service/set/set.cpp2
-rw-r--r--src/core/hle/service/sm/controller.cpp20
-rw-r--r--src/core/hle/service/sm/sm.cpp7
-rw-r--r--src/core/hle/service/sockets/bsd_u.cpp8
-rw-r--r--src/core/hle/service/time/time.cpp86
-rw-r--r--src/core/hle/service/time/time.h13
-rw-r--r--src/core/hle/service/vi/vi.cpp314
-rw-r--r--src/core/hle/service/vi/vi.h126
-rw-r--r--src/core/hle/service/vi/vi_m.cpp7
-rw-r--r--src/core/hle/service/vi/vi_m.h8
63 files changed, 1767 insertions, 793 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 4c9b0de28..6066d8a18 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -11,7 +11,6 @@
#include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/domain.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
@@ -31,11 +30,6 @@ public:
RequestHelperBase(Kernel::HLERequestContext& context)
: context(&context), cmdbuf(context.CommandBuffer()) {}
- void ValidateHeader() {
- // DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)",
- // header.raw);
- }
-
void Skip(unsigned size_in_words, bool set_to_null) {
if (set_to_null)
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
@@ -60,14 +54,30 @@ public:
}
};
-class RequestBuilder : public RequestHelperBase {
+class ResponseBuilder : public RequestHelperBase {
public:
- RequestBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
+ ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
+
+ u32 normal_params_size{};
+ u32 num_handles_to_copy{};
+ u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
+ std::ptrdiff_t datapayload_index{};
+
+ /// Flags used for customizing the behavior of ResponseBuilder
+ enum class Flags : u32 {
+ None = 0,
+ /// Uses move handles to move objects in the response, even when in a domain. This is
+ /// required when PushMoveObjects is used.
+ AlwaysMoveHandles = 1,
+ };
+
+ ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
+ u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
+ Flags flags = Flags::None)
+
+ : RequestHelperBase(context), normal_params_size(normal_params_size),
+ num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) {
- RequestBuilder(Kernel::HLERequestContext& context, unsigned normal_params_size,
- u32 num_handles_to_copy = 0, u32 num_handles_to_move = 0,
- u32 num_domain_objects = 0)
- : RequestHelperBase(context) {
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
context.ClearIncomingObjects();
@@ -77,12 +87,19 @@ public:
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
// padding.
u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
- if (context.IsDomain()) {
- raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
+
+ u32 num_handles_to_move{};
+ u32 num_domain_objects{};
+ const bool always_move_handles{
+ (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
+ if (!context.Session()->IsDomain() || always_move_handles) {
+ num_handles_to_move = num_objects_to_move;
} else {
- // If we're not in a domain, turn the domain object parameters into move handles.
- num_handles_to_move += num_domain_objects;
- num_domain_objects = 0;
+ num_domain_objects = num_objects_to_move;
+ }
+
+ if (context.Session()->IsDomain()) {
+ raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
}
header.data_size.Assign(raw_data_size);
@@ -101,7 +118,7 @@ public:
AlignWithPadding();
- if (context.IsDomain()) {
+ if (context.Session()->IsDomain()) {
IPC::DomainMessageHeader domain_header{};
domain_header.num_objects = num_domain_objects;
PushRaw(domain_header);
@@ -110,23 +127,43 @@ public:
IPC::DataPayloadHeader data_payload_header{};
data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
PushRaw(data_payload_header);
+
+ datapayload_index = index;
}
- template <class T, class... Args>
- void PushIpcInterface(Args&&... args) {
- auto iface = std::make_shared<T>(std::forward<Args>(args)...);
- if (context->IsDomain()) {
+ template <class T>
+ void PushIpcInterface(std::shared_ptr<T> iface) {
+ if (context->Session()->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
- auto port = iface->CreatePort();
- auto session = port->Connect();
- ASSERT(session.Succeeded());
- context->AddMoveObject(std::move(session).Unwrap());
+ auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName());
+ auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
+ auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
+ iface->ClientConnected(server);
+ context->AddMoveObject(std::move(client));
}
}
+ template <class T, class... Args>
+ void PushIpcInterface(Args&&... args) {
+ PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...));
+ }
+
+ void ValidateHeader() {
+ const size_t num_domain_objects = context->NumDomainObjects();
+ const size_t num_move_objects = context->NumMoveObjects();
+ ASSERT_MSG(!num_domain_objects || !num_move_objects,
+ "cannot move normal handles and domain objects");
+ ASSERT_MSG((index - datapayload_index) == normal_params_size,
+ "normal_params_size value is incorrect");
+ ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move,
+ "num_objects_to_move value is incorrect");
+ ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy,
+ "num_handles_to_copy value is incorrect");
+ }
+
// Validate on destruction, as there shouldn't be any case where we don't want it
- ~RequestBuilder() {
+ ~ResponseBuilder() {
ValidateHeader();
}
@@ -154,52 +191,52 @@ public:
/// Push ///
template <>
-inline void RequestBuilder::Push(u32 value) {
+inline void ResponseBuilder::Push(u32 value) {
cmdbuf[index++] = value;
}
template <typename T>
-void RequestBuilder::PushRaw(const T& value) {
+void ResponseBuilder::PushRaw(const T& value) {
std::memcpy(cmdbuf + index, &value, sizeof(T));
index += (sizeof(T) + 3) / 4; // round up to word length
}
template <>
-inline void RequestBuilder::Push(ResultCode value) {
+inline void ResponseBuilder::Push(ResultCode value) {
// Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded.
Push(value.raw);
Push<u32>(0);
}
template <>
-inline void RequestBuilder::Push(u8 value) {
+inline void ResponseBuilder::Push(u8 value) {
PushRaw(value);
}
template <>
-inline void RequestBuilder::Push(u16 value) {
+inline void ResponseBuilder::Push(u16 value) {
PushRaw(value);
}
template <>
-inline void RequestBuilder::Push(u64 value) {
+inline void ResponseBuilder::Push(u64 value) {
Push(static_cast<u32>(value));
Push(static_cast<u32>(value >> 32));
}
template <>
-inline void RequestBuilder::Push(bool value) {
+inline void ResponseBuilder::Push(bool value) {
Push(static_cast<u8>(value));
}
template <typename First, typename... Other>
-void RequestBuilder::Push(const First& first_value, const Other&... other_values) {
+void ResponseBuilder::Push(const First& first_value, const Other&... other_values) {
Push(first_value);
Push(other_values...);
}
template <typename... O>
-inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
+inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
context->AddCopyObject(std::move(object));
@@ -207,7 +244,7 @@ inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
}
template <typename... O>
-inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
+inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
context->AddMoveObject(std::move(object));
@@ -226,15 +263,10 @@ public:
Skip(CommandIdSize, false);
}
- RequestBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
- u32 num_handles_to_move, u32 num_domain_objects,
- bool validate_header = true) {
- if (validate_header) {
- ValidateHeader();
- }
-
- return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move,
- num_domain_objects};
+ ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
+ u32 num_handles_to_move,
+ ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) {
+ return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move, flags};
}
template <typename T>
@@ -305,6 +337,11 @@ inline u64 RequestParser::Pop() {
}
template <>
+inline s64 RequestParser::Pop() {
+ return static_cast<s64>(Pop<u64>());
+}
+
+template <>
inline bool RequestParser::Pop() {
return Pop<u8>() != 0;
}
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index d6ab4f893..2258f95bc 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -7,7 +7,7 @@
#include <memory>
#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/sync_object.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -16,7 +16,7 @@ class ServerSession;
class Session;
class Thread;
-class ClientSession final : public SyncObject {
+class ClientSession final : public Object {
public:
friend class ServerSession;
@@ -33,7 +33,7 @@ public:
return HANDLE_TYPE;
}
- ResultCode SendSyncRequest(SharedPtr<Thread> thread) override;
+ ResultCode SendSyncRequest(SharedPtr<Thread> thread);
std::string name; ///< Name of client port (optional)
diff --git a/src/core/hle/kernel/domain.cpp b/src/core/hle/kernel/domain.cpp
deleted file mode 100644
index 5035e9c08..000000000
--- a/src/core/hle/kernel/domain.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/domain.h"
-#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/session.h"
-#include "core/hle/kernel/thread.h"
-
-namespace Kernel {
-
-ResultVal<SharedPtr<Domain>> Domain::Create(std::string name) {
- SharedPtr<Domain> domain(new Domain);
- domain->name = std::move(name);
- return MakeResult(std::move(domain));
-}
-
-ResultVal<SharedPtr<Domain>> Domain::CreateFromSession(const Session& session) {
- auto res = Create(session.port->GetName() + "_Domain");
- auto& domain = res.Unwrap();
- domain->request_handlers.push_back(std::move(session.server->hle_handler));
- Kernel::g_handle_table.ConvertSessionToDomain(session, domain);
- return res;
-}
-
-ResultCode Domain::SendSyncRequest(SharedPtr<Thread> thread) {
- Kernel::HLERequestContext context(this);
- u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
- context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
- Kernel::g_handle_table);
-
- auto& domain_message_header = context.GetDomainMessageHeader();
- if (domain_message_header) {
- // If there is a DomainMessageHeader, then this is CommandType "Request"
- const u32 object_id{context.GetDomainMessageHeader()->object_id};
- switch (domain_message_header->command) {
- case IPC::DomainMessageHeader::CommandType::SendMessage:
- return request_handlers[object_id - 1]->HandleSyncRequest(context);
-
- case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
- LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
-
- request_handlers[object_id - 1] = nullptr;
-
- IPC::RequestBuilder rb{context, 2};
- rb.Push(RESULT_SUCCESS);
-
- return RESULT_SUCCESS;
- }
- }
-
- LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
- UNIMPLEMENTED();
- }
- return request_handlers.front()->HandleSyncRequest(context);
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/domain.h b/src/core/hle/kernel/domain.h
deleted file mode 100644
index 3fec3b0b2..000000000
--- a/src/core/hle/kernel/domain.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <vector>
-#include "core/hle/kernel/sync_object.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-class Session;
-class SessionRequestHandler;
-
-class Domain final : public SyncObject {
-public:
- std::string GetTypeName() const override {
- return "Domain";
- }
-
- static const HandleType HANDLE_TYPE = HandleType::Domain;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- static ResultVal<SharedPtr<Domain>> CreateFromSession(const Session& server);
-
- ResultCode SendSyncRequest(SharedPtr<Thread> thread) override;
-
- /// The name of this domain (optional)
- std::string name;
-
- std::vector<std::shared_ptr<SessionRequestHandler>> request_handlers;
-
-private:
- Domain() = default;
- ~Domain() override = default;
-
- static ResultVal<SharedPtr<Domain>> Create(std::string name = "Unknown");
-};
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 74d3d0514..3beb55753 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -5,12 +5,10 @@
#include <utility>
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
@@ -55,14 +53,6 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
return Create(std::move(object));
}
-void HandleTable::ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain) {
- for (auto& object : objects) {
- if (DynamicObjectCast<ClientSession>(object) == session.client) {
- object = domain;
- }
- }
-}
-
ResultCode HandleTable::Close(Handle handle) {
if (!IsValid(handle))
return ERR_INVALID_HANDLE;
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index 935cc22b5..ba968c666 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -17,8 +17,6 @@ enum KernelHandle : Handle {
CurrentProcess = 0xFFFF8001,
};
-class Session;
-
/**
* This class allows the creation of Handles, which are references to objects that can be tested
* for validity and looked up. Here they are used to pass references to kernel objects to/from the
@@ -62,11 +60,6 @@ public:
ResultVal<Handle> Duplicate(Handle handle);
/**
- * Convert all handles of the specified Session to the specified Domain.
- */
- void ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain);
-
- /**
* Closes a handle, removing it from the table and decreasing the object's ref-count.
* @return `RESULT_SUCCESS` or one of the following errors:
* - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index ecf32c18a..db104e8a2 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -7,7 +7,6 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/domain.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
@@ -26,10 +25,6 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
boost::range::remove_erase(connected_sessions, server_session);
}
-HLERequestContext::HLERequestContext(SharedPtr<Kernel::Domain> domain) : domain(std::move(domain)) {
- cmd_buf[0] = 0;
-}
-
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
: server_session(std::move(server_session)) {
cmd_buf[0] = 0;
@@ -87,7 +82,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
// Padding to align to 16 bytes
rp.AlignWithPadding();
- if (IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
+ if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
// If this is an incoming message, only CommandType "Request" has a domain header
// All outgoing domain messages have the domain header
domain_message_header =
@@ -200,12 +195,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P
// TODO(Subv): Translate the X/A/B/W buffers.
- if (IsDomain()) {
+ if (Session()->IsDomain()) {
ASSERT(domain_message_header->num_objects == domain_objects.size());
// Write the domain objects to the command buffer, these go after the raw untranslated data.
// TODO(Subv): This completely ignores C buffers.
size_t domain_offset = size - domain_message_header->num_objects;
- auto& request_handlers = domain->request_handlers;
+ auto& request_handlers = server_session->domain_request_handlers;
for (auto& object : domain_objects) {
request_handlers.emplace_back(object);
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 80fa48d7f..da8335b35 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -86,7 +86,6 @@ protected:
*/
class HLERequestContext {
public:
- HLERequestContext(SharedPtr<Kernel::Domain> domain);
HLERequestContext(SharedPtr<Kernel::ServerSession> session);
~HLERequestContext();
@@ -96,17 +95,10 @@ public:
}
/**
- * Returns the domain through which this request was made.
- */
- const SharedPtr<Kernel::Domain>& Domain() const {
- return domain;
- }
-
- /**
* Returns the session through which this request was made. This can be used as a map key to
* access per-client data on services.
*/
- const SharedPtr<Kernel::ServerSession>& ServerSession() const {
+ const SharedPtr<Kernel::ServerSession>& Session() const {
return server_session;
}
@@ -151,10 +143,6 @@ public:
return domain_message_header;
}
- bool IsDomain() const {
- return domain != nullptr;
- }
-
template <typename T>
SharedPtr<T> GetCopyObject(size_t index) {
ASSERT(index < copy_objects.size());
@@ -187,9 +175,20 @@ public:
domain_objects.clear();
}
+ size_t NumMoveObjects() const {
+ return move_objects.size();
+ }
+
+ size_t NumCopyObjects() const {
+ return copy_objects.size();
+ }
+
+ size_t NumDomainObjects() const {
+ return domain_objects.size();
+ }
+
private:
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
- SharedPtr<Kernel::Domain> domain;
SharedPtr<Kernel::ServerSession> server_session;
// TODO(yuriks): Check common usage of this and optimize size accordingly
boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4d9549e45..c77e58f3c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -31,7 +31,6 @@ enum class HandleType : u32 {
ServerPort,
ClientSession,
ServerSession,
- Domain,
};
enum {
@@ -84,27 +83,12 @@ public:
case HandleType::CodeSet:
case HandleType::ClientPort:
case HandleType::ClientSession:
- case HandleType::Domain:
return false;
}
UNREACHABLE();
}
- /**
- * Check if svcSendSyncRequest can be called on the object
- * @return True svcSendSyncRequest can be called on the object, otherwise false
- */
- bool IsSyncable() const {
- switch (GetHandleType()) {
- case HandleType::ClientSession:
- case HandleType::Domain:
- return true;
- }
-
- UNREACHABLE();
- }
-
public:
static unsigned int next_object_id;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 09d02a691..54481f7f1 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -4,6 +4,7 @@
#include <tuple>
+#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/handle_table.h"
@@ -61,6 +62,38 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
// similar.
+ Kernel::HLERequestContext context(this);
+ u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
+ context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
+ Kernel::g_handle_table);
+
+ // If the session has been converted to a domain, handle the doomain request
+ if (IsDomain()) {
+ auto& domain_message_header = context.GetDomainMessageHeader();
+ if (domain_message_header) {
+ // If there is a DomainMessageHeader, then this is CommandType "Request"
+ const u32 object_id{context.GetDomainMessageHeader()->object_id};
+ switch (domain_message_header->command) {
+ case IPC::DomainMessageHeader::CommandType::SendMessage:
+ return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
+
+ case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
+ LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
+
+ domain_request_handlers[object_id - 1] = nullptr;
+
+ IPC::ResponseBuilder rb{context, 2};
+ rb.Push(RESULT_SUCCESS);
+ return RESULT_SUCCESS;
+ }
+ }
+
+ LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
+ ASSERT(false);
+ }
+ // If there is no domain header, the regular session handler is used
+ }
+
// If this ServerSession has an associated HLE handler, forward the request to it.
ResultCode result{RESULT_SUCCESS};
if (hle_handler != nullptr) {
@@ -69,11 +102,6 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
if (translate_result.IsError())
return translate_result;
- Kernel::HLERequestContext context(this);
- u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
- context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
- Kernel::g_handle_table);
-
result = hle_handler->HandleSyncRequest(context);
} else {
// Add the thread to the list of threads that have issued a sync request with this
@@ -84,6 +112,15 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
// on it.
WakeupAllWaitingThreads();
+
+ // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
+ // end of the command such that only commands following this one are handled as domains
+ if (convert_to_domain) {
+ ASSERT_MSG(domain_request_handlers.empty(), "already a domain");
+ domain_request_handlers = {hle_handler};
+ convert_to_domain = false;
+ }
+
return result;
}
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 6ff4ef8c1..144692106 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -79,7 +79,10 @@ public:
std::string name; ///< The name of this session (optional)
std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.
std::shared_ptr<SessionRequestHandler>
- hle_handler; ///< This session's HLE request handler (optional)
+ hle_handler; ///< This session's HLE request handler (applicable when not a domain)
+
+ /// This is the list of domain request handlers (after conversion to a domain)
+ std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
/// List of threads that are pending a response after a sync request. This list is processed in
/// a LIFO manner, thus, the last request will be dispatched first.
@@ -91,6 +94,16 @@ public:
/// TODO(Subv): Find a better name for this.
SharedPtr<Thread> currently_handling;
+ /// Returns true if the session has been converted to a domain, otherwise False
+ bool IsDomain() const {
+ return !domain_request_handlers.empty();
+ }
+
+ /// Converts the session to a domain at the end of the current command
+ void ConvertToDomain() {
+ convert_to_domain = true;
+ }
+
private:
ServerSession();
~ServerSession() override;
@@ -102,6 +115,9 @@ private:
* @return The created server session
*/
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
+
+ /// When set to True, converts the session to a domain at the end of the command
+ bool convert_to_domain{};
};
/**
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 516309036..4c0276cf0 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -20,7 +20,6 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_wrap.h"
-#include "core/hle/kernel/sync_object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
@@ -87,7 +86,7 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
/// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Handle handle) {
- SharedPtr<SyncObject> session = g_handle_table.Get<SyncObject>(handle);
+ SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle);
return ERR_INVALID_HANDLE;
diff --git a/src/core/hle/kernel/sync_object.h b/src/core/hle/kernel/sync_object.h
deleted file mode 100644
index f2befa2ea..000000000
--- a/src/core/hle/kernel/sync_object.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <boost/smart_ptr/intrusive_ptr.hpp>
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-class Thread;
-
-/// Class that represents a Kernel object that svcSendSyncRequest can be called on
-class SyncObject : public Object {
-public:
- /**
- * Handle a sync request from the emulated application.
- * @param thread Thread that initiated the request.
- * @returns ResultCode from the operation.
- */
- virtual ResultCode SendSyncRequest(SharedPtr<Thread> thread) = 0;
-};
-
-// Specialization of DynamicObjectCast for SyncObjects
-template <>
-inline SharedPtr<SyncObject> DynamicObjectCast<SyncObject>(SharedPtr<Object> object) {
- if (object != nullptr && object->IsSyncable()) {
- return boost::static_pointer_cast<SyncObject>(std::move(object));
- }
- return nullptr;
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 10ddc4feb..656e1b4a7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -19,6 +19,8 @@
enum class ErrorDescription : u32 {
Success = 0,
RemoteProcessDead = 301,
+ InvalidOffset = 6061,
+ InvalidLength = 6062,
};
/**
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 7f0192fd3..67f05aad4 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -22,7 +22,7 @@ private:
void GetBase(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
ProfileBase profile_base{};
- IPC::RequestBuilder rb{ctx, 16};
+ IPC::ResponseBuilder rb{ctx, 16};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(profile_base);
}
@@ -40,7 +40,7 @@ public:
private:
void CheckAvailability(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
@@ -48,13 +48,13 @@ private:
void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProfile>();
LOG_DEBUG(Service, "called");
@@ -62,12 +62,12 @@ void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) {
void ACC_U0::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ACC_U0::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IManagerForApplication>();
LOG_DEBUG(Service, "called");
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a761bea65..b6896852e 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -8,8 +8,9 @@
namespace Service {
namespace AM {
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<AppletOE>()->InstallAsService(service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager,
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
+ std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
}
} // namespace AM
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 63d86cd41..3b8a06c1d 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -4,13 +4,19 @@
#pragma once
+#include <memory>
#include "core/hle/service/service.h"
namespace Service {
+namespace NVFlinger {
+class NVFlinger;
+}
+
namespace AM {
/// Registers all AM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager,
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
} // namespace AM
} // namespace Service
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index b4a6ad232..15b7701e0 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -7,6 +7,7 @@
#include "core/hle/kernel/event.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/apm/apm.h"
+#include "core/hle/service/nvflinger/nvflinger.h"
namespace Service {
namespace AM {
@@ -24,14 +25,14 @@ public:
private:
void GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
}
void AcquireForegroundRights(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
};
@@ -53,7 +54,8 @@ public:
class ISelfController final : public ServiceFramework<ISelfController> {
public:
- ISelfController() : ServiceFramework("ISelfController") {
+ ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
+ : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
static const FunctionInfo functions[] = {
{1, &ISelfController::LockExit, "LockExit"},
{2, &ISelfController::UnlockExit, "UnlockExit"},
@@ -65,6 +67,7 @@ public:
{14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
{16, &ISelfController::SetOutOfFocusSuspendingEnabled,
"SetOutOfFocusSuspendingEnabled"},
+ {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
};
RegisterHandlers(functions);
}
@@ -83,14 +86,14 @@ private:
};
auto flags = rp.PopRaw<FocusHandlingModeParams>();
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
}
void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
@@ -101,7 +104,7 @@ private:
bool flag = rp.Pop<bool>();
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called flag=%u", static_cast<u32>(flag));
@@ -112,7 +115,7 @@ private:
bool flag = rp.Pop<bool>();
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called flag=%u", static_cast<u32>(flag));
@@ -125,25 +128,40 @@ private:
bool enabled = rp.Pop<bool>();
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called enabled=%u", static_cast<u32>(enabled));
}
void LockExit(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
}
void UnlockExit(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
}
+
+ void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
+ // TODO(Subv): Find out how AM determines the display to use, for now just create the layer
+ // in the Default display.
+ u64 display_id = nvflinger->OpenDisplay("Default");
+ u64 layer_id = nvflinger->CreateLayer(display_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(layer_id);
+
+ LOG_WARNING(Service, "(STUBBED) called");
+ }
+
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
@@ -175,7 +193,7 @@ private:
void GetEventHandle(Kernel::HLERequestContext& ctx) {
event->Signal();
- IPC::RequestBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event);
@@ -183,7 +201,7 @@ private:
}
void ReceiveMessage(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(15);
@@ -191,7 +209,7 @@ private:
}
void GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(FocusState::InFocus));
@@ -199,7 +217,7 @@ private:
}
void GetOperationMode(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(OperationMode::Handheld));
@@ -207,7 +225,7 @@ private:
}
void GetPerformanceMode(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(APM::PerformanceMode::Handheld));
@@ -232,7 +250,7 @@ private:
std::vector<u8> buffer;
void GetSize(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(buffer.size()));
@@ -251,7 +269,7 @@ private:
Memory::WriteBlock(output_buffer.Address(), buffer.data() + offset, output_buffer.Size());
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -273,7 +291,7 @@ private:
std::vector<u8> buffer;
void Open(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorageAccessor>(buffer);
@@ -310,7 +328,7 @@ private:
std::vector<u8> buffer(data, data + sizeof(data));
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorage>(buffer);
@@ -325,34 +343,34 @@ private:
IPC::RequestParser rp{ctx};
u32 result = rp.Pop<u32>();
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called, result=0x%08X", result);
}
void GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(SystemLanguage::English);
LOG_WARNING(Service, "(STUBBED) called");
}
void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
}
void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
}
void NotifyRunning(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
@@ -367,7 +385,8 @@ public:
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
- IApplicationProxy() : ServiceFramework("IApplicationProxy") {
+ IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
+ : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &IApplicationProxy::GetSelfController, "GetSelfController"},
@@ -383,70 +402,73 @@ public:
private:
void GetAudioController(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
LOG_DEBUG(Service, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
LOG_DEBUG(Service, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
LOG_DEBUG(Service, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
LOG_DEBUG(Service, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISelfController>();
+ rb.PushIpcInterface<ISelfController>(nvflinger);
LOG_DEBUG(Service, "called");
}
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>();
LOG_DEBUG(Service, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
LOG_DEBUG(Service, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
LOG_DEBUG(Service, "called");
}
+
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IApplicationProxy>();
+ rb.PushIpcInterface<IApplicationProxy>(nvflinger);
LOG_DEBUG(Service, "called");
}
-AppletOE::AppletOE() : ServiceFramework("appletOE") {
+AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
+ : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) {
static const FunctionInfo functions[] = {
{0x00000000, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 6ee5b0e9f..8083135c3 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -4,10 +4,15 @@
#pragma once
+#include <memory>
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
namespace Service {
+namespace NVFlinger {
+class NVFlinger;
+}
+
namespace AM {
// TODO: Add more languages
@@ -18,11 +23,13 @@ enum SystemLanguage {
class AppletOE final : public ServiceFramework<AppletOE> {
public:
- AppletOE();
+ AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
~AppletOE() = default;
private:
void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
+
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
} // namespace AM
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index bf7e12288..c4b1723c5 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -30,7 +30,7 @@ private:
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
u32 config = rp.Pop<u32>();
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called mode=%u config=%u", static_cast<u32>(mode), config);
@@ -41,7 +41,7 @@ private:
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // Performance configuration
@@ -58,7 +58,7 @@ APM::APM() : ServiceFramework("apm") {
}
void APM::OpenSession(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISession>();
}
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
new file mode 100644
index 000000000..ee749fddd
--- /dev/null
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -0,0 +1,41 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/audio/audin_u.h"
+
+namespace Service {
+namespace Audio {
+
+class IAudioIn final : public ServiceFramework<IAudioIn> {
+public:
+ IAudioIn() : ServiceFramework("IAudioIn") {
+ static const FunctionInfo functions[] = {
+ {0x0, nullptr, "GetAudioInState"},
+ {0x1, nullptr, "StartAudioIn"},
+ {0x2, nullptr, "StopAudioIn"},
+ {0x3, nullptr, "AppendAudioInBuffer_1"},
+ {0x4, nullptr, "RegisterBufferEvent"},
+ {0x5, nullptr, "GetReleasedAudioInBuffer_1"},
+ {0x6, nullptr, "ContainsAudioInBuffer"},
+ {0x7, nullptr, "AppendAudioInBuffer_2"},
+ {0x8, nullptr, "GetReleasedAudioInBuffer_2"},
+ };
+ RegisterHandlers(functions);
+ }
+ ~IAudioIn() = default;
+};
+
+AudInU::AudInU() : ServiceFramework("audin:u") {
+ static const FunctionInfo functions[] = {
+ {0x00000000, nullptr, "ListAudioIns"},
+ {0x00000001, nullptr, "OpenAudioIn"},
+ };
+ RegisterHandlers(functions);
+}
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
new file mode 100644
index 000000000..2b8576756
--- /dev/null
+++ b/src/core/hle/service/audio/audin_u.h
@@ -0,0 +1,23 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class HLERequestContext;
+}
+
+namespace Service {
+namespace Audio {
+
+class AudInU final : public ServiceFramework<AudInU> {
+public:
+ explicit AudInU();
+ ~AudInU() = default;
+};
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 2b4c6c5d0..3f7fb44eb 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,14 +2,22 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/audio/audin_u.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/audio/audout_u.h"
+#include "core/hle/service/audio/audrec_u.h"
+#include "core/hle/service/audio/audren_u.h"
+#include "core/hle/service/audio/codecctl.h"
namespace Service {
namespace Audio {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<AudOutU>()->InstallAsService(service_manager);
+ std::make_shared<AudInU>()->InstallAsService(service_manager);
+ std::make_shared<AudRecU>()->InstallAsService(service_manager);
+ std::make_shared<AudRenU>()->InstallAsService(service_manager);
+ std::make_shared<CodecCtl>()->InstallAsService(service_manager);
}
} // namespace Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index c028262c6..f56ba2ea1 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -2,23 +2,197 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <vector>
#include "common/logging/log.h"
+#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audout_u.h"
namespace Service {
namespace Audio {
+/// Switch sample rate frequency
+constexpr u32 sample_rate{48000};
+/// TODO(st4rk): dynamic number of channels, as I think Switch has support
+/// to more audio channels (probably when Docked I guess)
+constexpr u32 audio_channels{2};
+/// TODO(st4rk): find a proper value for the audio_ticks
+constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 500)};
+
+class IAudioOut final : public ServiceFramework<IAudioOut> {
+public:
+ IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(AudioState::Stopped) {
+ static const FunctionInfo functions[] = {
+ {0x0, nullptr, "GetAudioOutState"},
+ {0x1, &IAudioOut::StartAudioOut, "StartAudioOut"},
+ {0x2, &IAudioOut::StopAudioOut, "StopAudioOut"},
+ {0x3, &IAudioOut::AppendAudioOutBuffer_1, "AppendAudioOutBuffer_1"},
+ {0x4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
+ {0x5, &IAudioOut::GetReleasedAudioOutBuffer_1, "GetReleasedAudioOutBuffer_1"},
+ {0x6, nullptr, "ContainsAudioOutBuffer"},
+ {0x7, nullptr, "AppendAudioOutBuffer_2"},
+ {0x8, nullptr, "GetReleasedAudioOutBuffer_2"},
+ };
+ RegisterHandlers(functions);
+
+ // This is the event handle used to check if the audio buffer was released
+ buffer_event =
+ Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
+
+ // Register event callback to update the Audio Buffer
+ audio_event = CoreTiming::RegisterEvent(
+ "IAudioOut::UpdateAudioBuffersCallback", [this](u64 userdata, int cycles_late) {
+ UpdateAudioBuffersCallback();
+ CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
+ });
+
+ // Start the audio event
+ CoreTiming::ScheduleEvent(audio_ticks, audio_event);
+ }
+
+ ~IAudioOut() = default;
+
+private:
+ void StartAudioOut(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ // Start audio
+ audio_out_state = AudioState::Started;
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void StopAudioOut(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ // Stop audio
+ audio_out_state = AudioState::Stopped;
+
+ queue_keys.clear();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(buffer_event);
+ }
+
+ void AppendAudioOutBuffer_1(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+
+ const u64 key{rp.Pop<u64>()};
+ queue_keys.insert(queue_keys.begin(), key);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void GetReleasedAudioOutBuffer_1(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ const auto& buffer = ctx.BufferDescriptorB()[0];
+
+ // TODO(st4rk): This is how libtransistor currently implements the
+ // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address
+ // is used to know which buffer should be filled with data and send again to the service
+ // through AppendAudioOutBuffer. Check if this is the proper way to do it.
+ u64 key{0};
+
+ if (queue_keys.size()) {
+ key = queue_keys.back();
+ queue_keys.pop_back();
+ }
+
+ Memory::WriteBlock(buffer.Address(), &key, sizeof(u64));
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ // TODO(st4rk): This might be the total of released buffers, needs to be verified on
+ // hardware
+ rb.Push<u32>(static_cast<u32>(queue_keys.size()));
+ }
+
+ void UpdateAudioBuffersCallback() {
+ if (audio_out_state != AudioState::Started) {
+ return;
+ }
+
+ if (queue_keys.empty()) {
+ return;
+ }
+
+ buffer_event->Signal();
+ }
+
+ enum class AudioState : u32 {
+ Started,
+ Stopped,
+ };
+
+ /// This is used to trigger the audio event callback that is going to read the samples from the
+ /// audio_buffer list and enqueue the samples using the sink (audio_core).
+ CoreTiming::EventType* audio_event;
+
+ /// This is the evend handle used to check if the audio buffer was released
+ Kernel::SharedPtr<Kernel::Event> buffer_event;
+
+ /// (st4rk): This is just a temporary workaround for the future implementation. Libtransistor
+ /// uses the key as an address in the App, so we need to return when the
+ /// GetReleasedAudioOutBuffer_1 is called, otherwise we'll run in problems, because
+ /// libtransistor uses the key returned as an pointer.
+ std::vector<u64> queue_keys;
+
+ AudioState audio_out_state;
+};
+
void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2};
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+
+ auto& buffer = ctx.BufferDescriptorB()[0];
+ const std::string audio_interface = "AudioInterface";
+
+ Memory::WriteBlock(buffer.Address(), &audio_interface[0], audio_interface.size());
+
+ IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
+
+ rb.Push(RESULT_SUCCESS);
+ // TODO(st4rk): We're currently returning only one audio interface (stringlist size). However,
+ // it's highly possible to have more than one interface (despite that libtransistor requires
+ // only one).
+ rb.Push<u32>(1);
+}
+
+void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ if (!audio_out_interface) {
+ audio_out_interface = std::make_shared<IAudioOut>();
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6, 0, 1};
rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(sample_rate);
+ rb.Push<u32>(audio_channels);
+ rb.Push<u32>(static_cast<u32>(PcmFormat::Int16));
+ rb.Push<u32>(0); // This field is unknown
+ rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
}
AudOutU::AudOutU() : ServiceFramework("audout:u") {
- static const FunctionInfo functions[] = {
- {0x00000000, &AudOutU::ListAudioOuts, "ListAudioOuts"},
- };
+ static const FunctionInfo functions[] = {{0x00000000, &AudOutU::ListAudioOuts, "ListAudioOuts"},
+ {0x00000001, &AudOutU::OpenAudioOut, "OpenAudioOut"},
+ {0x00000002, nullptr, "Unknown2"},
+ {0x00000003, nullptr, "Unknown3"}};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index 42680af94..7fbce2225 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,19 +4,37 @@
#pragma once
-#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
+namespace Kernel {
+class HLERequestContext;
+}
+
namespace Service {
namespace Audio {
+class IAudioOut;
+
class AudOutU final : public ServiceFramework<AudOutU> {
public:
AudOutU();
~AudOutU() = default;
private:
+ std::shared_ptr<IAudioOut> audio_out_interface;
+
void ListAudioOuts(Kernel::HLERequestContext& ctx);
+ void OpenAudioOut(Kernel::HLERequestContext& ctx);
+
+ enum class PcmFormat : u32 {
+ Invalid = 0,
+ Int8 = 1,
+ Int16 = 2,
+ Int24 = 3,
+ Int32 = 4,
+ PcmFloat = 5,
+ Adpcm = 6,
+ };
};
} // namespace Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
new file mode 100644
index 000000000..f2626ec70
--- /dev/null
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -0,0 +1,38 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/audio/audrec_u.h"
+
+namespace Service {
+namespace Audio {
+
+class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> {
+public:
+ IFinalOutputRecorder() : ServiceFramework("IFinalOutputRecorder") {
+ static const FunctionInfo functions[] = {
+ {0x0, nullptr, "GetFinalOutputRecorderState"},
+ {0x1, nullptr, "StartFinalOutputRecorder"},
+ {0x2, nullptr, "StopFinalOutputRecorder"},
+ {0x3, nullptr, "AppendFinalOutputRecorderBuffer"},
+ {0x4, nullptr, "RegisterBufferEvent"},
+ {0x5, nullptr, "GetReleasedFinalOutputRecorderBuffer"},
+ {0x6, nullptr, "ContainsFinalOutputRecorderBuffer"},
+ };
+ RegisterHandlers(functions);
+ }
+ ~IFinalOutputRecorder() = default;
+};
+
+AudRecU::AudRecU() : ServiceFramework("audrec:u") {
+ static const FunctionInfo functions[] = {
+ {0x00000000, nullptr, "OpenFinalOutputRecorder"},
+ };
+ RegisterHandlers(functions);
+}
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h
new file mode 100644
index 000000000..c31e412c1
--- /dev/null
+++ b/src/core/hle/service/audio/audrec_u.h
@@ -0,0 +1,23 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class HLERequestContext;
+}
+
+namespace Service {
+namespace Audio {
+
+class AudRecU final : public ServiceFramework<AudRecU> {
+public:
+ explicit AudRecU();
+ ~AudRecU() = default;
+};
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
new file mode 100644
index 000000000..4bafdfac3
--- /dev/null
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -0,0 +1,44 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/audio/audren_u.h"
+
+namespace Service {
+namespace Audio {
+
+class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
+public:
+ IAudioRenderer() : ServiceFramework("IAudioRenderer") {
+ static const FunctionInfo functions[] = {
+ {0x0, nullptr, "GetAudioRendererSampleRate"},
+ {0x1, nullptr, "GetAudioRendererSampleCount"},
+ {0x2, nullptr, "GetAudioRendererMixBufferCount"},
+ {0x3, nullptr, "GetAudioRendererState"},
+ {0x4, nullptr, "RequestUpdateAudioRenderer"},
+ {0x5, nullptr, "StartAudioRenderer"},
+ {0x6, nullptr, "StopAudioRenderer"},
+ {0x7, nullptr, "QuerySystemEvent"},
+ {0x8, nullptr, "SetAudioRendererRenderingTimeLimit"},
+ {0x9, nullptr, "GetAudioRendererRenderingTimeLimit"},
+ };
+ RegisterHandlers(functions);
+ }
+ ~IAudioRenderer() = default;
+};
+
+AudRenU::AudRenU() : ServiceFramework("audren:u") {
+ static const FunctionInfo functions[] = {
+ {0x00000000, nullptr, "OpenAudioRenderer"},
+ {0x00000001, nullptr, "GetAudioRendererWorkBufferSize"},
+ {0x00000002, nullptr, "GetAudioRenderersProcessMasterVolume"},
+ {0x00000003, nullptr, "SetAudioRenderersProcessMasterVolume"},
+ };
+ RegisterHandlers(functions);
+}
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
new file mode 100644
index 000000000..1d9264c72
--- /dev/null
+++ b/src/core/hle/service/audio/audren_u.h
@@ -0,0 +1,23 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class HLERequestContext;
+}
+
+namespace Service {
+namespace Audio {
+
+class AudRenU final : public ServiceFramework<AudRenU> {
+public:
+ explicit AudRenU();
+ ~AudRenU() = default;
+};
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
new file mode 100644
index 000000000..d2a7f4cd0
--- /dev/null
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -0,0 +1,33 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/audio/codecctl.h"
+
+namespace Service {
+namespace Audio {
+
+CodecCtl::CodecCtl() : ServiceFramework("codecctl") {
+ static const FunctionInfo functions[] = {
+ {0x00000000, nullptr, "InitializeCodecController"},
+ {0x00000001, nullptr, "FinalizeCodecController"},
+ {0x00000002, nullptr, "SleepCodecController"},
+ {0x00000003, nullptr, "WakeCodecController"},
+ {0x00000004, nullptr, "SetCodecVolume"},
+ {0x00000005, nullptr, "GetCodecVolumeMax"},
+ {0x00000006, nullptr, "GetCodecVolumeMin"},
+ {0x00000007, nullptr, "SetCodecActiveTarget"},
+ {0x00000008, nullptr, "Unknown"},
+ {0x00000009, nullptr, "BindCodecHeadphoneMicJackInterrupt"},
+ {0x0000000A, nullptr, "IsCodecHeadphoneMicJackInserted"},
+ {0x0000000B, nullptr, "ClearCodecHeadphoneMicJackInterrupt"},
+ {0x0000000C, nullptr, "IsCodecDeviceRequested"},
+ };
+ RegisterHandlers(functions);
+}
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h
new file mode 100644
index 000000000..1121ab0b1
--- /dev/null
+++ b/src/core/hle/service/audio/codecctl.h
@@ -0,0 +1,23 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class HLERequestContext;
+}
+
+namespace Service {
+namespace Audio {
+
+class CodecCtl final : public ServiceFramework<CodecCtl> {
+public:
+ explicit CodecCtl();
+ ~CodecCtl() = default;
+};
+
+} // namespace Audio
+} // namespace Service
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
new file mode 100644
index 000000000..4b47548fd
--- /dev/null
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -0,0 +1,54 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <boost/container/flat_map.hpp>
+#include "core/file_sys/filesystem.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/filesystem/fsp_srv.h"
+
+namespace Service {
+namespace FileSystem {
+
+/**
+ * Map of registered file systems, identified by type. Once an file system is registered here, it
+ * is never removed until UnregisterFileSystems is called.
+ */
+static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map;
+
+ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) {
+ auto result = filesystem_map.emplace(type, std::move(factory));
+
+ bool inserted = result.second;
+ ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
+
+ auto& filesystem = result.first->second;
+ LOG_DEBUG(Service_FS, "Registered file system %s with id code 0x%08X",
+ filesystem->GetName().c_str(), static_cast<u32>(type));
+ return RESULT_SUCCESS;
+}
+
+ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
+ FileSys::Path& path) {
+ LOG_TRACE(Service_FS, "Opening FileSystem with type=%d", type);
+
+ auto itr = filesystem_map.find(type);
+ if (itr == filesystem_map.end()) {
+ // TODO(bunnei): Find a better error code for this
+ return ResultCode(-1);
+ }
+
+ return itr->second->Open(path);
+}
+
+void UnregisterFileSystems() {
+ filesystem_map.clear();
+}
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+ UnregisterFileSystems();
+ std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
+}
+
+} // namespace FileSystem
+} // namespace Service
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
new file mode 100644
index 000000000..a674c9493
--- /dev/null
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -0,0 +1,50 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "common/common_types.h"
+#include "core/hle/result.h"
+
+namespace FileSys {
+class FileSystemBackend;
+class FileSystemFactory;
+class Path;
+} // namespace FileSys
+
+namespace Service {
+
+namespace SM {
+class ServiceManager;
+} // namespace SM
+
+namespace FileSystem {
+
+/// Supported FileSystem types
+enum class Type {
+ RomFS = 1,
+};
+
+/**
+ * Registers a FileSystem, instances of which can later be opened using its IdCode.
+ * @param factory FileSystem backend interface to use
+ * @param type Type used to access this type of FileSystem
+ */
+ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type);
+
+/**
+ * Opens a file system
+ * @param type Type of the file system to open
+ * @param path Path to the file system, used with Binary paths
+ * @return FileSys::FileSystemBackend interface to the file system
+ */
+ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
+ FileSys::Path& path);
+
+/// Registers all Filesystem services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager);
+
+} // namespace FileSystem
+} // namespace Service
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
new file mode 100644
index 000000000..71b82393e
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -0,0 +1,138 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/file_sys/filesystem.h"
+#include "core/file_sys/storage.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/filesystem/fsp_srv.h"
+
+namespace Service {
+namespace FileSystem {
+
+class IStorage final : public ServiceFramework<IStorage> {
+public:
+ IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend)
+ : ServiceFramework("IStorage"), backend(std::move(backend)) {
+ static const FunctionInfo functions[] = {
+ {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
+ {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"},
+ };
+ RegisterHandlers(functions);
+ }
+
+private:
+ std::unique_ptr<FileSys::StorageBackend> backend;
+
+ void Read(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s64 offset = rp.Pop<s64>();
+ const s64 length = rp.Pop<s64>();
+ const auto& descriptor = ctx.BufferDescriptorB()[0];
+
+ LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length);
+
+ // Error checking
+ ASSERT_MSG(length == descriptor.Size(), "unexpected size difference");
+ if (length < 0) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ return;
+ }
+ if (offset < 0) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ return;
+ }
+
+ // Read the data from the Storage backend
+ std::vector<u8> output(length);
+ ResultVal<size_t> res = backend->Read(offset, length, output.data());
+ if (res.Failed()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res.Code());
+ return;
+ }
+
+ // Write the data to memory
+ Memory::WriteBlock(descriptor.Address(), output.data(), descriptor.Size());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+};
+
+FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
+ static const FunctionInfo functions[] = {
+ {1, &FSP_SRV::Initalize, "Initalize"},
+ {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
+ {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"},
+ {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
+ };
+ RegisterHandlers(functions);
+}
+
+void FSP_SRV::TryLoadRomFS() {
+ if (romfs) {
+ return;
+ }
+ FileSys::Path unused;
+ auto res = OpenFileSystem(Type::RomFS, unused);
+ if (res.Succeeded()) {
+ romfs = std::move(res.Unwrap());
+ }
+}
+
+void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(5);
+}
+
+void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ TryLoadRomFS();
+ if (!romfs) {
+ // TODO (bunnei): Find the right error code to use here
+ LOG_CRITICAL(Service_FS, "no file system interface available!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ // Attempt to open a StorageBackend interface to the RomFS
+ auto storage = romfs->OpenFile({}, {});
+ if (storage.Failed()) {
+ LOG_CRITICAL(Service_FS, "no storage interface available!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(storage.Code());
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
+}
+
+void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess");
+ OpenDataStorageByCurrentProcess(ctx);
+}
+
+} // namespace FileSystem
+} // namespace Service
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
new file mode 100644
index 000000000..15be8edc1
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -0,0 +1,34 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "core/hle/service/service.h"
+
+namespace FileSys {
+class FileSystemBackend;
+}
+
+namespace Service {
+namespace FileSystem {
+
+class FSP_SRV final : public ServiceFramework<FSP_SRV> {
+public:
+ explicit FSP_SRV();
+ ~FSP_SRV() = default;
+
+private:
+ void TryLoadRomFS();
+
+ void Initalize(Kernel::HLERequestContext& ctx);
+ void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
+ void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
+ void OpenRomStorage(Kernel::HLERequestContext& ctx);
+
+ std::unique_ptr<FileSys::FileSystemBackend> romfs;
+};
+
+} // namespace FileSystem
+} // namespace Service
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index be7a6ff65..326e0a4ab 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -46,7 +46,7 @@ public:
private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(shared_mem);
LOG_DEBUG(Service, "called");
@@ -162,18 +162,17 @@ public:
~Hid() = default;
private:
+ std::shared_ptr<IAppletResource> applet_resource;
+
void CreateAppletResource(Kernel::HLERequestContext& ctx) {
- auto client_port = std::make_shared<IAppletResource>()->CreatePort();
- auto session = client_port->Connect();
- if (session.Succeeded()) {
- LOG_DEBUG(Service, "called, initialized IAppletResource -> session=%u",
- (*session)->GetObjectId());
- IPC::RequestBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(std::move(session).Unwrap());
- } else {
- UNIMPLEMENTED();
+ if (applet_resource == nullptr) {
+ applet_resource = std::make_shared<IAppletResource>();
}
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IAppletResource>(applet_resource);
+ LOG_DEBUG(Service, "called");
}
};
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 13c9ee3d3..2843e0e40 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -65,7 +65,7 @@ private:
*/
void Log(Kernel::HLERequestContext& ctx) {
// This function only succeeds - Get that out of the way
- IPC::RequestBuilder rb{ctx, 1};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
// Read MessageHeader, despite not doing anything with it right now
@@ -130,7 +130,7 @@ private:
}
output += message;
- LOG_DEBUG(Debug_Emulated, "%s", output.c_str());
+ LOG_INFO(Debug_Emulated, "%s", output.c_str());
}
};
@@ -146,20 +146,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
* 0: ResultCode
*/
void LM::Initialize(Kernel::HLERequestContext& ctx) {
- auto client_port = std::make_shared<Logger>()->CreatePort();
- auto session = client_port->Connect();
- if (session.Succeeded()) {
- LOG_DEBUG(Service_SM, "called, initialized logger -> session=%u",
- (*session)->GetObjectId());
- IPC::RequestBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(std::move(session).Unwrap());
- registered_loggers.emplace_back(std::move(client_port));
- } else {
- UNIMPLEMENTED();
- }
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<Logger>();
- LOG_INFO(Service_SM, "called");
+ LOG_DEBUG(Service, "called");
}
LM::LM() : ServiceFramework("lm") {
diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h
index 4b954bdb2..371135057 100644
--- a/src/core/hle/service/lm/lm.h
+++ b/src/core/hle/service/lm/lm.h
@@ -5,7 +5,6 @@
#pragma once
#include <vector>
-#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/service.h"
@@ -19,8 +18,6 @@ public:
private:
void Initialize(Kernel::HLERequestContext& ctx);
-
- std::vector<Kernel::SharedPtr<Kernel::ClientPort>> registered_loggers;
};
/// Registers all LM services with the specified service manager.
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
new file mode 100644
index 000000000..2078f2187
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -0,0 +1,46 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
+
+namespace Service {
+namespace Nvidia {
+namespace Devices {
+
+u32 nvhost_ctrl::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
+ LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%lx, output_size=0x%lx", command,
+ input.size(), output.size());
+
+ switch (command) {
+ case IocGetConfigCommand:
+ return NvOsGetConfigU32(input, output);
+ }
+ UNIMPLEMENTED();
+ return 0;
+}
+
+u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
+ IocGetConfigParams params;
+ std::memcpy(&params, input.data(), sizeof(params));
+ LOG_DEBUG(Service_NVDRV, "called, setting=%s!%s", params.domain_str.data(),
+ params.param_str.data());
+
+ if (!strcmp(params.domain_str.data(), "nv")) {
+ if (!strcmp(params.param_str.data(), "NV_MEMORY_PROFILER")) {
+ params.config_str[0] = '1';
+ } else {
+ UNIMPLEMENTED();
+ }
+ } else {
+ UNIMPLEMENTED();
+ }
+ std::memcpy(output.data(), &params, sizeof(params));
+ return 0;
+}
+
+} // namespace Devices
+} // namespace Nvidia
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
new file mode 100644
index 000000000..abce35e17
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -0,0 +1,48 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include "common/common_types.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service {
+namespace Nvidia {
+namespace Devices {
+
+class nvhost_ctrl final : public nvdevice {
+public:
+ nvhost_ctrl() = default;
+ ~nvhost_ctrl() override = default;
+
+ u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
+
+private:
+ enum IoctlCommands {
+ IocSyncptReadCommand = 0xC0080014,
+ IocSyncptIncrCommand = 0x40040015,
+ IocSyncptWaitCommand = 0xC00C0016,
+ IocModuleMutexCommand = 0x40080017,
+ IocModuleRegRDWRCommand = 0xC008010E,
+ IocSyncptWaitexCommand = 0xC0100019,
+ IocSyncptReadMaxCommand = 0xC008001A,
+ IocGetConfigCommand = 0xC183001B,
+ };
+
+ struct IocGetConfigParams {
+ std::array<char, 0x41> domain_str;
+ std::array<char, 0x41> param_str;
+ std::array<char, 0x101> config_str;
+ };
+
+ u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
+};
+
+} // namespace Devices
+} // namespace Nvidia
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index d37b5b159..74ee7e154 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -22,20 +22,21 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
}
u32 nvmap::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
- switch (command) {
- case IocCreateCommand:
+ switch (static_cast<IoctlCommand>(command)) {
+ case IoctlCommand::Create:
return IocCreate(input, output);
- case IocAllocCommand:
+ case IoctlCommand::Alloc:
return IocAlloc(input, output);
- case IocGetIdCommand:
+ case IoctlCommand::GetId:
return IocGetId(input, output);
- case IocFromIdCommand:
+ case IoctlCommand::FromId:
return IocFromId(input, output);
- case IocParamCommand:
+ case IoctlCommand::Param:
return IocParam(input, output);
}
UNIMPLEMENTED();
+ return 0;
}
u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 6954c0324..42e00f370 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -48,12 +48,12 @@ private:
/// Mapping of currently allocated handles to the objects they represent.
std::unordered_map<u32, std::shared_ptr<Object>> handles;
- enum IoctlCommands {
- IocCreateCommand = 0xC0080101,
- IocFromIdCommand = 0xC0080103,
- IocAllocCommand = 0xC0200104,
- IocParamCommand = 0xC00C0109,
- IocGetIdCommand = 0xC008010E
+ enum class IoctlCommand : u32 {
+ Create = 0xC0080101,
+ FromId = 0xC0080103,
+ Alloc = 0xC0200104,
+ Param = 0xC00C0109,
+ GetId = 0xC008010E
};
struct IocCreateParams {
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 417455200..85ecde6d2 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -18,7 +18,7 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) {
std::string device_name = Memory::ReadCString(buffer.Address(), buffer.Size());
u32 fd = nvdrv->Open(device_name);
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(fd);
rb.Push<u32>(0);
@@ -43,7 +43,7 @@ void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
Memory::WriteBlock(output_buffer.Address(), output.data(), output_buffer.Size());
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(nv_result);
}
@@ -56,26 +56,25 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
auto result = nvdrv->Close(fd);
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
}
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u64 pid = rp.Pop<u64>();
- u64 unk = rp.Pop<u64>();
+ pid = rp.Pop<u64>();
- LOG_WARNING(Service, "(STUBBED) called, pid=0x%llx, unk=0x%llx", pid, unk);
-
- IPC::RequestBuilder rb{ctx, 2};
+ LOG_INFO(Service, "called, pid=0x%lx", pid);
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0);
}
NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 2283f358e..f96f2bd29 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -25,6 +25,8 @@ private:
void SetClientPID(Kernel::HLERequestContext& ctx);
std::shared_ptr<Module> nvdrv;
+
+ u64 pid{};
};
} // namespace Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 9d3013c16..141ddaedd 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -6,9 +6,11 @@
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
+#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvdrv/nvmemp.h"
namespace Service {
namespace Nvidia {
@@ -19,6 +21,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
auto module_ = std::make_shared<Module>();
std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager);
+ std::make_shared<NVMEMP>()->InstallAsService(service_manager);
nvdrv = module_;
}
@@ -27,6 +30,7 @@ Module::Module() {
devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>();
devices["/dev/nvmap"] = nvmap_dev;
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
+ devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();
}
u32 Module::Open(std::string device_name) {
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
new file mode 100644
index 000000000..5a13732c7
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvdrv/nvmemp.h"
+
+namespace Service {
+namespace Nvidia {
+
+NVMEMP::NVMEMP() : ServiceFramework("nvmemp") {
+ static const FunctionInfo functions[] = {
+ {0, &NVMEMP::Unknown0, "Unknown0"},
+ {1, &NVMEMP::Unknown1, "Unknown1"},
+ };
+ RegisterHandlers(functions);
+}
+
+void NVMEMP::Unknown0(Kernel::HLERequestContext& ctx) {
+ UNIMPLEMENTED();
+}
+
+void NVMEMP::Unknown1(Kernel::HLERequestContext& ctx) {
+ UNIMPLEMENTED();
+}
+
+} // namespace Nvidia
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
new file mode 100644
index 000000000..a6b5fbb82
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -0,0 +1,23 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace Nvidia {
+
+class NVMEMP final : public ServiceFramework<NVMEMP> {
+public:
+ NVMEMP();
+ ~NVMEMP() = default;
+
+private:
+ void Unknown0(Kernel::HLERequestContext& ctx);
+ void Unknown1(Kernel::HLERequestContext& ctx);
+};
+
+} // namespace Nvidia
+} // namespace Service
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
new file mode 100644
index 000000000..705bdbe5d
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -0,0 +1,96 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+
+#include "common/alignment.h"
+#include "common/scope_exit.h"
+#include "core/core_timing.h"
+#include "core/hle/service/nvflinger/buffer_queue.h"
+
+namespace Service {
+namespace NVFlinger {
+
+BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
+ native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
+}
+
+void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
+ Buffer buffer{};
+ buffer.slot = slot;
+ buffer.igbp_buffer = igbp_buffer;
+ buffer.status = Buffer::Status::Free;
+
+ LOG_WARNING(Service, "Adding graphics buffer %u", slot);
+
+ queue.emplace_back(buffer);
+}
+
+u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) {
+ auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
+ // Only consider free buffers. Buffers become free once again after they've been Acquired
+ // and Released by the compositor, see the NVFlinger::Compose method.
+ if (buffer.status != Buffer::Status::Free)
+ return false;
+
+ // Make sure that the parameters match.
+ auto& igbp_buffer = buffer.igbp_buffer;
+ return igbp_buffer.format == pixel_format && igbp_buffer.width == width &&
+ igbp_buffer.height == height;
+ });
+ ASSERT(itr != queue.end());
+
+ itr->status = Buffer::Status::Dequeued;
+ return itr->slot;
+}
+
+const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
+ auto itr = std::find_if(queue.begin(), queue.end(),
+ [&](const Buffer& buffer) { return buffer.slot == slot; });
+ ASSERT(itr != queue.end());
+ ASSERT(itr->status == Buffer::Status::Dequeued);
+ return itr->igbp_buffer;
+}
+
+void BufferQueue::QueueBuffer(u32 slot) {
+ auto itr = std::find_if(queue.begin(), queue.end(),
+ [&](const Buffer& buffer) { return buffer.slot == slot; });
+ ASSERT(itr != queue.end());
+ ASSERT(itr->status == Buffer::Status::Dequeued);
+ itr->status = Buffer::Status::Queued;
+}
+
+boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
+ auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) {
+ return buffer.status == Buffer::Status::Queued;
+ });
+ if (itr == queue.end())
+ return boost::none;
+ itr->status = Buffer::Status::Acquired;
+ return *itr;
+}
+
+void BufferQueue::ReleaseBuffer(u32 slot) {
+ auto itr = std::find_if(queue.begin(), queue.end(),
+ [&](const Buffer& buffer) { return buffer.slot == slot; });
+ ASSERT(itr != queue.end());
+ ASSERT(itr->status == Buffer::Status::Acquired);
+ itr->status = Buffer::Status::Free;
+}
+
+u32 BufferQueue::Query(QueryType type) {
+ LOG_WARNING(Service, "(STUBBED) called type=%u", static_cast<u32>(type));
+ switch (type) {
+ case QueryType::NativeWindowFormat:
+ // TODO(Subv): Use an enum for this
+ static constexpr u32 FormatABGR8 = 1;
+ return FormatABGR8;
+ }
+
+ UNIMPLEMENTED();
+ return 0;
+}
+
+} // namespace NVFlinger
+} // namespace Service
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
new file mode 100644
index 000000000..5c6719407
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -0,0 +1,82 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include <boost/optional.hpp>
+#include "common/swap.h"
+#include "core/hle/kernel/event.h"
+
+namespace CoreTiming {
+struct EventType;
+}
+
+namespace Service {
+namespace NVFlinger {
+
+struct IGBPBuffer {
+ u32_le magic;
+ u32_le width;
+ u32_le height;
+ u32_le stride;
+ u32_le format;
+ u32_le usage;
+ INSERT_PADDING_WORDS(1);
+ u32_le index;
+ INSERT_PADDING_WORDS(3);
+ u32_le gpu_buffer_id;
+ INSERT_PADDING_WORDS(17);
+ u32_le nvmap_handle;
+ u32_le offset;
+ INSERT_PADDING_WORDS(60);
+};
+
+static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size");
+
+class BufferQueue final {
+public:
+ enum class QueryType {
+ NativeWindowWidth = 0,
+ NativeWindowHeight = 1,
+ NativeWindowFormat = 2,
+ };
+
+ BufferQueue(u32 id, u64 layer_id);
+ ~BufferQueue() = default;
+
+ struct Buffer {
+ enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 };
+
+ u32 slot;
+ Status status = Status::Free;
+ IGBPBuffer igbp_buffer;
+ };
+
+ void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
+ u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height);
+ const IGBPBuffer& RequestBuffer(u32 slot) const;
+ void QueueBuffer(u32 slot);
+ boost::optional<const Buffer&> AcquireBuffer();
+ void ReleaseBuffer(u32 slot);
+ u32 Query(QueryType type);
+
+ u32 GetId() const {
+ return id;
+ }
+
+ Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const {
+ return native_handle;
+ }
+
+private:
+ u32 id;
+ u64 layer_id;
+
+ std::vector<Buffer> queue;
+ Kernel::SharedPtr<Kernel::Event> native_handle;
+};
+
+} // namespace NVFlinger
+} // namespace Service
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
new file mode 100644
index 000000000..fe622b986
--- /dev/null
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -0,0 +1,161 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+
+#include "common/alignment.h"
+#include "common/scope_exit.h"
+#include "core/core_timing.h"
+#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvflinger/buffer_queue.h"
+#include "core/hle/service/nvflinger/nvflinger.h"
+#include "video_core/renderer_base.h"
+#include "video_core/video_core.h"
+
+namespace Service {
+namespace NVFlinger {
+
+constexpr size_t SCREEN_REFRESH_RATE = 60;
+constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
+
+NVFlinger::NVFlinger() {
+ // Add the different displays to the list of displays.
+ Display default_{0, "Default"};
+ Display external{1, "External"};
+ Display edid{2, "Edid"};
+ Display internal{3, "Internal"};
+
+ displays.emplace_back(default_);
+ displays.emplace_back(external);
+ displays.emplace_back(edid);
+ displays.emplace_back(internal);
+
+ // Schedule the screen composition events
+ composition_event =
+ CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) {
+ Compose();
+ CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event);
+ });
+
+ CoreTiming::ScheduleEvent(frame_ticks, composition_event);
+}
+
+NVFlinger::~NVFlinger() {
+ CoreTiming::UnscheduleEvent(composition_event, 0);
+}
+
+u64 NVFlinger::OpenDisplay(const std::string& name) {
+ LOG_WARNING(Service, "Opening display %s", name.c_str());
+
+ // TODO(Subv): Currently we only support the Default display.
+ ASSERT(name == "Default");
+
+ auto itr = std::find_if(displays.begin(), displays.end(),
+ [&](const Display& display) { return display.name == name; });
+
+ ASSERT(itr != displays.end());
+
+ return itr->id;
+}
+
+u64 NVFlinger::CreateLayer(u64 display_id) {
+ auto& display = GetDisplay(display_id);
+
+ ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment");
+
+ u64 layer_id = next_layer_id++;
+ u32 buffer_queue_id = next_buffer_queue_id++;
+ auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id);
+ display.layers.emplace_back(layer_id, buffer_queue);
+ buffer_queues.emplace_back(std::move(buffer_queue));
+ return layer_id;
+}
+
+u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
+ const auto& layer = GetLayer(display_id, layer_id);
+ return layer.buffer_queue->GetId();
+}
+
+Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) {
+ const auto& display = GetDisplay(display_id);
+ return display.vsync_event;
+}
+
+std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
+ auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
+ [&](const auto& queue) { return queue->GetId() == id; });
+
+ ASSERT(itr != buffer_queues.end());
+ return *itr;
+}
+
+Display& NVFlinger::GetDisplay(u64 display_id) {
+ auto itr = std::find_if(displays.begin(), displays.end(),
+ [&](const Display& display) { return display.id == display_id; });
+
+ ASSERT(itr != displays.end());
+ return *itr;
+}
+
+Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
+ auto& display = GetDisplay(display_id);
+
+ auto itr = std::find_if(display.layers.begin(), display.layers.end(),
+ [&](const Layer& layer) { return layer.id == layer_id; });
+
+ ASSERT(itr != display.layers.end());
+ return *itr;
+}
+
+void NVFlinger::Compose() {
+ for (auto& display : displays) {
+ // Trigger vsync for this display at the end of drawing
+ SCOPE_EXIT({ display.vsync_event->Signal(); });
+
+ // Don't do anything for displays without layers.
+ if (display.layers.empty())
+ continue;
+
+ // TODO(Subv): Support more than 1 layer.
+ ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported");
+
+ Layer& layer = display.layers[0];
+ auto& buffer_queue = layer.buffer_queue;
+
+ // Search for a queued buffer and acquire it
+ auto buffer = buffer_queue->AcquireBuffer();
+
+ if (buffer == boost::none) {
+ // There was no queued buffer to draw, render previous frame
+ VideoCore::g_renderer->SwapBuffers({});
+ continue;
+ }
+
+ auto& igbp_buffer = buffer->igbp_buffer;
+
+ // Now send the buffer to the GPU for drawing.
+ auto nvdrv = Nvidia::nvdrv.lock();
+ ASSERT(nvdrv);
+
+ // TODO(Subv): Support more than just disp0. The display device selection is probably based
+ // on which display we're drawing (Default, Internal, External, etc)
+ auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
+ ASSERT(nvdisp);
+
+ nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
+ igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride);
+
+ buffer_queue->ReleaseBuffer(buffer->slot);
+ }
+}
+
+Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
+
+Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
+ vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event");
+}
+
+} // namespace NVFlinger
+} // namespace Service
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
new file mode 100644
index 000000000..3126018ad
--- /dev/null
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -0,0 +1,84 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <boost/optional.hpp>
+#include "core/hle/kernel/event.h"
+
+namespace CoreTiming {
+struct EventType;
+}
+
+namespace Service {
+namespace NVFlinger {
+
+class BufferQueue;
+
+struct Layer {
+ Layer(u64 id, std::shared_ptr<BufferQueue> queue);
+ ~Layer() = default;
+
+ u64 id;
+ std::shared_ptr<BufferQueue> buffer_queue;
+};
+
+struct Display {
+ Display(u64 id, std::string name);
+ ~Display() = default;
+
+ u64 id;
+ std::string name;
+
+ std::vector<Layer> layers;
+ Kernel::SharedPtr<Kernel::Event> vsync_event;
+};
+
+class NVFlinger final {
+public:
+ NVFlinger();
+ ~NVFlinger();
+
+ /// Opens the specified display and returns the id.
+ u64 OpenDisplay(const std::string& name);
+
+ /// Creates a layer on the specified display and returns the layer id.
+ u64 CreateLayer(u64 display_id);
+
+ /// Gets the buffer queue id of the specified layer in the specified display.
+ u32 GetBufferQueueId(u64 display_id, u64 layer_id);
+
+ /// Gets the vsync event for the specified display.
+ Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id);
+
+ /// Obtains a buffer queue identified by the id.
+ std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
+
+ /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
+ /// finished.
+ void Compose();
+
+private:
+ /// Returns the display identified by the specified id.
+ Display& GetDisplay(u64 display_id);
+
+ /// Returns the layer identified by the specified id in the desired display.
+ Layer& GetLayer(u64 display_id, u64 layer_id);
+
+ std::vector<Display> displays;
+ std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
+
+ /// Id to use for the next layer that is created, this counter is shared among all displays.
+ u64 next_layer_id = 1;
+ /// Id to use for the next buffer queue that is created, this counter is shared among all
+ /// layers.
+ u32 next_buffer_queue_id = 1;
+
+ /// CoreTiming event that handles screen composition.
+ CoreTiming::EventType* composition_event;
+};
+
+} // namespace NVFlinger
+} // namespace Service
diff --git a/src/core/hle/service/pctl/pctl_a.cpp b/src/core/hle/service/pctl/pctl_a.cpp
index 7978aecb8..c808b764b 100644
--- a/src/core/hle/service/pctl/pctl_a.cpp
+++ b/src/core/hle/service/pctl/pctl_a.cpp
@@ -15,7 +15,7 @@ public:
};
void PCTL_A::GetService(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IParentalControlService>();
LOG_DEBUG(Service, "called");
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 19213a2f4..294351b76 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -19,6 +19,7 @@
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/audio/audio.h"
+#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/lm/lm.h"
#include "core/hle/service/nvdrv/nvdrv.h"
@@ -131,7 +132,7 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
switch (context.GetCommandType()) {
case IPC::CommandType::Close: {
- IPC::RequestBuilder rb{context, 1};
+ IPC::ResponseBuilder rb{context, 2};
rb.Push(RESULT_SUCCESS);
return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead);
}
@@ -164,21 +165,26 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
/// Initialize ServiceManager
void Init() {
+ // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
+ // here and pass it into the respective InstallInterfaces functions.
+ auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
+
SM::g_service_manager = std::make_shared<SM::ServiceManager>();
SM::ServiceManager::InstallInterfaces(SM::g_service_manager);
Account::InstallInterfaces(*SM::g_service_manager);
- AM::InstallInterfaces(*SM::g_service_manager);
+ AM::InstallInterfaces(*SM::g_service_manager, nv_flinger);
AOC::InstallInterfaces(*SM::g_service_manager);
APM::InstallInterfaces(*SM::g_service_manager);
Audio::InstallInterfaces(*SM::g_service_manager);
+ FileSystem::InstallInterfaces(*SM::g_service_manager);
HID::InstallInterfaces(*SM::g_service_manager);
LM::InstallInterfaces(*SM::g_service_manager);
Nvidia::InstallInterfaces(*SM::g_service_manager);
PCTL::InstallInterfaces(*SM::g_service_manager);
Sockets::InstallInterfaces(*SM::g_service_manager);
Time::InstallInterfaces(*SM::g_service_manager);
- VI::InstallInterfaces(*SM::g_service_manager);
+ VI::InstallInterfaces(*SM::g_service_manager, nv_flinger);
Set::InstallInterfaces(*SM::g_service_manager);
LOG_DEBUG(Service, "initialized OK");
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 3715acd74..e0e157fe1 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -19,7 +19,7 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
Memory::WriteBlock(output_buffer.Address(), lang_codes.data(), lang_codes.size());
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(lang_codes.size()));
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 7b1c8ee37..a81ff9f49 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -4,30 +4,26 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/domain.h"
#include "core/hle/service/sm/controller.h"
namespace Service {
namespace SM {
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
- auto domain = Kernel::Domain::CreateFromSession(*ctx.ServerSession()->parent).Unwrap();
+ ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain");
+ ctx.Session()->ConvertToDomain();
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u32>(domain->request_handlers.size()));
+ rb.Push<u32>(1); // Converted sessions start with 1 request handler
- LOG_DEBUG(Service, "called, domain=%d", domain->GetObjectId());
+ LOG_DEBUG(Service, "called, server_session=%d", ctx.Session()->GetObjectId());
}
void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(RESULT_SUCCESS);
- // TODO(Subv): Check if this is correct
- if (ctx.IsDomain())
- rb.PushMoveObjects(ctx.Domain());
- else
- rb.PushMoveObjects(ctx.ServerSession());
+ rb.PushMoveObjects(ctx.Session());
LOG_DEBUG(Service, "called");
}
@@ -39,7 +35,7 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
}
void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0x500);
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index c4078f02f..73aa013e3 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -83,7 +83,7 @@ std::shared_ptr<ServiceManager> g_service_manager;
* 0: ResultCode
*/
void SM::Initialize(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 1};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_DEBUG(Service_SM, "called");
}
@@ -99,7 +99,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
auto client_port = service_manager->GetServicePort(name);
if (client_port.Failed()) {
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(client_port.Code());
LOG_ERROR(Service_SM, "called service=%s -> error 0x%08X", name.c_str(),
client_port.Code().raw);
@@ -112,7 +112,8 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
if (session.Succeeded()) {
LOG_DEBUG(Service_SM, "called service=%s -> session=%u", name.c_str(),
(*session)->GetObjectId());
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 1, 0);
+ IPC::ResponseBuilder rb =
+ rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles);
rb.Push(session.Code());
rb.PushMoveObjects(std::move(session).Unwrap());
}
diff --git a/src/core/hle/service/sockets/bsd_u.cpp b/src/core/hle/service/sockets/bsd_u.cpp
index a819acc96..4fd960bd8 100644
--- a/src/core/hle/service/sockets/bsd_u.cpp
+++ b/src/core/hle/service/sockets/bsd_u.cpp
@@ -11,7 +11,7 @@ namespace Sockets {
void BSD_U::RegisterClient(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // bsd errno
@@ -28,7 +28,7 @@ void BSD_U::Socket(Kernel::HLERequestContext& ctx) {
u32 fd = next_fd++;
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(fd);
@@ -38,7 +38,7 @@ void BSD_U::Socket(Kernel::HLERequestContext& ctx) {
void BSD_U::Connect(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // ret
@@ -48,7 +48,7 @@ void BSD_U::Connect(Kernel::HLERequestContext& ctx) {
void BSD_U::SendTo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // ret
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 9fed89246..5802f6f6c 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -4,6 +4,7 @@
#include <chrono>
#include "common/logging/log.h"
+#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
@@ -19,25 +20,47 @@ public:
ISystemClock() : ServiceFramework("ISystemClock") {
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
- };
+ {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}};
RegisterHandlers(functions);
}
private:
void GetCurrentTime(Kernel::HLERequestContext& ctx) {
- const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::milliseconds>(
+ const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
- IPC::RequestBuilder rb{ctx, 4};
+ LOG_DEBUG(Service, "called");
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(time_since_epoch);
- LOG_DEBUG(Service, "called");
+ }
+
+ void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called");
+ SystemClockContext system_clock_ontext{};
+ IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(system_clock_ontext);
}
};
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
public:
- ISteadyClock() : ServiceFramework("ISteadyClock") {}
+ ISteadyClock() : ServiceFramework("ISteadyClock") {
+ static const FunctionInfo functions[] = {
+ {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
+ };
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service, "called");
+ SteadyClockTimePoint steady_clock_time_point{cyclesToMs(CoreTiming::GetTicks()) / 1000};
+ IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(steady_clock_time_point);
+ }
};
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
@@ -55,14 +78,14 @@ private:
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
LocationName location_name{};
- IPC::RequestBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
+ IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(location_name);
}
void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
}
@@ -75,7 +98,7 @@ private:
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
CalendarAdditionalInfo additional_info{};
- IPC::RequestBuilder rb{ctx, 10};
+ IPC::ResponseBuilder rb{ctx, 10};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(calendar_time);
rb.PushRaw(additional_info);
@@ -83,49 +106,28 @@ private:
};
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
- auto client_port = std::make_shared<ISystemClock>()->CreatePort();
- auto session = client_port->Connect();
- if (session.Succeeded()) {
- LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u",
- (*session)->GetObjectId());
- IPC::RequestBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(std::move(session).Unwrap());
- } else {
- UNIMPLEMENTED();
- }
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISystemClock>();
+ LOG_DEBUG(Service, "called");
}
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
- auto client_port = std::make_shared<ISystemClock>()->CreatePort();
- auto session = client_port->Connect();
- if (session.Succeeded()) {
- LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u",
- (*session)->GetObjectId());
- IPC::RequestBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(std::move(session).Unwrap());
- } else {
- UNIMPLEMENTED();
- }
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISystemClock>();
+ LOG_DEBUG(Service, "called");
}
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
- auto client_port = std::make_shared<ISteadyClock>()->CreatePort();
- auto session = client_port->Connect();
- if (session.Succeeded()) {
- LOG_DEBUG(Service, "called, initialized ISteadyClock -> session=%u",
- (*session)->GetObjectId());
- IPC::RequestBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(std::move(session).Unwrap());
- } else {
- UNIMPLEMENTED();
- }
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISteadyClock>();
+ LOG_DEBUG(Service, "called");
}
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ITimeZoneService>();
LOG_DEBUG(Service, "called");
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 399f474d6..1cbbadb21 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -33,6 +33,19 @@ struct CalendarAdditionalInfo {
static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
"CalendarAdditionalInfo structure has incorrect size");
+// TODO(bunnei) RE this structure
+struct SystemClockContext {
+ INSERT_PADDING_BYTES(0x20);
+};
+static_assert(sizeof(SystemClockContext) == 0x20,
+ "SystemClockContext structure has incorrect size");
+
+struct SteadyClockTimePoint {
+ u64 value;
+ INSERT_PADDING_WORDS(4);
+};
+static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index c624e734e..3b993f36c 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -8,8 +8,7 @@
#include "common/scope_exit.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
-#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/vi/vi.h"
#include "core/hle/service/vi/vi_m.h"
#include "video_core/renderer_base.h"
@@ -18,9 +17,6 @@
namespace Service {
namespace VI {
-constexpr size_t SCREEN_REFRESH_RATE = 60;
-constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
-
class Parcel {
public:
// This default size was chosen arbitrarily.
@@ -204,8 +200,8 @@ public:
void DeserializeData() override {
std::u16string token = ReadInterfaceToken();
data = Read<Data>();
- ASSERT(data.graphic_buffer_length == sizeof(IGBPBuffer));
- buffer = Read<IGBPBuffer>();
+ ASSERT(data.graphic_buffer_length == sizeof(NVFlinger::IGBPBuffer));
+ buffer = Read<NVFlinger::IGBPBuffer>();
}
struct Data {
@@ -216,7 +212,7 @@ public:
};
Data data;
- IGBPBuffer buffer;
+ NVFlinger::IGBPBuffer buffer;
};
class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
@@ -288,7 +284,8 @@ public:
class IGBPRequestBufferResponseParcel : public Parcel {
public:
- explicit IGBPRequestBufferResponseParcel(IGBPBuffer buffer) : Parcel(), buffer(buffer) {}
+ explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer)
+ : Parcel(), buffer(buffer) {}
~IGBPRequestBufferResponseParcel() override = default;
protected:
@@ -296,7 +293,7 @@ protected:
// TODO(Subv): Find out what this all means
Write<u32_le>(1);
- Write<u32_le>(sizeof(IGBPBuffer));
+ Write<u32_le>(sizeof(NVFlinger::IGBPBuffer));
Write<u32_le>(0); // Unknown
Write(buffer);
@@ -304,7 +301,7 @@ protected:
Write<u32_le>(0);
}
- IGBPBuffer buffer;
+ NVFlinger::IGBPBuffer buffer;
};
class IGBPQueueBufferRequestParcel : public Parcel {
@@ -356,9 +353,38 @@ private:
Data data{};
};
+class IGBPQueryRequestParcel : public Parcel {
+public:
+ explicit IGBPQueryRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) {
+ Deserialize();
+ }
+ ~IGBPQueryRequestParcel() override = default;
+
+ void DeserializeData() override {
+ std::u16string token = ReadInterfaceToken();
+ type = Read<u32_le>();
+ }
+
+ u32 type;
+};
+
+class IGBPQueryResponseParcel : public Parcel {
+public:
+ explicit IGBPQueryResponseParcel(u32 value) : Parcel(), value(value) {}
+ ~IGBPQueryResponseParcel() override = default;
+
+protected:
+ void SerializeData() override {
+ Write(value);
+ }
+
+private:
+ u32_le value;
+};
+
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
public:
- explicit IHOSBinderDriver(std::shared_ptr<NVFlinger> nv_flinger)
+ explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
@@ -445,12 +471,22 @@ private:
auto response_buffer = response.Serialize();
Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
output_buffer.Size());
+ } else if (transaction == TransactionId::Query) {
+ IGBPQueryRequestParcel request{input_data};
+
+ u32 value =
+ buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
+
+ IGBPQueryResponseParcel response{value};
+ auto response_buffer = response.Serialize();
+ Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
+ output_buffer.Size());
} else {
ASSERT_MSG(false, "Unimplemented");
}
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -461,7 +497,7 @@ private:
u32 type = rp.Pop<u32>();
LOG_WARNING(Service, "(STUBBED) called id=%u, addval=%08X, type=%08X", id, addval, type);
- IPC::RequestBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -475,12 +511,12 @@ private:
// TODO(Subv): Find out what this actually is.
LOG_WARNING(Service, "(STUBBED) called id=%u, unknown=%08X", id, unknown);
- IPC::RequestBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(buffer_queue->GetNativeHandle());
}
- std::shared_ptr<NVFlinger> nv_flinger;
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
};
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@@ -501,14 +537,14 @@ private:
u64 layer_id = rp.Pop<u64>();
u64 z_value = rp.Pop<u64>();
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
};
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
public:
- explicit IManagerDisplayService(std::shared_ptr<NVFlinger> nv_flinger)
+ explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
{1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
@@ -526,7 +562,7 @@ private:
IPC::RequestParser rp{ctx};
u64 display = rp.Pop<u64>();
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
@@ -540,7 +576,7 @@ private:
u64 layer_id = nv_flinger->CreateLayer(display);
- IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
rb.Push(RESULT_SUCCESS);
rb.Push(layer_id);
}
@@ -551,17 +587,17 @@ private:
u32 stack = rp.Pop<u32>();
u64 layer_id = rp.Pop<u64>();
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
- std::shared_ptr<NVFlinger> nv_flinger;
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
};
void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger);
}
@@ -569,7 +605,7 @@ void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx)
void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemDisplayService>();
}
@@ -577,7 +613,7 @@ void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestConte
void IApplicationDisplayService::GetManagerDisplayService(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IManagerDisplayService>(nv_flinger);
}
@@ -586,7 +622,7 @@ void IApplicationDisplayService::GetIndirectDisplayTransactionService(
Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger);
}
@@ -601,7 +637,7 @@ void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
- IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(nv_flinger->OpenDisplay(name));
}
@@ -611,7 +647,7 @@ void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u64 display_id = rp.Pop<u64>();
- IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
rb.Push(RESULT_SUCCESS);
}
@@ -635,7 +671,7 @@ void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) {
auto data = native_window.Serialize();
Memory::WriteBlock(buffer.Address(), data.data(), data.size());
- IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(data.size());
}
@@ -658,7 +694,7 @@ void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx
auto data = native_window.Serialize();
Memory::WriteBlock(buffer.Address(), data.data(), data.size());
- IPC::RequestBuilder rb = rp.MakeBuilder(6, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
rb.Push(RESULT_SUCCESS);
rb.Push(layer_id);
rb.Push<u64>(data.size());
@@ -670,7 +706,7 @@ void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ct
IPC::RequestParser rp{ctx};
u64 layer_id = rp.Pop<u64>();
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
@@ -680,7 +716,7 @@ void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext&
u32 scaling_mode = rp.Pop<u32>();
u64 unknown = rp.Pop<u64>();
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
@@ -691,12 +727,13 @@ void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext&
auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 1, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0);
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(vsync_event);
}
-IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger)
+IApplicationDisplayService::IApplicationDisplayService(
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
{100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
@@ -716,212 +753,9 @@ IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger
RegisterHandlers(functions);
}
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<VI_M>()->InstallAsService(service_manager);
-}
-
-NVFlinger::NVFlinger() {
- // Add the different displays to the list of displays.
- Display default_{0, "Default"};
- Display external{1, "External"};
- Display edid{2, "Edid"};
- Display internal{3, "Internal"};
-
- displays.emplace_back(default_);
- displays.emplace_back(external);
- displays.emplace_back(edid);
- displays.emplace_back(internal);
-
- // Schedule the screen composition events
- composition_event =
- CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) {
- Compose();
- CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event);
- });
-
- CoreTiming::ScheduleEvent(frame_ticks, composition_event);
-}
-
-NVFlinger::~NVFlinger() {
- CoreTiming::UnscheduleEvent(composition_event, 0);
-}
-
-u64 NVFlinger::OpenDisplay(const std::string& name) {
- LOG_WARNING(Service, "Opening display %s", name.c_str());
-
- // TODO(Subv): Currently we only support the Default display.
- ASSERT(name == "Default");
-
- auto itr = std::find_if(displays.begin(), displays.end(),
- [&](const Display& display) { return display.name == name; });
-
- ASSERT(itr != displays.end());
-
- return itr->id;
-}
-
-u64 NVFlinger::CreateLayer(u64 display_id) {
- auto& display = GetDisplay(display_id);
-
- ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment");
-
- u64 layer_id = next_layer_id++;
- u32 buffer_queue_id = next_buffer_queue_id++;
- auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id);
- display.layers.emplace_back(layer_id, buffer_queue);
- buffer_queues.emplace_back(std::move(buffer_queue));
- return layer_id;
-}
-
-u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
- const auto& layer = GetLayer(display_id, layer_id);
- return layer.buffer_queue->GetId();
-}
-
-Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) {
- const auto& display = GetDisplay(display_id);
- return display.vsync_event;
-}
-
-std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
- auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
- [&](const auto& queue) { return queue->GetId() == id; });
-
- ASSERT(itr != buffer_queues.end());
- return *itr;
-}
-
-Display& NVFlinger::GetDisplay(u64 display_id) {
- auto itr = std::find_if(displays.begin(), displays.end(),
- [&](const Display& display) { return display.id == display_id; });
-
- ASSERT(itr != displays.end());
- return *itr;
-}
-
-Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
- auto& display = GetDisplay(display_id);
-
- auto itr = std::find_if(display.layers.begin(), display.layers.end(),
- [&](const Layer& layer) { return layer.id == layer_id; });
-
- ASSERT(itr != display.layers.end());
- return *itr;
-}
-
-void NVFlinger::Compose() {
- for (auto& display : displays) {
- // Trigger vsync for this display at the end of drawing
- SCOPE_EXIT({ display.vsync_event->Signal(); });
-
- // Don't do anything for displays without layers.
- if (display.layers.empty())
- continue;
-
- // TODO(Subv): Support more than 1 layer.
- ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported");
-
- Layer& layer = display.layers[0];
- auto& buffer_queue = layer.buffer_queue;
-
- // Search for a queued buffer and acquire it
- auto buffer = buffer_queue->AcquireBuffer();
-
- if (buffer == boost::none) {
- // There was no queued buffer to draw, render previous frame
- VideoCore::g_renderer->SwapBuffers({});
- continue;
- }
-
- auto& igbp_buffer = buffer->igbp_buffer;
-
- // Now send the buffer to the GPU for drawing.
- auto nvdrv = Nvidia::nvdrv.lock();
- ASSERT(nvdrv);
-
- // TODO(Subv): Support more than just disp0. The display device selection is probably based
- // on which display we're drawing (Default, Internal, External, etc)
- auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
- ASSERT(nvdisp);
-
- nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
- igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride);
-
- buffer_queue->ReleaseBuffer(buffer->slot);
- }
-}
-
-BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
- native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
-}
-
-void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
- Buffer buffer{};
- buffer.slot = slot;
- buffer.igbp_buffer = igbp_buffer;
- buffer.status = Buffer::Status::Free;
-
- LOG_WARNING(Service, "Adding graphics buffer %u", slot);
-
- queue.emplace_back(buffer);
-}
-
-u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) {
- auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
- // Only consider free buffers. Buffers become free once again after they've been Acquired
- // and Released by the compositor, see the NVFlinger::Compose method.
- if (buffer.status != Buffer::Status::Free)
- return false;
-
- // Make sure that the parameters match.
- auto& igbp_buffer = buffer.igbp_buffer;
- return igbp_buffer.format == pixel_format && igbp_buffer.width == width &&
- igbp_buffer.height == height;
- });
- ASSERT(itr != queue.end());
-
- itr->status = Buffer::Status::Dequeued;
- return itr->slot;
-}
-
-const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
- auto itr = std::find_if(queue.begin(), queue.end(),
- [&](const Buffer& buffer) { return buffer.slot == slot; });
- ASSERT(itr != queue.end());
- ASSERT(itr->status == Buffer::Status::Dequeued);
- return itr->igbp_buffer;
-}
-
-void BufferQueue::QueueBuffer(u32 slot) {
- auto itr = std::find_if(queue.begin(), queue.end(),
- [&](const Buffer& buffer) { return buffer.slot == slot; });
- ASSERT(itr != queue.end());
- ASSERT(itr->status == Buffer::Status::Dequeued);
- itr->status = Buffer::Status::Queued;
-}
-
-boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
- auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) {
- return buffer.status == Buffer::Status::Queued;
- });
- if (itr == queue.end())
- return boost::none;
- itr->status = Buffer::Status::Acquired;
- return *itr;
-}
-
-void BufferQueue::ReleaseBuffer(u32 slot) {
- auto itr = std::find_if(queue.begin(), queue.end(),
- [&](const Buffer& buffer) { return buffer.slot == slot; });
- ASSERT(itr != queue.end());
- ASSERT(itr->status == Buffer::Status::Acquired);
- itr->status = Buffer::Status::Free;
-}
-
-Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
-
-Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
- vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event");
+void InstallInterfaces(SM::ServiceManager& service_manager,
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) {
+ std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager);
}
} // namespace VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 81d4f3daa..a6e084f87 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -7,6 +7,7 @@
#include <memory>
#include <boost/optional.hpp>
#include "core/hle/kernel/event.h"
+#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/service.h"
namespace CoreTiming {
@@ -16,127 +17,9 @@ struct EventType;
namespace Service {
namespace VI {
-struct IGBPBuffer {
- u32_le magic;
- u32_le width;
- u32_le height;
- u32_le stride;
- u32_le format;
- u32_le usage;
- INSERT_PADDING_WORDS(1);
- u32_le index;
- INSERT_PADDING_WORDS(3);
- u32_le gpu_buffer_id;
- INSERT_PADDING_WORDS(17);
- u32_le nvmap_handle;
- u32_le offset;
- INSERT_PADDING_WORDS(60);
-};
-
-static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size");
-
-class BufferQueue {
-public:
- BufferQueue(u32 id, u64 layer_id);
- ~BufferQueue() = default;
-
- struct Buffer {
- enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 };
-
- u32 slot;
- Status status = Status::Free;
- IGBPBuffer igbp_buffer;
- };
-
- void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
- u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height);
- const IGBPBuffer& RequestBuffer(u32 slot) const;
- void QueueBuffer(u32 slot);
- boost::optional<const Buffer&> AcquireBuffer();
- void ReleaseBuffer(u32 slot);
-
- u32 GetId() const {
- return id;
- }
-
- Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const {
- return native_handle;
- }
-
-private:
- u32 id;
- u64 layer_id;
-
- std::vector<Buffer> queue;
- Kernel::SharedPtr<Kernel::Event> native_handle;
-};
-
-struct Layer {
- Layer(u64 id, std::shared_ptr<BufferQueue> queue);
- ~Layer() = default;
-
- u64 id;
- std::shared_ptr<BufferQueue> buffer_queue;
-};
-
-struct Display {
- Display(u64 id, std::string name);
- ~Display() = default;
-
- u64 id;
- std::string name;
-
- std::vector<Layer> layers;
- Kernel::SharedPtr<Kernel::Event> vsync_event;
-};
-
-class NVFlinger {
-public:
- NVFlinger();
- ~NVFlinger();
-
- /// Opens the specified display and returns the id.
- u64 OpenDisplay(const std::string& name);
-
- /// Creates a layer on the specified display and returns the layer id.
- u64 CreateLayer(u64 display_id);
-
- /// Gets the buffer queue id of the specified layer in the specified display.
- u32 GetBufferQueueId(u64 display_id, u64 layer_id);
-
- /// Gets the vsync event for the specified display.
- Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id);
-
- /// Obtains a buffer queue identified by the id.
- std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
-
- /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
- /// finished.
- void Compose();
-
-private:
- /// Returns the display identified by the specified id.
- Display& GetDisplay(u64 display_id);
-
- /// Returns the layer identified by the specified id in the desired display.
- Layer& GetLayer(u64 display_id, u64 layer_id);
-
- std::vector<Display> displays;
- std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
-
- /// Id to use for the next layer that is created, this counter is shared among all displays.
- u64 next_layer_id = 1;
- /// Id to use for the next buffer queue that is created, this counter is shared among all
- /// layers.
- u32 next_buffer_queue_id = 1;
-
- /// CoreTiming event that handles screen composition.
- CoreTiming::EventType* composition_event;
-};
-
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
- IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger);
+ IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
~IApplicationDisplayService() = default;
private:
@@ -152,11 +35,12 @@ private:
void DestroyStrayLayer(Kernel::HLERequestContext& ctx);
void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx);
- std::shared_ptr<NVFlinger> nv_flinger;
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
};
/// Registers all VI services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager,
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
} // namespace VI
} // namespace Service
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 1a5a28b0d..bb440cadb 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -13,17 +13,18 @@ namespace VI {
void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
- IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger);
}
-VI_M::VI_M() : ServiceFramework("vi:m") {
+VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
+ : ServiceFramework("vi:m"), nv_flinger(std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
{2, &VI_M::GetDisplayService, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
};
RegisterHandlers(functions);
- nv_flinger = std::make_shared<NVFlinger>();
}
} // namespace VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index 70ff7a2f3..e5319b1e7 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -8,17 +8,21 @@
#include "core/hle/service/service.h"
namespace Service {
+namespace NVFlinger {
+class NVFlinger;
+}
+
namespace VI {
class VI_M final : public ServiceFramework<VI_M> {
public:
- VI_M();
+ VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
~VI_M() = default;
private:
void GetDisplayService(Kernel::HLERequestContext& ctx);
- std::shared_ptr<NVFlinger> nv_flinger;
+ std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
};
} // namespace VI