From 0e93a510307c1e50a8916fadcc3f52015a6d4cc2 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Tue, 10 Sep 2019 11:55:28 +0200 Subject: [PATCH] bcat:u: Implement EnumerateDeliveryCacheDirectory (#768) * bcat:u: Implement EnumerateDeliveryCacheDirectory Basic implementation `EnumerateDeliveryCacheDirectory` call to `IDeliveryCacheStorageService` according to RE. (close #622) I've added some comments in the whole service for when we'll implement a real bcat implementation. For now, all games who use it isn't playable because of GPU. * Use Array instead of List * Add ApplicationLaunchPropertyHelper * Fix helper * Fix helper 2 * Fix ApplicationLaunchProperty Default * Fix ApplicationLaunchProperty 2 * Fix folder --- .../HOS/Services/Acc/IAccountService.cs | 18 ++------ .../Services/Acc/IManagerForApplication.cs | 2 +- .../Services/Arp/ApplicationLaunchProperty.cs | 11 ----- Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs | 4 +- .../Bcat/IDeliveryCacheStorageService.cs | 42 +++++++++++++++++- .../HOS/Services/Bcat/IServiceCreator.cs | 24 +++++++++-- Ryujinx.HLE/HOS/Services/Bcat/ResultCode.cs | 14 ++++++ .../Glue/ApplicationLaunchProperty.cs | 43 +++++++++++++++++++ 8 files changed, 125 insertions(+), 33 deletions(-) delete mode 100644 Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bcat/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs diff --git a/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs b/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs index 4bda472eb..23f3eec79 100644 --- a/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs +++ b/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Arp; +using Ryujinx.HLE.HOS.Services.Glue; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Utilities; using System; @@ -173,26 +173,14 @@ namespace Ryujinx.HLE.HOS.Services.Acc /* if (nn::arp::detail::IReader::GetApplicationLaunchProperty() == 0xCC9D) // InvalidProcessId { - _applicationLaunchProperty = new ApplicationLaunchProperty - { - TitleId = 0x00; - Version = 0x00; - BaseGameStorageId = 0x03; - UpdateGameStorageId = 0x00; - } + _applicationLaunchProperty = ApplicationLaunchProperty.Default; return ResultCode.InvalidArgument; } else */ { - _applicationLaunchProperty = new ApplicationLaunchProperty - { - TitleId = BitConverter.ToInt64(StringUtils.HexToBytes(context.Device.System.TitleID), 0), - Version = 0x00, - BaseGameStorageId = (byte)StorageId.NandSystem, - UpdateGameStorageId = (byte)StorageId.None - }; + _applicationLaunchProperty = ApplicationLaunchProperty.GetByPid(context); } Logger.PrintStub(LogClass.ServiceAcc, new { unknown }); diff --git a/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs b/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs index 02cafd250..8fb901c5b 100644 --- a/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs +++ b/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs @@ -1,5 +1,5 @@ using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Arp; +using Ryujinx.HLE.HOS.Services.Glue; using Ryujinx.HLE.Utilities; namespace Ryujinx.HLE.HOS.Services.Acc diff --git a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs deleted file mode 100644 index 16ffea0b8..000000000 --- a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Arp -{ - class ApplicationLaunchProperty - { - public long TitleId; - public int Version; - public byte BaseGameStorageId; - public byte UpdateGameStorageId; - public short Padding; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs b/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs index 6fdcba46c..030f9110b 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs @@ -1,7 +1,9 @@ +using Ryujinx.HLE.HOS.Services.Glue; + namespace Ryujinx.HLE.HOS.Services.Bcat { class IBcatService : IpcService { - public IBcatService() { } + public IBcatService(ApplicationLaunchProperty applicationLaunchProperty) { } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs index 5e3db998b..1c9aed118 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs @@ -1,7 +1,47 @@ +using Ryujinx.HLE.HOS.Services.Glue; +using System; +using System.Text; + namespace Ryujinx.HLE.HOS.Services.Bcat { class IDeliveryCacheStorageService : IpcService { - public IDeliveryCacheStorageService() { } + private const int DeliveryCacheDirectoriesLimit = 100; + private const int DeliveryCacheDirectoryNameLength = 32; + + private string[] _deliveryCacheDirectories = new string[0]; + + public IDeliveryCacheStorageService(ServiceCtx context, ApplicationLaunchProperty applicationLaunchProperty) + { + // TODO: Read directories.meta file from the save data (loaded in IServiceCreator) in _deliveryCacheDirectories. + } + + [Command(10)] + // EnumerateDeliveryCacheDirectory() -> (u32, buffer) + public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context) + { + long outputPosition = context.Request.ReceiveBuff[0].Position; + long outputSize = context.Request.ReceiveBuff[0].Size; + + for (int index = 0; index < _deliveryCacheDirectories.Length; index++) + { + if (index == DeliveryCacheDirectoriesLimit - 1) + { + break; + } + + byte[] directoryNameBuffer = Encoding.ASCII.GetBytes(_deliveryCacheDirectories[index]); + + Array.Resize(ref directoryNameBuffer, DeliveryCacheDirectoryNameLength); + + directoryNameBuffer[DeliveryCacheDirectoryNameLength - 1] = 0x00; + + context.Memory.WriteBytes(outputPosition + index * DeliveryCacheDirectoryNameLength, directoryNameBuffer); + } + + context.ResponseData.Write(_deliveryCacheDirectories.Length); + + return ResultCode.Success; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs index e2a3b3522..4e9d36563 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Glue; + namespace Ryujinx.HLE.HOS.Services.Bcat { [Service("bcat:a")] @@ -12,9 +14,16 @@ namespace Ryujinx.HLE.HOS.Services.Bcat // CreateBcatService(u64, pid) -> object public ResultCode CreateBcatService(ServiceCtx context) { - long id = context.RequestData.ReadInt64(); + // TODO: Call arp:r GetApplicationLaunchProperty with the pid to get the TitleId. + // Add an instance of nn::bcat::detail::service::core::PassphraseManager. + // Add an instance of nn::bcat::detail::service::ServiceMemoryManager. + // Add an instance of nn::bcat::detail::service::core::TaskManager who load "bcat-sys:/" system save data and open "dc/task.bin". + // If the file don't exist, create a new one (size of 0x800) and write 2 empty struct with a size of 0x400. - MakeObject(context, new IBcatService()); + MakeObject(context, new IBcatService(ApplicationLaunchProperty.GetByPid(context))); + + // NOTE: If the IBcatService is null this error is returned, Doesn't occur in our case. + // return ResultCode.NullObject; return ResultCode.Success; } @@ -23,9 +32,16 @@ namespace Ryujinx.HLE.HOS.Services.Bcat // CreateDeliveryCacheStorageService(u64, pid) -> object public ResultCode CreateDeliveryCacheStorageService(ServiceCtx context) { - long id = context.RequestData.ReadInt64(); + // TODO: Call arp:r GetApplicationLaunchProperty with the pid to get the TitleId. + // Add an instance of nn::bcat::detail::service::core::ApplicationStorageManager who load "bcat-dc-X:/" system save data, + // return ResultCode.NullSaveData if failed. + // Where X depend of the ApplicationLaunchProperty stored in an array (range 0-3). + // Add an instance of nn::bcat::detail::service::ServiceMemoryManager. - MakeObject(context, new IDeliveryCacheStorageService()); + MakeObject(context, new IDeliveryCacheStorageService(context, ApplicationLaunchProperty.GetByPid(context))); + + // NOTE: If the IDeliveryCacheStorageService is null this error is returned, Doesn't occur in our case. + // return ResultCode.NullObject; return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Bcat/ResultCode.cs new file mode 100644 index 000000000..bc13d9dd4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bcat/ResultCode.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Services.Bcat +{ + enum ResultCode + { + ModuleId = 122, + ErrorCodeShift = 9, + + Success = 0, + + NullArgument = (2 << ErrorCodeShift) | ModuleId, + NullSaveData = (31 << ErrorCodeShift) | ModuleId, + NullObject = (91 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs b/Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs new file mode 100644 index 000000000..b96f0d054 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs @@ -0,0 +1,43 @@ +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.Utilities; +using System; + +namespace Ryujinx.HLE.HOS.Services.Glue +{ + class ApplicationLaunchProperty + { + public long TitleId; + public int Version; + public byte BaseGameStorageId; + public byte UpdateGameStorageId; + public short Padding; + + public static ApplicationLaunchProperty Default + { + get + { + return new ApplicationLaunchProperty + { + TitleId = 0x00, + Version = 0x00, + BaseGameStorageId = (byte)StorageId.NandSystem, + UpdateGameStorageId = (byte)StorageId.None + }; + } + } + + public static ApplicationLaunchProperty GetByPid(ServiceCtx context) + { + // TODO: Handle ApplicationLaunchProperty as array when pid will be supported and return the right item. + // For now we can hardcode values, and fix it after GetApplicationLaunchProperty is implemented. + + return new ApplicationLaunchProperty + { + TitleId = BitConverter.ToInt64(StringUtils.HexToBytes(context.Device.System.TitleID), 0), + Version = 0x00, + BaseGameStorageId = (byte)StorageId.NandSystem, + UpdateGameStorageId = (byte)StorageId.None + }; + } + } +} \ No newline at end of file