diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4f5c449d..e8ce8702 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -121,7 +121,6 @@ add_library(skyline SHARED ${source_DIR}/skyline/vfs/ticket.cpp ${source_DIR}/skyline/services/serviceman.cpp ${source_DIR}/skyline/services/base_service.cpp - ${source_DIR}/skyline/services/common/parcel.cpp ${source_DIR}/skyline/services/sm/IUserInterface.cpp ${source_DIR}/skyline/services/fatalsrv/IService.cpp ${source_DIR}/skyline/services/audio/IAudioOutManager.cpp @@ -182,12 +181,13 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp + ${source_DIR}/skyline/services/hosbinder/parcel.cpp ${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp ${source_DIR}/skyline/services/hosbinder/GraphicBufferProducer.cpp ${source_DIR}/skyline/services/visrv/IDisplayService.cpp ${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp ${source_DIR}/skyline/services/visrv/IManagerDisplayService.cpp - ${source_DIR}/skyline/services/visrv/IManagerRootService.cpp + ${source_DIR}/skyline/services/visrv/IRootService.cpp ${source_DIR}/skyline/services/visrv/ISystemDisplayService.cpp ${source_DIR}/skyline/services/pl/IPlatformServiceManager.cpp ${source_DIR}/skyline/services/aocsrv/IAddOnContentManager.cpp diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index c86e1cca..21248e8d 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -218,11 +218,16 @@ namespace skyline { /** * @brief Returns a std::string_view from the payload - * @param size The length of the string (0 means the string is null terminated) + * @param size The length of the string (0 should only be used with nullTerminated and automatically determines size) + * @param nullTerminated If the returned view should only encapsulate a null terminated substring */ - 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(); + std::string_view PopString(size_t size = 0, bool nullTerminated = true) { + size = size ? size : cmdArgSz - reinterpret_cast(payloadOffset); + auto view{span(payloadOffset, size).as_string(nullTerminated)}; + if (nullTerminated) + payloadOffset += size; + else + payloadOffset += view.length(); return view; } diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp index 70e6e70e..7f829c33 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp @@ -2,11 +2,11 @@ // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #include -#include +#include #include "ISelfController.h" namespace skyline::service::am { - ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared(state, false)), BaseService(state, manager) {} + ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared(state, false)), hosbinder(manager.CreateOrGetService("dispdrv")), BaseService(state, manager) {} Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { return {}; @@ -47,18 +47,12 @@ namespace skyline::service::am { } Result ISelfController::CreateManagedDisplayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - state.logger->Debug("Creating Managed Layer on Default Display"); - - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized) - throw exception("The application is creating more than one layer"); - producer->layerStatus = hosbinder::LayerStatus::Managed; - - response.Push(0); + auto layerId{hosbinder->CreateLayer(hosbinder::DisplayId::Default)}; + state.logger->Debug("Creating Managed Layer #{} on 'Default' Display", layerId); + response.Push(layerId); return {}; } - Result ISelfController::GetAccumulatedSuspendedTickValue(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { // TODO: Properly handle this after we implement game suspending response.Push(0); diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.h b/app/src/main/cpp/skyline/services/am/controller/ISelfController.h index 7fd4fe02..fc7f200e 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.h +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.h @@ -5,6 +5,10 @@ #include +namespace skyline::service::hosbinder { + class IHOSBinderDriver; +} + namespace skyline::service::am { /** * @brief This has functions relating to an application's own current status @@ -14,6 +18,7 @@ namespace skyline::service::am { private: std::shared_ptr libraryAppletLaunchableEvent; //!< This KEvent is triggered when the library applet is launchable std::shared_ptr accumulatedSuspendedTickChangedEvent; //!< This KEvent is triggered when the time the system has spent in suspend is updated + std::shared_ptr hosbinder; //!< IHOSBinder service for managed display layers public: ISelfController(const DeviceState &state, ServiceManager &manager); diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp index d581a0c7..c9710c13 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp @@ -70,7 +70,7 @@ namespace skyline::service::hosbinder { } else { size_t index{}; std::string bufferString; - for (auto& bufferSlot : queue) + for (auto &bufferSlot : queue) bufferString += util::Format("\n#{} - State: {}, Has Graphic Buffer: {}, Frame Number: {}", ++index, ToString(bufferSlot.state), static_cast(bufferSlot.graphicBuffer), bufferSlot.frameNumber); state.logger->Warn("Cannot find any free buffers to dequeue:{}", bufferString); return AndroidStatus::InvalidOperation; @@ -489,31 +489,4 @@ namespace skyline::service::hosbinder { throw exception("An unimplemented transaction was called: {}", static_cast(code)); } } - - static frz::unordered_map DisplayTypeMap{ - {"Default", DisplayId::Default}, - {"External", DisplayId::External}, - {"Edid", DisplayId::Edid}, - {"Internal", DisplayId::Internal}, - {"Null", DisplayId::Null}, - }; - - void GraphicBufferProducer::SetDisplay(const std::string &name) { - try { - if (displayId == DisplayId::Null) - displayId = DisplayTypeMap.at(frz::string(name.data(), name.size())); - else - throw exception("Trying to change display type from non-null type"); - } catch (const std::out_of_range &) { - throw exception("The display with name: '{}' doesn't exist", name); - } - } - - void GraphicBufferProducer::CloseDisplay() { - if (displayId == DisplayId::Null) - state.logger->Warn("Trying to close uninitiated display"); - displayId = DisplayId::Null; - } - - std::weak_ptr producer{}; } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h index f4f5276c..06fa143b 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#include "parcel.h" #include "android_types.h" #include "native_window.h" @@ -43,24 +43,6 @@ namespace skyline::service::hosbinder { std::unique_ptr graphicBuffer{}; }; - /** - * @brief An enumeration of all the possible display IDs - * @url https://switchbrew.org/wiki/Display_services#DisplayName - */ - enum class DisplayId : u64 { - Default, //!< Refers to the default display used by most applications - External, //!< Refers to an external display - Edid, //!< Refers to an external display with EDID capabilities - Internal, //!< Refers to the the internal display - Null, //!< Refers to the null display which is used for discarding data - }; - - enum class LayerStatus { - Uninitialized, //!< The layer hasn't been initialized - Stray, //!< The layer has been initialized as a stray layer - Managed, //!< The layer has been initialized as a managed layer - }; - /** * @brief An endpoint for the GraphicBufferProducer interface, it approximately implements BufferQueueProducer but also implements the functionality of interfaces called into by it such as GraphicBufferConsumer, Gralloc and so on * @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h @@ -147,8 +129,6 @@ namespace skyline::service::hosbinder { public: std::shared_ptr bufferEvent; //!< Signalled every time a buffer in the queue is freed - DisplayId displayId{DisplayId::Null}; //!< The ID of this display - LayerStatus layerStatus{LayerStatus::Uninitialized}; //!< The status of the single layer the display has /** * @brief The transactions supported by android.gui.IGraphicBufferProducer @@ -178,18 +158,5 @@ namespace skyline::service::hosbinder { * @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp;l=277-426 */ void OnTransact(TransactionCode code, Parcel &in, Parcel &out); - - /** - * @brief Sets displayId to a specific display type - * @note displayId has to be DisplayId::Null or this will throw an exception - */ - void SetDisplay(const std::string &name); - - /** - * @brief Closes the display by setting displayId to DisplayId::Null - */ - void CloseDisplay(); }; - - extern std::weak_ptr producer; //!< A globally shared instance of the GraphicsBufferProducer } diff --git a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp index 9868eb33..659f1758 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp @@ -7,43 +7,166 @@ #include "GraphicBufferProducer.h" namespace skyline::service::hosbinder { - IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : producer(hosbinder::producer.expired() ? std::make_shared(state) : hosbinder::producer.lock()), BaseService(state, manager) { - if (hosbinder::producer.expired()) - hosbinder::producer = producer; - } + IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} Result IHOSBinderDriver::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - auto layerId{request.Pop()}; + // We opted for just supporting a single layer and display as it's what basically all games use and wasting cycles on it is pointless + // If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically + // There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer + + auto binderHandle{request.Pop()}; + if (binderHandle != DefaultBinderLayerHandle) + throw exception("Transaction on unknown binder object: #{}", binderHandle); + auto code{request.Pop()}; Parcel in(request.inputBuf.at(0), state, true); Parcel out(state); - // We opted for just supporting a single layer and display as it's what basically all games use and wasting cycles on it is pointless - // If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically - // There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer - - state.logger->Debug("Layer ID: {}, Code: {}", layerId, code); - producer->OnTransact(code, in, out); + if (!layer) + throw exception("Transacting parcel with non-existant layer"); + layer->OnTransact(code, in, out); out.WriteParcel(request.outputBuf.at(0)); return {}; } Result IHOSBinderDriver::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - request.Skip(); - auto addVal{request.Pop()}; - auto type{request.Pop()}; - state.logger->Debug("Reference Change: {} {} reference", addVal, type ? "strong" : "weak"); + auto binderHandle{request.Pop()}; + if (binderHandle != DefaultBinderLayerHandle) + throw exception("Adjusting Binder object reference count for unknown object: #{}", binderHandle); + + auto value{request.Pop()}; + bool isStrong{static_cast(request.Pop())}; + if (isStrong) { + if (layerStrongReferenceCount != InitialStrongReferenceCount) + layerStrongReferenceCount += value; + else + layerStrongReferenceCount = value; + + if (layerStrongReferenceCount < 0) { + state.logger->Warn("Strong reference count is lower than 0: {} + {} = {}", (layerStrongReferenceCount - value), value, layerStrongReferenceCount); + layerStrongReferenceCount = 0; + } + + if (layerStrongReferenceCount == 0) + layer.reset(); + } else { + layerWeakReferenceCount += value; + + if (layerWeakReferenceCount < 0) { + state.logger->Warn("Weak reference count is lower than 0: {} + {} = {}", (layerWeakReferenceCount - value), value, layerWeakReferenceCount); + layerWeakReferenceCount = 0; + } + + if (layerWeakReferenceCount == 0 && layerStrongReferenceCount < 1) + layer.reset(); + } + + state.logger->Debug("Reference Change: {} {} reference (S{} W{})", value, isStrong ? "strong" : "weak", layerStrongReferenceCount, layerWeakReferenceCount); return {}; } Result IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - KHandle handle{state.process->InsertItem(producer->bufferEvent)}; + auto binderHandle{request.Pop()}; + if (binderHandle != DefaultBinderLayerHandle) + throw exception("Getting handle from unknown binder object: #{}", binderHandle); + + constexpr u32 BufferEventHandleId{0xF}; //!< The ID of the buffer event handle in the layer object + auto handleId{request.Pop()}; + if (handleId != BufferEventHandleId) + throw exception("Getting unknown handle from binder object: 0x{:X}", handleId); + + KHandle handle{state.process->InsertItem(layer->bufferEvent)}; state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); return {}; } + + DisplayId IHOSBinderDriver::OpenDisplay(std::string_view name) { + if (name.length() > sizeof(u64)) + throw exception("Opening display with name larger than sizeof(u64): '{}' ({})", name, name.length()); + + auto newDisplayId{[&]() -> DisplayId { + #define DISPLAY_CASE(id) case util::MakeMagic(#id): { return DisplayId::id; } + switch (util::MakeMagic(name)) { + DISPLAY_CASE(Default) + DISPLAY_CASE(External) + DISPLAY_CASE(Edid) + DISPLAY_CASE(Internal) + DISPLAY_CASE(Null) + default: + throw exception("Opening non-existent display: '{}'", name); + } + #undef DISPLAY_CASE + }()}; + if (displayId != DisplayId::Null && displayId != newDisplayId) + throw exception("Opening a new display ({}) prior to closing opened display ({})", name, ToString(displayId)); + + return displayId = newDisplayId; + } + + void IHOSBinderDriver::CloseDisplay(DisplayId id) { + if (displayId != id) + throw exception("Closing an unopened display: {} (Currently open display: {})", ToString(id), ToString(displayId)); + displayId = DisplayId::Null; + } + + u64 IHOSBinderDriver::CreateLayer(DisplayId pDisplayId) { + if (pDisplayId != displayId) + throw exception("Creating layer on unopened display: '{}'", ToString(pDisplayId)); + else if (layer) + throw exception("Creation of multiple layers is not supported"); + + layerStrongReferenceCount = InitialStrongReferenceCount; + layerWeakReferenceCount = 0; + layer.emplace(state); + + return DefaultLayerId; + } + + Parcel IHOSBinderDriver::OpenLayer(DisplayId pDisplayId, u64 layerId) { + if (pDisplayId != displayId) + throw exception("Opening layer #{} with unopened display: '{}'", layerId, ToString(pDisplayId)); + else if (layerId != DefaultLayerId) + throw exception("Attempting to open unrecognized layer #{}", layerId); + else if (!layer) + throw exception("Opening layer #{} prior to creation or after destruction", layerId); + + Parcel parcel(state); + // Flat Binder with the layer's IGraphicBufferProducer + // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:bionic/libc/kernel/uapi/linux/binder.h;l=47-57 + parcel.Push(0x2); // Type of the IBinder + parcel.Push(0); // Flags + parcel.Push(DefaultBinderLayerHandle); // Handle + parcel.Push(0); // Cookie + // Unknown HOS-specific layer properties + parcel.Push(util::MakeMagic("dispdrv\0")); + parcel.Push({}); // Unknown + + parcel.PushObject(0); // Offset of flattened IBinder relative to Parcel data + + layerWeakReferenceCount++; // IBinder represents a weak reference to the layer + + return parcel; + } + + void IHOSBinderDriver::CloseLayer(u64 layerId) { + if (layerId != DefaultLayerId) + throw exception("Closing non-existent layer #{}", layerId); + else if (layerWeakReferenceCount == 0) + throw exception("Closing layer #{} which has no weak references to it", layerId); + + if (--layerWeakReferenceCount == 0 && layerStrongReferenceCount < 1) + layer.reset(); + } + + void IHOSBinderDriver::DestroyLayer(u64 layerId) { + if (layerId != DefaultLayerId) + throw exception("Destroying non-existent layer #{}", layerId); + else if (layer) + throw exception("Destroying layer #{} which hasn't been closed: Weak References: {}, Strong References: {}", layerWeakReferenceCount, layerStrongReferenceCount); + } } diff --git a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h index b28ef62b..af423490 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h +++ b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h @@ -3,17 +3,46 @@ #pragma once -#include +#include +#include "GraphicBufferProducer.h" namespace skyline::service::hosbinder { - class GraphicBufferProducer; + /** + * @brief A display identifier specific to HOS, translated to a corresponding Android display internally + * @url https://switchbrew.org/wiki/Display_services#DisplayName + */ + enum class DisplayId : u64 { + Default, //!< Automatically determines the default display + External, //!< Refers to an external display, if any + Edid, //!< Refers to an external display with EDID capabilities + Internal, //!< Refers to the internal display on the Switch + Null, //!< A placeholder display which doesn't refer to any display + }; + + ENUM_STRING(DisplayId, { + ENUM_CASE(Default); + ENUM_CASE(External); + ENUM_CASE(Edid); + ENUM_CASE(Internal); + ENUM_CASE(Null); + }) /** * @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is a translation layer between Android Binder IPC and HOS IPC to communicate with the Android display stack */ class IHOSBinderDriver : public BaseService { private: - std::shared_ptr producer; + DisplayId displayId{DisplayId::Null}; //!< The ID of the display that the layer is connected to + constexpr static u64 DefaultLayerId{1}; //!< The VI ID of the default (and only) layer in our surface stack + constexpr static u32 DefaultBinderLayerHandle{1}; //!< The handle as assigned by SurfaceFlinger of the default layer + constexpr static i32 InitialStrongReferenceCount{std::numeric_limits::min()}; //!< Initial value for the strong reference count, weak references will keep the object alive till the strong reference count is first mutated + i32 layerStrongReferenceCount; //!< The amount of strong references to the layer object + i32 layerWeakReferenceCount; //!< The amount of weak references to the layer object + std::optional layer; //!< The IGraphicBufferProducer backing the layer (NativeWindow) + + void AddWeakLayerReference(u32 count = 1) { + + } public: IHOSBinderDriver(const DeviceState &state, ServiceManager &manager); @@ -25,7 +54,7 @@ namespace skyline::service::hosbinder { Result TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** - * @brief Adjusts the reference counts to the underlying binder, it's stubbed as we aren't using the real symbols + * @brief Adjusts the reference counts to the underlying Android reference counted object * @url https://switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount */ Result AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); @@ -36,6 +65,38 @@ namespace skyline::service::hosbinder { */ Result GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @note This will throw an exception if another display was opened and not closed + */ + DisplayId OpenDisplay(std::string_view name); + + /** + * @note This **must** be called prior to opening a different Display + */ + void CloseDisplay(DisplayId id); + + /** + * @return An ID that can be utilized to refer to the layer + * @note This will throw an exception if the specified display has not been opened + */ + u64 CreateLayer(DisplayId displayId); + + /** + * @return A parcel with a flattened IBinder to the IGraphicBufferProducer of the layer + * @note This will throw an exception if the specified display has not been opened + */ + Parcel OpenLayer(DisplayId displayId, u64 layerId); + + /** + * @note This **must** be called prior to destroying the layer + */ + void CloseLayer(u64 layerId); + + /** + * @note This **must** be called prior to opening a different Display + */ + void DestroyLayer(u64 layerId); + SERVICE_DECL( SFUNC(0x0, IHOSBinderDriver, TransactParcel), SFUNC(0x1, IHOSBinderDriver, AdjustRefcount), diff --git a/app/src/main/cpp/skyline/services/common/parcel.cpp b/app/src/main/cpp/skyline/services/hosbinder/parcel.cpp similarity index 97% rename from app/src/main/cpp/skyline/services/common/parcel.cpp rename to app/src/main/cpp/skyline/services/hosbinder/parcel.cpp index 15c71484..fcc7b108 100644 --- a/app/src/main/cpp/skyline/services/common/parcel.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/parcel.cpp @@ -3,7 +3,7 @@ #include "parcel.h" -namespace skyline::service { +namespace skyline::service::hosbinder { Parcel::Parcel(span buffer, const DeviceState &state, bool hasToken) : state(state) { header = buffer.as(); diff --git a/app/src/main/cpp/skyline/services/common/parcel.h b/app/src/main/cpp/skyline/services/hosbinder/parcel.h similarity index 99% rename from app/src/main/cpp/skyline/services/common/parcel.h rename to app/src/main/cpp/skyline/services/hosbinder/parcel.h index a6615100..09dce4da 100644 --- a/app/src/main/cpp/skyline/services/common/parcel.h +++ b/app/src/main/cpp/skyline/services/hosbinder/parcel.h @@ -5,7 +5,7 @@ #include -namespace skyline::service { +namespace skyline::service::hosbinder { /** * @brief This allows easy access and efficient serialization of an Android Parcel object * @url https://switchbrew.org/wiki/Display_services#Parcel diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index 8b955941..2a848cfe 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -18,6 +18,9 @@ #include "services/timesrv/core.h" #include "fssrv/IFileSystemProxy.h" #include "services/nvdrv/INvDrvServices.h" +#include "hosbinder/IHOSBinderDriver.h" +#include "visrv/IApplicationRootService.h" +#include "visrv/ISystemRootService.h" #include "visrv/IManagerRootService.h" #include "pl/IPlatformServiceManager.h" #include "aocsrv/IAddOnContentManager.h" @@ -35,7 +38,7 @@ #define SERVICE_CASE(class, name, ...) \ case util::MakeMagic(name): { \ - std::shared_ptr serviceObject = std::make_shared(state, *this __VA_OPT__(,) __VA_ARGS__); \ + std::shared_ptr serviceObject{std::make_shared(state, *this, ##__VA_ARGS__)}; \ serviceMap[util::MakeMagic(name)] = serviceObject; \ return serviceObject; \ } @@ -49,7 +52,7 @@ namespace skyline::service { ServiceManager::ServiceManager(const DeviceState &state) : state(state), smUserInterface(std::make_shared(state, *this)), globalServiceState(std::make_shared(state)) {} - std::shared_ptr ServiceManager::CreateService(ServiceName name) { + std::shared_ptr ServiceManager::CreateOrGetService(ServiceName name) { auto serviceIter{serviceMap.find(name)}; if (serviceIter != serviceMap.end()) return (*serviceIter).second; @@ -74,9 +77,10 @@ namespace skyline::service { SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:a") SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:s") SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:t") + SERVICE_CASE(hosbinder::IHOSBinderDriver, "dispdrv") + SERVICE_CASE(visrv::IApplicationRootService, "vi:u") + SERVICE_CASE(visrv::ISystemRootService, "vi:s") SERVICE_CASE(visrv::IManagerRootService, "vi:m") - SERVICE_CASE(visrv::IManagerRootService, "vi:u") - SERVICE_CASE(visrv::IManagerRootService, "vi:s") SERVICE_CASE(pl::IPlatformServiceManager, "pl:u") SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u") SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl") @@ -100,7 +104,7 @@ namespace skyline::service { std::shared_ptr ServiceManager::NewService(ServiceName name, type::KSession &session, ipc::IpcResponse &response) { std::lock_guard serviceGuard(mutex); - auto serviceObject{CreateService(name)}; + auto serviceObject{CreateOrGetService(name)}; KHandle handle{}; if (session.isDomain) { session.domains.push_back(serviceObject); diff --git a/app/src/main/cpp/skyline/services/serviceman.h b/app/src/main/cpp/skyline/services/serviceman.h index f6e74c54..0690b0a9 100644 --- a/app/src/main/cpp/skyline/services/serviceman.h +++ b/app/src/main/cpp/skyline/services/serviceman.h @@ -21,13 +21,6 @@ namespace skyline::service { std::unordered_map> serviceMap; //!< A mapping from a Service to the underlying object std::mutex mutex; //!< Synchronizes concurrent access to services to prevent crashes - /** - * @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance - * @param name The name of the service to create - * @return A shared pointer to an instance of the service - */ - std::shared_ptr CreateService(ServiceName name); - public: std::shared_ptr smUserInterface; //!< Used by applications to open connections to services std::shared_ptr globalServiceState; @@ -58,19 +51,13 @@ namespace skyline::service { } /** - * @param serviceType The type of the service - * @tparam The class of the service - * @return A shared pointer to an instance of the service - * @note This only works for services created with `NewService` as sub-interfaces used with `RegisterService` can have multiple instances + * @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance */ - template - std::shared_ptr GetService(ServiceName name) { - return std::static_pointer_cast(serviceMap.at(name)); - } + std::shared_ptr CreateOrGetService(ServiceName name); template - constexpr std::shared_ptr GetService(std::string_view name) { - return GetService(util::MakeMagic(name)); + constexpr std::shared_ptr CreateOrGetService(std::string_view name) { + return std::static_pointer_cast(CreateOrGetService(util::MakeMagic(name))); } /** diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp index 4a7a9ab2..86562a74 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp @@ -3,101 +3,85 @@ #include #include +#include #include -#include #include "IApplicationDisplayService.h" #include "ISystemDisplayService.h" #include "IManagerDisplayService.h" +#include "results.h" namespace skyline::service::visrv { - IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {} + IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level) : level(level), IDisplayService(state, manager) {} Result IApplicationDisplayService::GetRelayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response); + manager.RegisterService(hosbinder, session, response); return {}; } Result IApplicationDisplayService::GetIndirectDisplayTransactionService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response); + if (level < PrivilegeLevel::System) + return result::IllegalOperation; + manager.RegisterService(hosbinder, session, response); return {}; } Result IApplicationDisplayService::GetSystemDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (level < PrivilegeLevel::System) + return result::IllegalOperation; manager.RegisterService(SRVREG(ISystemDisplayService), session, response); return {}; } Result IApplicationDisplayService::GetManagerDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (level < PrivilegeLevel::Manager) + return result::IllegalOperation; manager.RegisterService(SRVREG(IManagerDisplayService), session, response); return {}; } Result IApplicationDisplayService::OpenDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - std::string displayName(request.PopString()); - state.logger->Debug("Setting display as: {}", displayName); - - auto producer{hosbinder::producer.lock()}; - producer->SetDisplay(displayName); - - response.Push(0); // There's only one display + auto displayName(request.PopString()); + state.logger->Debug("Opening display: {}", displayName); + response.Push(hosbinder->OpenDisplay(displayName)); return {}; } Result IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - state.logger->Debug("Closing the display"); - auto producer{hosbinder::producer.lock()}; - producer->CloseDisplay(); + auto displayId{request.Pop()}; + state.logger->Debug("Closing display: {}", hosbinder::ToString(displayId)); + hosbinder->CloseDisplay(displayId); return {}; } Result IApplicationDisplayService::OpenLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - struct InputStruct { - char displayName[0x40]; - u64 layerId; - u64 userId; - } input = request.Pop(); - state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input.displayName, input.layerId, input.userId); - - std::string name(input.displayName); - - Parcel parcel(state); - LayerParcel data{ - .type = 0x2, - .pid = 0, - .bufferId = 0, // As we only have one layer and buffer - .string = "dispdrv" - }; - parcel.Push(data); - parcel.objects.resize(4); + auto displayName{request.PopString(0x40)}; + auto layerId{request.Pop()}; + state.logger->Debug("Opening layer #{} on display: {}", layerId, displayName); + auto displayId{hosbinder->OpenDisplay(displayName)}; + auto parcel{hosbinder->OpenLayer(displayId, layerId)}; response.Push(parcel.WriteParcel(request.outputBuf.at(0))); + return {}; } Result IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { u64 layerId{request.Pop()}; - state.logger->Debug("Closing Layer: {}", layerId); - - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized) - state.logger->Warn("The application is destroying an uninitialized layer"); - producer->layerStatus = hosbinder::LayerStatus::Uninitialized; - + state.logger->Debug("Closing layer #{}", layerId); + hosbinder->CloseLayer(layerId); return {}; } Result IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto scalingMode{request.Pop()}; auto layerId{request.Pop()}; - state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId); return {}; } Result IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { KHandle handle{state.process->InsertItem(state.gpu->presentation.vsyncEvent)}; - state.logger->Debug("VSync Event Handle: 0x{:X}", handle); - + state.logger->Debug("V-Sync Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); return {}; } diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h index a6313a41..da567c8e 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h @@ -4,6 +4,7 @@ #pragma once #include "IDisplayService.h" +#include "IRootService.h" namespace skyline::service::visrv { /** @@ -11,8 +12,11 @@ namespace skyline::service::visrv { * @url https://switchbrew.org/wiki/Display_services#IApplicationDisplayService */ class IApplicationDisplayService : public IDisplayService { + private: + PrivilegeLevel level; + public: - IApplicationDisplayService(const DeviceState &state, ServiceManager &manager); + IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level); /** * @brief Returns an handle to the 'nvnflinger' service @@ -74,19 +78,19 @@ namespace skyline::service::visrv { */ Result GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - SERVICE_DECL( - SFUNC(0x64, IApplicationDisplayService, GetRelayService), - SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService), - SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService), - SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService), - SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay), - SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay), - SFUNC(0x7E4, IApplicationDisplayService, OpenLayer), - SFUNC(0x7E5, IApplicationDisplayService, CloseLayer), - SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer), - SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer), - SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode), - SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent) - ) + SERVICE_DECL( + SFUNC(0x64, IApplicationDisplayService, GetRelayService), + SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService), + SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService), + SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService), + SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay), + SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay), + SFUNC(0x7E4, IApplicationDisplayService, OpenLayer), + SFUNC(0x7E5, IApplicationDisplayService, CloseLayer), + SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer), + SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer), + SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode), + SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent) + ) }; } diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h b/app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h new file mode 100644 index 00000000..d4ee4b25 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include "IRootService.h" + +namespace skyline::service::visrv { + /** + * @url https://switchbrew.org/wiki/Display_services#vi:u + */ + class IApplicationRootService : public IRootService { + public: + IApplicationRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Application) {} + + SERVICE_DECL( + SFUNC_BASE(0x0, IApplicationRootService, IRootService, GetDisplayService) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp index 6d6b0e31..0873f0e1 100644 --- a/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp @@ -1,46 +1,33 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include +#include +#include #include "IDisplayService.h" namespace skyline::service::visrv { - IDisplayService::IDisplayService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} + IDisplayService::IDisplayService(const DeviceState &state, ServiceManager &manager) : hosbinder(manager.CreateOrGetService("dispdrv")), BaseService(state, manager) {} Result IDisplayService::CreateStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - request.Skip(); - auto displayId{request.Pop()}; + request.Skip(); // VI Layer flags + auto displayId{request.Pop()}; - state.logger->Debug("Creating Stray Layer on Display: {}", displayId); + auto layerId{hosbinder->CreateLayer(displayId)}; + response.Push(layerId); - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Stray) - throw exception("The application is creating more than one stray layer"); - producer->layerStatus = hosbinder::LayerStatus::Stray; - - response.Push(0); // There's only one layer - - Parcel parcel(state); - LayerParcel data{ - .type = 0x2, - .pid = 0, - .bufferId = 0, // As we only have one layer and buffer - .string = "dispdrv" - }; - parcel.Push(data); + state.logger->Debug("Creating Stray Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId)); + auto parcel{hosbinder->OpenLayer(displayId, layerId)}; response.Push(parcel.WriteParcel(request.outputBuf.at(0))); + return {}; } Result IDisplayService::DestroyStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto layerId{request.Pop()}; - state.logger->Debug("Destroying Stray Layer: {}", layerId); + state.logger->Debug("Destroying Stray Layer #{}", layerId); - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized) - state.logger->Warn("The application is destroying an uninitialized layer"); - producer->layerStatus = hosbinder::LayerStatus::Uninitialized; + hosbinder->CloseLayer(layerId); return {}; } diff --git a/app/src/main/cpp/skyline/services/visrv/IDisplayService.h b/app/src/main/cpp/skyline/services/visrv/IDisplayService.h index c16856dd..608bbfe6 100644 --- a/app/src/main/cpp/skyline/services/visrv/IDisplayService.h +++ b/app/src/main/cpp/skyline/services/visrv/IDisplayService.h @@ -3,7 +3,11 @@ #pragma once -#include +#include + +namespace skyline::service::hosbinder { + class IHOSBinderDriver; +} namespace skyline::service::visrv { /** @@ -11,18 +15,7 @@ namespace skyline::service::visrv { */ class IDisplayService : public BaseService { protected: - /** - * @brief This is the parcel used in OpenLayer/CreateStrayLayer - */ - struct LayerParcel { - u32 type; //!< The type of the layer - u32 pid; //!< The PID that the layer belongs to - u32 bufferId; //!< The buffer ID of the layer - u32 _pad0_[3]; - u8 string[0x8]; //!< "dispdrv" - u64 _pad1_; - }; - static_assert(sizeof(LayerParcel) == 0x28); + std::shared_ptr hosbinder; //!< The IHOSBinder relayed via this display class public: IDisplayService(const DeviceState &state, ServiceManager &manager); diff --git a/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp index 15e6a0c2..0d47787d 100644 --- a/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp @@ -1,35 +1,27 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include +#include #include "IManagerDisplayService.h" namespace skyline::service::visrv { IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {} Result IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - request.Skip(); - auto displayId{request.Pop()}; - state.logger->Debug("Creating Managed Layer on Display: {}", displayId); + request.Skip(); // VI Layer flags + auto displayId{request.Pop()}; - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized) - throw exception("The application is creating more than one layer"); - producer->layerStatus = hosbinder::LayerStatus::Managed; + auto layerId{hosbinder->CreateLayer(displayId)}; + state.logger->Debug("Creating Managed Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId)); + response.Push(layerId); - response.Push(0); // There's only one layer return {}; } Result IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto layerId{request.Pop()}; - state.logger->Debug("Destroying Managed Layer: {}", layerId); - - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized) - state.logger->Warn("The application is destroying an uninitialized layer"); - producer->layerStatus = hosbinder::LayerStatus::Uninitialized; - + state.logger->Debug("Destroying Managed Layer #{}", layerId); + hosbinder->DestroyLayer(layerId); return {}; } diff --git a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp b/app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp deleted file mode 100644 index 54cd4ffa..00000000 --- a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#include "IManagerRootService.h" -#include "IApplicationDisplayService.h" - -namespace skyline::service::visrv { - IManagerRootService::IManagerRootService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} - - Result IManagerRootService::GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(IApplicationDisplayService), session, response); - return {}; - } -} diff --git a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h b/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h index a4e6f432..482f8d45 100644 --- a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h +++ b/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h @@ -3,26 +3,18 @@ #pragma once -#include -#include +#include "IRootService.h" namespace skyline::service::visrv { /** - * @brief This service is used to get an handle to #IApplicationDisplayService * @url https://switchbrew.org/wiki/Display_services#vi:m */ - class IManagerRootService : public BaseService { + class IManagerRootService : public IRootService { public: - IManagerRootService(const DeviceState &state, ServiceManager &manager); + IManagerRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Manager) {} - /** - * @brief Returns an handle to #IApplicationDisplayService - * @url https://switchbrew.org/wiki/Display_services#GetDisplayService - */ - Result GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - - SERVICE_DECL( - SFUNC(0x2, IManagerRootService, GetDisplayService) - ) + SERVICE_DECL( + SFUNC_BASE(0x2, IManagerRootService, IRootService, GetDisplayService) + ) }; } diff --git a/app/src/main/cpp/skyline/services/visrv/IRootService.cpp b/app/src/main/cpp/skyline/services/visrv/IRootService.cpp new file mode 100644 index 00000000..3289f780 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/IRootService.cpp @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include "IRootService.h" +#include "IApplicationDisplayService.h" +#include "results.h" + +namespace skyline::service::visrv { + IRootService::IRootService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level) : level(level), BaseService(state, manager) {} + + Result IRootService::GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto requestedPrivileges{request.Pop()}; //!< A boolean indicating if the returned service should have higher privileges or not + if (requestedPrivileges && level < PrivilegeLevel::System) + return result::IllegalOperation; + manager.RegisterService(SRVREG(IApplicationDisplayService, level), session, response); + return {}; + } +} diff --git a/app/src/main/cpp/skyline/services/visrv/IRootService.h b/app/src/main/cpp/skyline/services/visrv/IRootService.h new file mode 100644 index 00000000..51d3e9b9 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/IRootService.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::visrv { + /** + * @brief All privilege-based variants that a single service can have + */ + enum class PrivilegeLevel { + Application, //!< The service used by user applications (Lowest) + System, //!< The service used by system applications (Higher) + Manager, //!< The service used by system services internally (Highest) + }; + + /** + * @brief Manages allocation of VI to display services + * @url https://switchbrew.org/wiki/Display_services#vi:u + * @url https://switchbrew.org/wiki/Display_services#vi:s + * @url https://switchbrew.org/wiki/Display_services#vi:m + */ + class IRootService : public BaseService { + private: + PrivilegeLevel level; + + public: + IRootService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level); + + /** + * @brief Returns an handle to #IApplicationDisplayService + * @url https://switchbrew.org/wiki/Display_services#GetDisplayService + */ + Result GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; +} diff --git a/app/src/main/cpp/skyline/services/visrv/ISystemRootService.h b/app/src/main/cpp/skyline/services/visrv/ISystemRootService.h new file mode 100644 index 00000000..08a8aa68 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/ISystemRootService.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include "IRootService.h" + +namespace skyline::service::visrv { + /** + * @url https://switchbrew.org/wiki/Display_services#vi:s + */ + class ISystemRootService : public IRootService { + public: + ISystemRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::System) {} + + SERVICE_DECL( + SFUNC_BASE(0x3, ISystemRootService, IRootService, GetDisplayService) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/visrv/results.h b/app/src/main/cpp/skyline/services/visrv/results.h new file mode 100644 index 00000000..9dcd28fd --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/results.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::visrv::result { + constexpr Result IllegalOperation(114, 6); +}