From 925d05d049fcf03737031d907e3bfdfb5f7b4dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Thu, 23 Apr 2020 22:09:40 +0530 Subject: [PATCH] Add String Support to IPC Push/Pop This commit does some minor renaming/reordering in IPC and adds support for strings to IPC Push/Pop. It also fixes a tiny regression with the frametime display. --- app/src/main/cpp/skyline/gpu.cpp | 2 +- app/src/main/cpp/skyline/kernel/ipc.cpp | 18 +++++----- app/src/main/cpp/skyline/kernel/ipc.h | 34 +++++++++++++++---- .../skyline/services/sm/IUserInterface.cpp | 2 +- .../visrv/IApplicationDisplayService.cpp | 2 +- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp index 1b423899..f41220a2 100644 --- a/app/src/main/cpp/skyline/gpu.cpp +++ b/app/src/main/cpp/skyline/gpu.cpp @@ -62,7 +62,7 @@ namespace skyline::gpu { if (frameTimestamp) { auto now = util::GetTimeNs(); - frametime = static_cast((now - frameTimestamp) / (constant::NsInSecond / 100)); // frametime / 100 is the real ms value, this is to retain the first two decimals + frametime = static_cast((now - frameTimestamp) / 10000); // frametime / 100 is the real ms value, this is to retain the first two decimals fps = static_cast(constant::NsInSecond / (now - frameTimestamp)); frameTimestamp = now; diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp index 62cd9165..44dc8998 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.cpp +++ b/app/src/main/cpp/skyline/kernel/ipc.cpp @@ -143,7 +143,7 @@ namespace skyline::kernel::ipc { memset(tls, 0, constant::TlsIpcSize); auto header = reinterpret_cast(pointer); - header->rawSize = static_cast((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(KHandle)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo + header->rawSize = static_cast((sizeof(PayloadHeader) + payload.size() + (domainObjects.size() * sizeof(KHandle)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo header->handleDesc = (!copyHandles.empty() || !moveHandles.empty()); pointer += sizeof(CommandHeader); @@ -174,15 +174,15 @@ namespace skyline::kernel::ipc { pointer += sizeof(DomainHeaderResponse); } - auto payload = reinterpret_cast(pointer); - payload->magic = util::MakeMagic("SFCO"); // SFCO is the magic in IPC responses - payload->version = 1; - payload->value = errorCode; + auto payloadHeader = reinterpret_cast(pointer); + payloadHeader->magic = util::MakeMagic("SFCO"); // SFCO is the magic in IPC responses + payloadHeader->version = 1; + payloadHeader->value = errorCode; pointer += sizeof(PayloadHeader); - if (!argVec.empty()) - std::memcpy(pointer, argVec.data(), argVec.size()); - pointer += argVec.size(); + if (!payload.empty()) + std::memcpy(pointer, payload.data(), payload.size()); + pointer += payload.size(); if (isDomain) { for (auto &domainObject : domainObjects) { @@ -191,6 +191,6 @@ namespace skyline::kernel::ipc { } } - state.logger->Debug("Output: Raw Size: {}, Command ID: 0x{:X}, Copy Handles: {}, Move Handles: {}", u32(header->rawSize), u32(payload->value), copyHandles.size(), moveHandles.size()); + state.logger->Debug("Output: Raw Size: {}, Command ID: 0x{:X}, Copy Handles: {}, Move Handles: {}", u32(header->rawSize), u32(payloadHeader->value), copyHandles.size(), moveHandles.size()); } } diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index 34b8cfd9..2f7eb03b 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -281,6 +281,16 @@ namespace skyline { return value; } + /** + * @brief This returns a std::string_view from the payload + * @param size The length of the string (0 means the string is null terminated) + */ + inline std::string_view PopString(size_t size = 0) { + auto view = size ? std::string_view(reinterpret_cast(payloadOffset), size) : std::string_view(reinterpret_cast(payloadOffset)); + payloadOffset += view.length(); + return view; + } + /** * @brief This skips an object to pop off the top * @tparam ValueType The type of the object to skip @@ -296,8 +306,8 @@ namespace skyline { */ class IpcResponse { private: - std::vector argVec; //!< This holds all of the contents to be pushed to the payload const DeviceState &state; //!< The state of the device + std::vector payload; //!< This holds all of the contents to be pushed to the payload public: bool nWrite{}; //!< This is to signal the IPC handler to not write this, as it will be manually written @@ -320,12 +330,22 @@ namespace skyline { */ template inline void Push(const ValueType &value) { - argVec.reserve(argVec.size() + sizeof(ValueType)); - auto item = reinterpret_cast(&value); - for (uint index = 0; sizeof(ValueType) > index; index++) { - argVec.push_back(*item); - item++; - } + auto size = payload.size(); + payload.resize(size + sizeof(ValueType)); + + std::memcpy(payload.data() + size, reinterpret_cast(&value), sizeof(ValueType)); + } + + /** + * @brief Writes a string to the payload + * @param string The string to write to the payload + */ + template<> + inline void Push(const std::string &string) { + auto size = payload.size(); + payload.resize(size + string.size()); + + std::memcpy(payload.data() + size, string.data(), string.size()); } /** diff --git a/app/src/main/cpp/skyline/services/sm/IUserInterface.cpp b/app/src/main/cpp/skyline/services/sm/IUserInterface.cpp index 19244a5b..6bf06d50 100644 --- a/app/src/main/cpp/skyline/services/sm/IUserInterface.cpp +++ b/app/src/main/cpp/skyline/services/sm/IUserInterface.cpp @@ -12,7 +12,7 @@ namespace skyline::service::sm { void IUserInterface::Initialize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} void IUserInterface::GetService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - std::string serviceName(reinterpret_cast(request.cmdArg)); + std::string serviceName(request.PopString()); if (serviceName.empty()) { response.errorCode = constant::status::ServiceInvName; diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp index b6268439..ad1601de 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp @@ -41,7 +41,7 @@ namespace skyline::service::visrv { } void IApplicationDisplayService::OpenDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - std::string displayName(reinterpret_cast(request.cmdArg)); + std::string displayName(request.PopString()); state.logger->Debug("Setting display as: {}", displayName); state.os->serviceManager.GetService(Service::hosbinder_IHOSBinderDriver)->SetDisplay(displayName);