diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Horizon/Sm | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Horizon/Sm')
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs | 20 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs | 185 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/Ipc/ManagerService.cs | 8 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/Ipc/UserService.cs | 66 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/SmMain.cs | 34 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/SmResult.cs | 19 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/SmServerManager.cs | 30 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon/Sm/Types/SmPortIndex.cs | 8 |
8 files changed, 370 insertions, 0 deletions
diff --git a/src/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs b/src/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs new file mode 100644 index 00000000..50c18a2c --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs @@ -0,0 +1,20 @@ +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Sm.Impl +{ + struct ServiceInfo + { + public ServiceName Name; + public ulong OwnerProcessId; + public int PortHandle; + + public void Free() + { + HorizonStatic.Syscall.CloseHandle(PortHandle); + + Name = ServiceName.Invalid; + OwnerProcessId = 0L; + PortHandle = 0; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs b/src/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs new file mode 100644 index 00000000..d1f94267 --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs @@ -0,0 +1,185 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Sm.Impl +{ + class ServiceManager + { + private const int MaxServicesCount = 256; + + private readonly ServiceInfo[] _services; + + public ServiceManager() + { + _services = new ServiceInfo[MaxServicesCount]; + } + + public Result GetService(out int handle, ulong processId, ServiceName name) + { + handle = 0; + Result result = ValidateServiceName(name); + + if (result.IsFailure) + { + return result; + } + + // TODO: Validation with GetProcessInfo etc. + + int serviceIndex = GetServiceInfo(name); + + if (serviceIndex < 0) + { + return SfResult.RequestDeferredByUser; + } + + result = GetServiceImpl(out handle, ref _services[serviceIndex]); + + return result == KernelResult.SessionCountExceeded ? SmResult.OutOfSessions : result; + } + + private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo) + { + return HorizonStatic.Syscall.ConnectToPort(out handle, serviceInfo.PortHandle); + } + + public Result RegisterService(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight) + { + handle = 0; + Result result = ValidateServiceName(name); + + if (result.IsFailure) + { + return result; + } + + // TODO: Validation with GetProcessInfo etc. + return HasServiceInfo(name) ? SmResult.AlreadyRegistered : RegisterServiceImpl(out handle, processId, name, maxSessions, isLight); + } + + public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions) + { + return RegisterServiceImpl(out handle, Os.GetCurrentProcessId(), name, maxSessions, false); + } + + private Result RegisterServiceImpl(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight) + { + handle = 0; + + Result result = ValidateServiceName(name); + + if (!result.IsSuccess) + { + return result; + } + + if (HasServiceInfo(name)) + { + return SmResult.AlreadyRegistered; + } + + int freeServiceIndex = GetFreeService(); + + if (freeServiceIndex < 0) + { + return SmResult.OutOfServices; + } + + ref ServiceInfo freeService = ref _services[freeServiceIndex]; + + result = HorizonStatic.Syscall.CreatePort(out handle, out int clientPort, maxSessions, isLight, null); + + if (!result.IsSuccess) + { + return result; + } + + freeService.PortHandle = clientPort; + freeService.Name = name; + freeService.OwnerProcessId = processId; + + return Result.Success; + } + + public Result UnregisterService(ulong processId, ServiceName name) + { + Result result = ValidateServiceName(name); + + if (result.IsFailure) + { + return result; + } + + // TODO: Validation with GetProcessInfo etc. + + int serviceIndex = GetServiceInfo(name); + if (serviceIndex < 0) + { + return SmResult.NotRegistered; + } + + ref var serviceInfo = ref _services[serviceIndex]; + if (serviceInfo.OwnerProcessId != processId) + { + return SmResult.NotAllowed; + } + + serviceInfo.Free(); + + return Result.Success; + } + + private static Result ValidateServiceName(ServiceName name) + { + if (name[0] == 0) + { + return SmResult.InvalidServiceName; + } + + int nameLength = 1; + + for (; nameLength < name.Length; nameLength++) + { + if (name[nameLength] == 0) + { + break; + } + } + + while (nameLength < name.Length) + { + if (name[nameLength++] != 0) + { + return SmResult.InvalidServiceName; + } + } + + return Result.Success; + } + + private bool HasServiceInfo(ServiceName name) + { + return GetServiceInfo(name) != -1; + } + + private int GetFreeService() + { + return GetServiceInfo(ServiceName.Invalid); + } + + private int GetServiceInfo(ServiceName name) + { + for (int index = 0; index < MaxServicesCount; index++) + { + if (_services[index].Name == name) + { + return index; + } + } + + return -1; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Horizon/Sm/Ipc/ManagerService.cs b/src/Ryujinx.Horizon/Sm/Ipc/ManagerService.cs new file mode 100644 index 00000000..c7dcddc9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/Ipc/ManagerService.cs @@ -0,0 +1,8 @@ +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Sm.Ipc +{ + partial class ManagerService : IManagerService + { + } +} diff --git a/src/Ryujinx.Horizon/Sm/Ipc/UserService.cs b/src/Ryujinx.Horizon/Sm/Ipc/UserService.cs new file mode 100644 index 00000000..d093913a --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/Ipc/UserService.cs @@ -0,0 +1,66 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sm; +using Ryujinx.Horizon.Sm.Impl; + +namespace Ryujinx.Horizon.Sm.Ipc +{ + partial class UserService : IUserService + { + private readonly ServiceManager _serviceManager; + + private ulong _clientProcessId; + private bool _initialized; + + public UserService(ServiceManager serviceManager) + { + _serviceManager = serviceManager; + } + + [CmifCommand(0)] + public Result Initialize([ClientProcessId] ulong clientProcessId) + { + _clientProcessId = clientProcessId; + _initialized = true; + + return Result.Success; + } + + [CmifCommand(1)] + public Result GetService([MoveHandle] out int handle, ServiceName name) + { + if (!_initialized) + { + handle = 0; + + return SmResult.InvalidClient; + } + + return _serviceManager.GetService(out handle, _clientProcessId, name); + } + + [CmifCommand(2)] + public Result RegisterService([MoveHandle] out int handle, ServiceName name, int maxSessions, bool isLight) + { + if (!_initialized) + { + handle = 0; + + return SmResult.InvalidClient; + } + + return _serviceManager.RegisterService(out handle, _clientProcessId, name, maxSessions, isLight); + } + + [CmifCommand(3)] + public Result UnregisterService(ServiceName name) + { + if (!_initialized) + { + return SmResult.InvalidClient; + } + + return _serviceManager.UnregisterService(_clientProcessId, name); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Horizon/Sm/SmMain.cs b/src/Ryujinx.Horizon/Sm/SmMain.cs new file mode 100644 index 00000000..f0b4d330 --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/SmMain.cs @@ -0,0 +1,34 @@ +using Ryujinx.Horizon.Prepo; +using Ryujinx.Horizon.Prepo.Types; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using Ryujinx.Horizon.Sm.Impl; +using Ryujinx.Horizon.Sm.Types; + +namespace Ryujinx.Horizon.Sm +{ + public class SmMain + { + private const int SmMaxSessionsCount = 64; + private const int SmmMaxSessionsCount = 1; + private const int SmTotalMaxSessionsCount = SmMaxSessionsCount + SmmMaxSessionsCount; + + private const int MaxPortsCount = 2; + + private SmServerManager _serverManager; + + private readonly ServiceManager _serviceManager = new(); + + public void Main() + { + HorizonStatic.Syscall.ManageNamedPort(out int smHandle, "sm:", SmMaxSessionsCount).AbortOnFailure(); + + _serverManager = new SmServerManager(_serviceManager, null, null, MaxPortsCount, ManagerOptions.Default, SmTotalMaxSessionsCount); + + _serverManager.RegisterServer((int)SmPortIndex.User, smHandle); + _serviceManager.RegisterServiceForSelf(out int smmHandle, ServiceName.Encode("sm:m"), SmmMaxSessionsCount).AbortOnFailure(); + _serverManager.RegisterServer((int)SmPortIndex.Manager, smmHandle); + _serverManager.ServiceRequests(); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Horizon/Sm/SmResult.cs b/src/Ryujinx.Horizon/Sm/SmResult.cs new file mode 100644 index 00000000..2d503a4f --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/SmResult.cs @@ -0,0 +1,19 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sm +{ + static class SmResult + { + private const int ModuleId = 21; + + public static Result OutOfProcess => new(ModuleId, 1); + public static Result InvalidClient => new(ModuleId, 2); + public static Result OutOfSessions => new(ModuleId, 3); + public static Result AlreadyRegistered => new(ModuleId, 4); + public static Result OutOfServices => new(ModuleId, 5); + public static Result InvalidServiceName => new(ModuleId, 6); + public static Result NotRegistered => new(ModuleId, 7); + public static Result NotAllowed => new(ModuleId, 8); + public static Result TooLargeAccessControl => new(ModuleId, 9); + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Horizon/Sm/SmServerManager.cs b/src/Ryujinx.Horizon/Sm/SmServerManager.cs new file mode 100644 index 00000000..dc8dc5b6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/SmServerManager.cs @@ -0,0 +1,30 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using Ryujinx.Horizon.Sm.Impl; +using Ryujinx.Horizon.Sm.Ipc; +using Ryujinx.Horizon.Sm.Types; +using System; + +namespace Ryujinx.Horizon.Sm +{ + class SmServerManager : ServerManager + { + private readonly ServiceManager _serviceManager; + + public SmServerManager(ServiceManager serviceManager, HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) + { + _serviceManager = serviceManager; + } + + protected override Result OnNeedsToAccept(int portIndex, Server server) + { + return (SmPortIndex)portIndex switch + { + SmPortIndex.User => AcceptImpl(server, new UserService(_serviceManager)), + SmPortIndex.Manager => AcceptImpl(server, new ManagerService()), + _ => throw new ArgumentOutOfRangeException(nameof(portIndex)), + }; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Horizon/Sm/Types/SmPortIndex.cs b/src/Ryujinx.Horizon/Sm/Types/SmPortIndex.cs new file mode 100644 index 00000000..5325558b --- /dev/null +++ b/src/Ryujinx.Horizon/Sm/Types/SmPortIndex.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sm.Types +{ + enum SmPortIndex + { + User, + Manager + } +}
\ No newline at end of file |
