diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp index 8e688ba8..7129c423 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.cpp +++ b/app/src/main/cpp/skyline/kernel/ipc.cpp @@ -10,6 +10,7 @@ namespace skyline::kernel::ipc { u8 *pointer{tls}; header = reinterpret_cast(pointer); + isTipc = static_cast(header->type) > static_cast(CommandType::TipcCloseSession); pointer += sizeof(CommandHeader); if (header->handleDesc) { @@ -64,39 +65,43 @@ namespace skyline::kernel::ipc { auto bufCPointer{pointer + header->rawSize * sizeof(u32)}; - size_t offset{static_cast(pointer - tls)}; // We calculate the relative offset as the absolute one might differ - auto padding{util::AlignUp(offset, constant::IpcPaddingSum) - offset}; // Calculate the amount of padding at the front - pointer += padding; - - if (isDomain && (header->type == CommandType::Request || header->type == CommandType::RequestWithContext)) { - domain = reinterpret_cast(pointer); - pointer += sizeof(DomainHeaderRequest); - - payload = reinterpret_cast(pointer); - pointer += sizeof(PayloadHeader); - - cmdArg = pointer; - cmdArgSz = domain->payloadSz - sizeof(PayloadHeader); - pointer += cmdArgSz; - - for (u8 index{}; domain->inputCount > index; index++) { - domainObjects.push_back(*reinterpret_cast(pointer)); - pointer += sizeof(KHandle); - } - } else { - payload = reinterpret_cast(pointer); - pointer += sizeof(PayloadHeader); - + if (isTipc) { cmdArg = pointer; cmdArgSz = header->rawSize * sizeof(u32); + } else { + size_t offset{static_cast(pointer - tls)}; // We calculate the relative offset as the absolute one might differ + auto padding{util::AlignUp(offset, constant::IpcPaddingSum) - offset}; // Calculate the amount of padding at the front + pointer += padding; + + if (isDomain && (header->type == CommandType::Request || header->type == CommandType::RequestWithContext)) { + domain = reinterpret_cast(pointer); + pointer += sizeof(DomainHeaderRequest); + + payload = reinterpret_cast(pointer); + pointer += sizeof(PayloadHeader); + + cmdArg = pointer; + cmdArgSz = domain->payloadSz - sizeof(PayloadHeader); + pointer += cmdArgSz; + + for (u8 index{}; domain->inputCount > index; index++) { + domainObjects.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(KHandle); + } + } else { + payload = reinterpret_cast(pointer); + pointer += sizeof(PayloadHeader); + + cmdArg = pointer; + cmdArgSz = header->rawSize * sizeof(u32); + } } payloadOffset = cmdArg; - if (payload->magic != util::MakeMagic("SFCI") && (header->type != CommandType::Control && header->type != CommandType::ControlWithContext && header->type != CommandType::Close) && (!domain || domain->command != DomainCommand::CloseVHandle)) // SFCI is the magic in received IPC messages + if (!isTipc && payload->magic != util::MakeMagic("SFCI") && (header->type != CommandType::Control && header->type != CommandType::ControlWithContext && header->type != CommandType::Close) && (!domain || domain->command != DomainCommand::CloseVHandle)) // SFCI is the magic in received IPC messages Logger::Debug("Unexpected Magic in PayloadHeader: 0x{:X}", static_cast(payload->magic)); - if (header->cFlag == BufferCFlag::SingleDescriptor) { auto bufC{reinterpret_cast(bufCPointer)}; if (bufC->address) { @@ -120,20 +125,25 @@ namespace skyline::kernel::ipc { Logger::Verbose("Handle Descriptor: Send PID: {}, Copy Count: {}, Move Count: {}", static_cast(handleDesc->sendPid), static_cast(handleDesc->copyCount), static_cast(handleDesc->moveCount)); if (isDomain) Logger::Verbose("Domain Header: Command: {}, Input Object Count: {}, Object ID: 0x{:X}", domain->command, domain->inputCount, domain->objectId); - Logger::Verbose("Command ID: 0x{:X}", static_cast(payload->value)); + + if (isTipc) + Logger::Verbose("TIPC Command ID: 0x{:X}", static_cast(header->type)); + else + Logger::Verbose("Command ID: 0x{:X}", static_cast(payload->value)); } } IpcResponse::IpcResponse(const DeviceState &state) : state(state) {} - void IpcResponse::WriteResponse(bool isDomain) { + void IpcResponse::WriteResponse(bool isDomain, bool isTipc) { auto tls{state.ctx->tpidrroEl0}; u8 *pointer{tls}; memset(tls, 0, constant::TlsIpcSize); auto header{reinterpret_cast(pointer)}; - 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 + size_t sizeBytes{isTipc ? (payload.size() + sizeof(Result)) : (sizeof(PayloadHeader) + constant::IpcPaddingSum + payload.size() + (domainObjects.size() * sizeof(KHandle)) + (isDomain ? sizeof(DomainHeaderRequest) : 0))}; + header->rawSize = static_cast(util::DivideCeil(sizeBytes, sizeof(u32))); // Size is in 32-bit units because Nintendo header->handleDesc = (!copyHandles.empty() || !moveHandles.empty()); pointer += sizeof(CommandHeader); @@ -154,33 +164,39 @@ namespace skyline::kernel::ipc { } } - size_t offset{static_cast(pointer - tls)}; // We calculate the relative offset as the absolute one might differ - auto padding{util::AlignUp(offset, constant::IpcPaddingSum) - offset}; // Calculate the amount of padding at the front - pointer += padding; - - if (isDomain) { - auto domain{reinterpret_cast(pointer)}; - domain->outputCount = static_cast(domainObjects.size()); - pointer += sizeof(DomainHeaderResponse); - } - - 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 (!payload.empty()) + if (isTipc) { + *reinterpret_cast(pointer) = errorCode; + pointer += sizeof(Result); std::memcpy(pointer, payload.data(), payload.size()); - pointer += payload.size(); + } else { + size_t offset{static_cast(pointer - tls)}; // We calculate the relative offset as the absolute one might differ + auto padding{util::AlignUp(offset, constant::IpcPaddingSum) - offset}; // Calculate the amount of padding at the front + pointer += padding; - if (isDomain) { - for (auto &domainObject : domainObjects) { - *reinterpret_cast(pointer) = domainObject; - pointer += sizeof(KHandle); + if (isDomain) { + auto domain{reinterpret_cast(pointer)}; + domain->outputCount = static_cast(domainObjects.size()); + pointer += sizeof(DomainHeaderResponse); + } + + 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 (!payload.empty()) + std::memcpy(pointer, payload.data(), payload.size()); + pointer += payload.size(); + + if (isDomain) { + for (auto &domainObject : domainObjects) { + *reinterpret_cast(pointer) = domainObject; + pointer += sizeof(KHandle); + } } } - Logger::Verbose("Output: Raw Size: {}, Result: 0x{:X}, Copy Handles: {}, Move Handles: {}", static_cast(header->rawSize), static_cast(payloadHeader->value), copyHandles.size(), moveHandles.size()); + Logger::Verbose("Output: Raw Size: {}, Result: 0x{:X}, Copy Handles: {}, Move Handles: {}", static_cast(header->rawSize), static_cast(errorCode), 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 eeda4dc5..3f19ee6d 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -26,6 +26,7 @@ namespace skyline { Control = 5, //!< A transaction between the client and IPC Manager RequestWithContext = 6, //!< Request with Token ControlWithContext = 7, //!< Control with Token + TipcCloseSession = 0xF, }; /** @@ -196,6 +197,7 @@ namespace skyline { CommandHeader *header{}; HandleDescriptor *handleDesc{}; bool isDomain{}; //!< If this is a domain request + bool isTipc; //!< If this is request uses the TIPC protocol DomainHeaderRequest *domain{}; PayloadHeader *payload{}; u8 *cmdArg{}; //!< A pointer to the data payload @@ -298,8 +300,9 @@ namespace skyline { /** * @brief Writes this IpcResponse object's contents into TLS * @param isDomain Indicates if this is a domain response + * @param isTipc Indicates if this is a TIPC response */ - void WriteResponse(bool isDomain); + void WriteResponse(bool isDomain, bool isTipc = false); }; } } diff --git a/app/src/main/cpp/skyline/services/base_service.cpp b/app/src/main/cpp/skyline/services/base_service.cpp index 1efd0079..56c1a855 100644 --- a/app/src/main/cpp/skyline/services/base_service.cpp +++ b/app/src/main/cpp/skyline/services/base_service.cpp @@ -21,11 +21,13 @@ namespace skyline::service { Result service::BaseService::HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { ServiceFunctionDescriptor function; + u32 functionId{request.isTipc ? static_cast(request.header->type) : request.payload->value}; + try { - function = GetServiceFunction(request.payload->value); + function = GetServiceFunction(functionId, request.isTipc); Logger::DebugNoPrefix("Service: {}", function.name); } catch (const std::out_of_range &) { - Logger::Warn("Cannot find function in service '{0}': 0x{1:X} ({1})", GetName(), static_cast(request.payload->value)); + Logger::Warn("Cannot find {0} function in service '{1}': 0x{2:X} ({2})", request.isTipc ? "TIPC" : "HIPC", GetName(), static_cast(functionId)); return {}; } TRACE_EVENT("service", perfetto::StaticString{function.name}); diff --git a/app/src/main/cpp/skyline/services/base_service.h b/app/src/main/cpp/skyline/services/base_service.h index 35cd326b..c7f3a1f7 100644 --- a/app/src/main/cpp/skyline/services/base_service.h +++ b/app/src/main/cpp/skyline/services/base_service.h @@ -5,8 +5,10 @@ #include +constexpr static skyline::u32 TipcFunctionIdFlag{1U << 31}; //!< Flag applied to the stored service function ID to differentiate between TIPC and HIPC functions #define SERVICE_STRINGIFY(string) #string #define SFUNC(id, Class, Function) std::pair>{id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}} +#define SFUNC_TIPC(id, Class, Function) std::pair>{TipcFunctionIdFlag | id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}} #define SFUNC_BASE(id, Class, BaseClass, Function) std::pair>{id, {&Class::CallBaseFunction, SERVICE_STRINGIFY(Class::Function)}} #define SERVICE_DECL_AUTO(name, value) decltype(value) name = value #define SERVICE_DECL(...) \ @@ -15,10 +17,10 @@ template(this)->*BaseFunction)(session, request, response); \ } \ -SERVICE_DECL_AUTO(functions, frozen::make_unordered_map({__VA_ARGS__})); \ +SERVICE_DECL_AUTO(functions, frozen::make_unordered_map({__VA_ARGS__})); \ protected: \ -ServiceFunctionDescriptor GetServiceFunction(u32 id) override { \ - auto& function{functions.at(id)}; \ +ServiceFunctionDescriptor GetServiceFunction(u32 id, bool isTipc) override { \ + auto& function{functions.at((isTipc ? TipcFunctionIdFlag : 0U) | id)}; \ return ServiceFunctionDescriptor{ \ reinterpret_cast(this), \ reinterpret_cast(function.first), \ @@ -71,7 +73,7 @@ namespace skyline::service { */ virtual ~BaseService() = default; - virtual ServiceFunctionDescriptor GetServiceFunction(u32 id) { + virtual ServiceFunctionDescriptor GetServiceFunction(u32 id, bool isTipc) { throw std::out_of_range("GetServiceFunction not implemented"); } diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index 27c0d04d..0c8486bc 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -238,11 +238,18 @@ namespace skyline::service { break; case ipc::CommandType::Close: + case ipc::CommandType::TipcCloseSession: Logger::Debug("Closing Session"); CloseSession(handle); break; default: - throw exception("Unimplemented IPC message type: {}", static_cast(request.header->type)); + // TIPC command ID is encoded in the request type + if (request.isTipc) { + response.errorCode = session->serviceObject->HandleRequest(*session, request, response); + response.WriteResponse(session->isDomain, true); + } else { + throw exception("Unimplemented IPC message type: {}", static_cast(request.header->type)); + } } } else { Logger::Warn("svcSendSyncRequest called on closed handle: 0x{:X}", handle); diff --git a/app/src/main/cpp/skyline/services/sm/IUserInterface.h b/app/src/main/cpp/skyline/services/sm/IUserInterface.h index 8c0ffed0..45f293c5 100644 --- a/app/src/main/cpp/skyline/services/sm/IUserInterface.h +++ b/app/src/main/cpp/skyline/services/sm/IUserInterface.h @@ -40,7 +40,9 @@ namespace skyline::service::sm { SERVICE_DECL( SFUNC(0x0, IUserInterface, Initialize), - SFUNC(0x1, IUserInterface, GetService) + SFUNC_TIPC(0x10, IUserInterface, Initialize), + SFUNC(0x1, IUserInterface, GetService), + SFUNC_TIPC(0x11, IUserInterface, GetService) ) }; }