forked from eden-emu/eden
		
	Merge pull request #3366 from bunnei/swkbd-fixes
applets: Fixes for software keyboard and transfer memory.
This commit is contained in:
		
						commit
						384e069c5c
					
				
					 14 changed files with 208 additions and 102 deletions
				
			
		|  | @ -1863,10 +1863,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto& kernel = system.Kernel(); |     auto& kernel = system.Kernel(); | ||||||
|     auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); |     auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); | ||||||
|  | 
 | ||||||
|  |     if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { | ||||||
|  |         return reserve_result; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |     auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||||||
|     const auto result = handle_table.Create(std::move(transfer_mem_handle)); |     const auto result{handle_table.Create(std::move(transfer_mem_handle))}; | ||||||
|     if (result.Failed()) { |     if (result.Failed()) { | ||||||
|         return result.Code(); |         return result.Code(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -8,15 +8,23 @@ | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
| #include "core/hle/kernel/transfer_memory.h" | #include "core/hle/kernel/transfer_memory.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
|  | #include "core/memory.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} | TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory) | ||||||
| TransferMemory::~TransferMemory() = default; |     : Object{kernel}, memory{memory} {} | ||||||
| 
 | 
 | ||||||
| std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, | TransferMemory::~TransferMemory() { | ||||||
|                                                        u64 size, MemoryPermission permissions) { |     // Release memory region when transfer memory is destroyed
 | ||||||
|     std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; |     Reset(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory, | ||||||
|  |                                                        VAddr base_address, u64 size, | ||||||
|  |                                                        MemoryPermission permissions) { | ||||||
|  |     std::shared_ptr<TransferMemory> transfer_memory{ | ||||||
|  |         std::make_shared<TransferMemory>(kernel, memory)}; | ||||||
| 
 | 
 | ||||||
|     transfer_memory->base_address = base_address; |     transfer_memory->base_address = base_address; | ||||||
|     transfer_memory->memory_size = size; |     transfer_memory->memory_size = size; | ||||||
|  | @ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const u8* TransferMemory::GetPointer() const { | const u8* TransferMemory::GetPointer() const { | ||||||
|     return backing_block.get()->data(); |     return memory.GetPointer(base_address); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u64 TransferMemory::GetSize() const { | u64 TransferMemory::GetSize() const { | ||||||
|  | @ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultCode TransferMemory::Reserve() { | ||||||
|  |     auto& vm_manager{owner_process->VMManager()}; | ||||||
|  |     const auto check_range_result{vm_manager.CheckRangeState( | ||||||
|  |         base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, | ||||||
|  |         MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All, | ||||||
|  |         VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, | ||||||
|  |         MemoryAttribute::IpcAndDeviceMapped)}; | ||||||
|  | 
 | ||||||
|  |     if (check_range_result.Failed()) { | ||||||
|  |         return check_range_result.Code(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto [state_, permissions_, attribute] = *check_range_result; | ||||||
|  | 
 | ||||||
|  |     if (const auto result{vm_manager.ReprotectRange( | ||||||
|  |             base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))}; | ||||||
|  |         result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, | ||||||
|  |                                          attribute | MemoryAttribute::Locked); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode TransferMemory::Reset() { | ||||||
|  |     auto& vm_manager{owner_process->VMManager()}; | ||||||
|  |     if (const auto result{vm_manager.CheckRangeState( | ||||||
|  |             base_address, memory_size, | ||||||
|  |             MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, | ||||||
|  |             MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None, | ||||||
|  |             VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, | ||||||
|  |             MemoryAttribute::IpcAndDeviceMapped)}; | ||||||
|  |         result.Failed()) { | ||||||
|  |         return result.Code(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (const auto result{ | ||||||
|  |             vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)}; | ||||||
|  |         result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, | ||||||
|  |                                          MemoryAttribute::None); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { | ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { | ||||||
|     if (memory_size != size) { |     if (memory_size != size) { | ||||||
|         return ERR_INVALID_SIZE; |         return ERR_INVALID_SIZE; | ||||||
|  |  | ||||||
|  | @ -11,6 +11,10 @@ | ||||||
| 
 | 
 | ||||||
| union ResultCode; | union ResultCode; | ||||||
| 
 | 
 | ||||||
|  | namespace Memory { | ||||||
|  | class Memory; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class KernelCore; | class KernelCore; | ||||||
|  | @ -26,12 +30,13 @@ enum class MemoryPermission : u32; | ||||||
| ///
 | ///
 | ||||||
| class TransferMemory final : public Object { | class TransferMemory final : public Object { | ||||||
| public: | public: | ||||||
|     explicit TransferMemory(KernelCore& kernel); |     explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory); | ||||||
|     ~TransferMemory() override; |     ~TransferMemory() override; | ||||||
| 
 | 
 | ||||||
|     static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; |     static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; | ||||||
| 
 | 
 | ||||||
|     static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, |     static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory, | ||||||
|  |                                                   VAddr base_address, u64 size, | ||||||
|                                                   MemoryPermission permissions); |                                                   MemoryPermission permissions); | ||||||
| 
 | 
 | ||||||
|     TransferMemory(const TransferMemory&) = delete; |     TransferMemory(const TransferMemory&) = delete; | ||||||
|  | @ -80,6 +85,14 @@ public: | ||||||
|     ///
 |     ///
 | ||||||
|     ResultCode UnmapMemory(VAddr address, u64 size); |     ResultCode UnmapMemory(VAddr address, u64 size); | ||||||
| 
 | 
 | ||||||
|  |     /// Reserves the region to be used for the transfer memory, called after the transfer memory is
 | ||||||
|  |     /// created.
 | ||||||
|  |     ResultCode Reserve(); | ||||||
|  | 
 | ||||||
|  |     /// Resets the region previously used for the transfer memory, called after the transfer memory
 | ||||||
|  |     /// is closed.
 | ||||||
|  |     ResultCode Reset(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     /// Memory block backing this instance.
 |     /// Memory block backing this instance.
 | ||||||
|     std::shared_ptr<PhysicalMemory> backing_block; |     std::shared_ptr<PhysicalMemory> backing_block; | ||||||
|  | @ -98,6 +111,8 @@ private: | ||||||
| 
 | 
 | ||||||
|     /// Whether or not this transfer memory instance has mapped memory.
 |     /// Whether or not this transfer memory instance has mapped memory.
 | ||||||
|     bool is_mapped = false; |     bool is_mapped = false; | ||||||
|  | 
 | ||||||
|  |     Memory::Memory& memory; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Kernel
 | } // namespace Kernel
 | ||||||
|  |  | ||||||
|  | @ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const { | ||||||
| 
 | 
 | ||||||
| ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, | ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, | ||||||
|                                          MemoryAttribute attribute) { |                                          MemoryAttribute attribute) { | ||||||
|     constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; |     constexpr auto ignore_mask = | ||||||
|  |         MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked; | ||||||
|     constexpr auto attribute_mask = ~ignore_mask; |     constexpr auto attribute_mask = ~ignore_mask; | ||||||
| 
 | 
 | ||||||
|     const auto result = CheckRangeState( |     const auto result = CheckRangeState( | ||||||
|  |  | ||||||
|  | @ -98,6 +98,8 @@ enum class MemoryAttribute : u32 { | ||||||
|     DeviceMapped = 4, |     DeviceMapped = 4, | ||||||
|     /// Uncached memory
 |     /// Uncached memory
 | ||||||
|     Uncached = 8, |     Uncached = 8, | ||||||
|  | 
 | ||||||
|  |     IpcAndDeviceMapped = LockedForIPC | DeviceMapped, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { | constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { | ||||||
|  | @ -654,6 +656,35 @@ public: | ||||||
|     /// is scheduled.
 |     /// is scheduled.
 | ||||||
|     Common::PageTable page_table{Memory::PAGE_BITS}; |     Common::PageTable page_table{Memory::PAGE_BITS}; | ||||||
| 
 | 
 | ||||||
|  |     using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; | ||||||
|  | 
 | ||||||
|  |     /// Checks if an address range adheres to the specified states provided.
 | ||||||
|  |     ///
 | ||||||
|  |     /// @param address         The starting address of the address range.
 | ||||||
|  |     /// @param size            The size of the address range.
 | ||||||
|  |     /// @param state_mask      The memory state mask.
 | ||||||
|  |     /// @param state           The state to compare the individual VMA states against,
 | ||||||
|  |     ///                        which is done in the form of: (vma.state & state_mask) != state.
 | ||||||
|  |     /// @param permission_mask The memory permissions mask.
 | ||||||
|  |     /// @param permissions     The permission to compare the individual VMA permissions against,
 | ||||||
|  |     ///                        which is done in the form of:
 | ||||||
|  |     ///                        (vma.permission & permission_mask) != permission.
 | ||||||
|  |     /// @param attribute_mask  The memory attribute mask.
 | ||||||
|  |     /// @param attribute       The memory attributes to compare the individual VMA attributes
 | ||||||
|  |     ///                        against, which is done in the form of:
 | ||||||
|  |     ///                        (vma.attributes & attribute_mask) != attribute.
 | ||||||
|  |     /// @param ignore_mask     The memory attributes to ignore during the check.
 | ||||||
|  |     ///
 | ||||||
|  |     /// @returns If successful, returns a tuple containing the memory attributes
 | ||||||
|  |     ///          (with ignored bits specified by ignore_mask unset), memory permissions, and
 | ||||||
|  |     ///          memory state across the memory range.
 | ||||||
|  |     /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
 | ||||||
|  |     ///
 | ||||||
|  |     CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, | ||||||
|  |                                  VMAPermission permission_mask, VMAPermission permissions, | ||||||
|  |                                  MemoryAttribute attribute_mask, MemoryAttribute attribute, | ||||||
|  |                                  MemoryAttribute ignore_mask) const; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     using VMAIter = VMAMap::iterator; |     using VMAIter = VMAMap::iterator; | ||||||
| 
 | 
 | ||||||
|  | @ -707,35 +738,6 @@ private: | ||||||
|     /// Clears out the page table
 |     /// Clears out the page table
 | ||||||
|     void ClearPageTable(); |     void ClearPageTable(); | ||||||
| 
 | 
 | ||||||
|     using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; |  | ||||||
| 
 |  | ||||||
|     /// Checks if an address range adheres to the specified states provided.
 |  | ||||||
|     ///
 |  | ||||||
|     /// @param address         The starting address of the address range.
 |  | ||||||
|     /// @param size            The size of the address range.
 |  | ||||||
|     /// @param state_mask      The memory state mask.
 |  | ||||||
|     /// @param state           The state to compare the individual VMA states against,
 |  | ||||||
|     ///                        which is done in the form of: (vma.state & state_mask) != state.
 |  | ||||||
|     /// @param permission_mask The memory permissions mask.
 |  | ||||||
|     /// @param permissions     The permission to compare the individual VMA permissions against,
 |  | ||||||
|     ///                        which is done in the form of:
 |  | ||||||
|     ///                        (vma.permission & permission_mask) != permission.
 |  | ||||||
|     /// @param attribute_mask  The memory attribute mask.
 |  | ||||||
|     /// @param attribute       The memory attributes to compare the individual VMA attributes
 |  | ||||||
|     ///                        against, which is done in the form of:
 |  | ||||||
|     ///                        (vma.attributes & attribute_mask) != attribute.
 |  | ||||||
|     /// @param ignore_mask     The memory attributes to ignore during the check.
 |  | ||||||
|     ///
 |  | ||||||
|     /// @returns If successful, returns a tuple containing the memory attributes
 |  | ||||||
|     ///          (with ignored bits specified by ignore_mask unset), memory permissions, and
 |  | ||||||
|     ///          memory state across the memory range.
 |  | ||||||
|     /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
 |  | ||||||
|     ///
 |  | ||||||
|     CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, |  | ||||||
|                                  VMAPermission permission_mask, VMAPermission permissions, |  | ||||||
|                                  MemoryAttribute attribute_mask, MemoryAttribute attribute, |  | ||||||
|                                  MemoryAttribute ignore_mask) const; |  | ||||||
| 
 |  | ||||||
|     /// Gets the amount of memory currently mapped (state != Unmapped) in a range.
 |     /// Gets the amount of memory currently mapped (state != Unmapped) in a range.
 | ||||||
|     ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; |     ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -50,17 +50,8 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { | ||||||
|         if (ShouldWait(thread.get())) |         if (ShouldWait(thread.get())) | ||||||
|             continue; |             continue; | ||||||
| 
 | 
 | ||||||
|         // A thread is ready to run if it's either in ThreadStatus::WaitSynch
 |         candidate = thread.get(); | ||||||
|         // and the rest of the objects it is waiting on are ready.
 |         candidate_priority = thread->GetPriority(); | ||||||
|         bool ready_to_run = true; |  | ||||||
|         if (thread_status == ThreadStatus::WaitSynch) { |  | ||||||
|             ready_to_run = thread->AllWaitObjectsReady(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (ready_to_run) { |  | ||||||
|             candidate = thread.get(); |  | ||||||
|             candidate_priority = thread->GetPriority(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return SharedFrom(candidate); |     return SharedFrom(candidate); | ||||||
|  |  | ||||||
|  | @ -709,8 +709,34 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { | ||||||
|     apm_sys->SetCpuBoostMode(ctx); |     apm_sys->SetCpuBoostMode(ctx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IStorage::IStorage(std::vector<u8> buffer) | IStorageImpl::~IStorageImpl() = default; | ||||||
|     : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | 
 | ||||||
|  | class StorageDataImpl final : public IStorageImpl { | ||||||
|  | public: | ||||||
|  |     explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {} | ||||||
|  | 
 | ||||||
|  |     std::vector<u8>& GetData() override { | ||||||
|  |         return buffer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const std::vector<u8>& GetData() const override { | ||||||
|  |         return buffer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::size_t GetSize() const override { | ||||||
|  |         return buffer.size(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::vector<u8> buffer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | IStorage::IStorage(std::vector<u8>&& buffer) | ||||||
|  |     : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { | ||||||
|  |     Register(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void IStorage::Register() { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|             {0, &IStorage::Open, "Open"}, |             {0, &IStorage::Open, "Open"}, | ||||||
|  | @ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer) | ||||||
| 
 | 
 | ||||||
| IStorage::~IStorage() = default; | IStorage::~IStorage() = default; | ||||||
| 
 | 
 | ||||||
| const std::vector<u8>& IStorage::GetData() const { | void IStorage::Open(Kernel::HLERequestContext& ctx) { | ||||||
|     return buffer; |     LOG_DEBUG(Service_AM, "called"); | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|  | 
 | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.PushIpcInterface<IStorageAccessor>(*this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -825,17 +856,16 @@ private: | ||||||
|     void PopOutData(Kernel::HLERequestContext& ctx) { |     void PopOutData(Kernel::HLERequestContext& ctx) { | ||||||
|         LOG_DEBUG(Service_AM, "called"); |         LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |  | ||||||
| 
 |  | ||||||
|         const auto storage = applet->GetBroker().PopNormalDataToGame(); |         const auto storage = applet->GetBroker().PopNormalDataToGame(); | ||||||
|         if (storage == nullptr) { |         if (storage == nullptr) { | ||||||
|             LOG_ERROR(Service_AM, |             LOG_ERROR(Service_AM, | ||||||
|                       "storage is a nullptr. There is no data in the current normal channel"); |                       "storage is a nullptr. There is no data in the current normal channel"); | ||||||
| 
 |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|             rb.Push(ERR_NO_DATA_IN_CHANNEL); |             rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         rb.PushIpcInterface<IStorage>(std::move(*storage)); |         rb.PushIpcInterface<IStorage>(std::move(*storage)); | ||||||
|     } |     } | ||||||
|  | @ -857,17 +887,16 @@ private: | ||||||
|     void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { |     void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { | ||||||
|         LOG_DEBUG(Service_AM, "called"); |         LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |  | ||||||
| 
 |  | ||||||
|         const auto storage = applet->GetBroker().PopInteractiveDataToGame(); |         const auto storage = applet->GetBroker().PopInteractiveDataToGame(); | ||||||
|         if (storage == nullptr) { |         if (storage == nullptr) { | ||||||
|             LOG_ERROR(Service_AM, |             LOG_ERROR(Service_AM, | ||||||
|                       "storage is a nullptr. There is no data in the current interactive channel"); |                       "storage is a nullptr. There is no data in the current interactive channel"); | ||||||
| 
 |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|             rb.Push(ERR_NO_DATA_IN_CHANNEL); |             rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         rb.PushIpcInterface<IStorage>(std::move(*storage)); |         rb.PushIpcInterface<IStorage>(std::move(*storage)); | ||||||
|     } |     } | ||||||
|  | @ -891,15 +920,6 @@ private: | ||||||
|     std::shared_ptr<Applets::Applet> applet; |     std::shared_ptr<Applets::Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void IStorage::Open(Kernel::HLERequestContext& ctx) { |  | ||||||
|     LOG_DEBUG(Service_AM, "called"); |  | ||||||
| 
 |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |  | ||||||
| 
 |  | ||||||
|     rb.Push(RESULT_SUCCESS); |  | ||||||
|     rb.PushIpcInterface<IStorageAccessor>(*this); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| IStorageAccessor::IStorageAccessor(IStorage& storage) | IStorageAccessor::IStorageAccessor(IStorage& storage) | ||||||
|     : ServiceFramework("IStorageAccessor"), backing(storage) { |     : ServiceFramework("IStorageAccessor"), backing(storage) { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|  | @ -921,7 +941,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.Push(static_cast<u64>(backing.buffer.size())); |     rb.Push(static_cast<u64>(backing.GetSize())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -932,17 +952,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); |     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); | ||||||
| 
 | 
 | ||||||
|     if (data.size() > backing.buffer.size() - offset) { |     if (data.size() > backing.GetSize() - offset) { | ||||||
|         LOG_ERROR(Service_AM, |         LOG_ERROR(Service_AM, | ||||||
|                   "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", |                   "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", | ||||||
|                   backing.buffer.size(), data.size(), offset); |                   backing.GetSize(), data.size(), offset); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(ERR_SIZE_OUT_OF_BOUNDS); |         rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); |     std::memcpy(backing.GetData().data() + offset, data.data(), data.size()); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  | @ -956,16 +976,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); |     LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); | ||||||
| 
 | 
 | ||||||
|     if (size > backing.buffer.size() - offset) { |     if (size > backing.GetSize() - offset) { | ||||||
|         LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", |         LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", | ||||||
|                   backing.buffer.size(), size, offset); |                   backing.GetSize(), size, offset); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(ERR_SIZE_OUT_OF_BOUNDS); |         rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ctx.WriteBuffer(backing.buffer.data() + offset, size); |     ctx.WriteBuffer(backing.GetData().data() + offset, size); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  | @ -1031,7 +1051,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex | ||||||
|     rp.SetCurrentOffset(3); |     rp.SetCurrentOffset(3); | ||||||
|     const auto handle{rp.Pop<Kernel::Handle>()}; |     const auto handle{rp.Pop<Kernel::Handle>()}; | ||||||
| 
 | 
 | ||||||
|     const auto transfer_mem = |     auto transfer_mem = | ||||||
|         system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); |         system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); | ||||||
| 
 | 
 | ||||||
|     if (transfer_mem == nullptr) { |     if (transfer_mem == nullptr) { | ||||||
|  | @ -1047,7 +1067,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); |     rb.PushIpcInterface<IStorage>(std::move(memory)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IApplicationFunctions::IApplicationFunctions(Core::System& system_) | IApplicationFunctions::IApplicationFunctions(Core::System& system_) | ||||||
|  | @ -1189,13 +1209,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | ||||||
|         u64 build_id{}; |         u64 build_id{}; | ||||||
|         std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); |         std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); | ||||||
| 
 | 
 | ||||||
|         const auto data = |         auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); | ||||||
|             backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); |  | ||||||
| 
 |  | ||||||
|         if (data.has_value()) { |         if (data.has_value()) { | ||||||
|             IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |             IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|             rb.Push(RESULT_SUCCESS); |             rb.Push(RESULT_SUCCESS); | ||||||
|             rb.PushIpcInterface<AM::IStorage>(*data); |             rb.PushIpcInterface<IStorage>(std::move(*data)); | ||||||
|             launch_popped_application_specific = true; |             launch_popped_application_specific = true; | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  | @ -1218,7 +1236,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | ||||||
|         std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); |         std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); | ||||||
|         std::memcpy(buffer.data(), ¶ms, buffer.size()); |         std::memcpy(buffer.data(), ¶ms, buffer.size()); | ||||||
| 
 | 
 | ||||||
|         rb.PushIpcInterface<AM::IStorage>(buffer); |         rb.PushIpcInterface<IStorage>(std::move(buffer)); | ||||||
|         launch_popped_account_preselect = true; |         launch_popped_account_preselect = true; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -12,7 +12,8 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| class KernelCore; | class KernelCore; | ||||||
| } | class TransferMemory; | ||||||
|  | } // namespace Kernel
 | ||||||
| 
 | 
 | ||||||
| namespace Service::NVFlinger { | namespace Service::NVFlinger { | ||||||
| class NVFlinger; | class NVFlinger; | ||||||
|  | @ -188,19 +189,36 @@ private: | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |     std::shared_ptr<AppletMessageQueue> msg_queue; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class IStorageImpl { | ||||||
|  | public: | ||||||
|  |     virtual ~IStorageImpl(); | ||||||
|  |     virtual std::vector<u8>& GetData() = 0; | ||||||
|  |     virtual const std::vector<u8>& GetData() const = 0; | ||||||
|  |     virtual std::size_t GetSize() const = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class IStorage final : public ServiceFramework<IStorage> { | class IStorage final : public ServiceFramework<IStorage> { | ||||||
| public: | public: | ||||||
|     explicit IStorage(std::vector<u8> buffer); |     explicit IStorage(std::vector<u8>&& buffer); | ||||||
|     ~IStorage() override; |     ~IStorage() override; | ||||||
| 
 | 
 | ||||||
|     const std::vector<u8>& GetData() const; |     std::vector<u8>& GetData() { | ||||||
|  |         return impl->GetData(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const std::vector<u8>& GetData() const { | ||||||
|  |         return impl->GetData(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::size_t GetSize() const { | ||||||
|  |         return impl->GetSize(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     void Register(); | ||||||
|     void Open(Kernel::HLERequestContext& ctx); |     void Open(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     std::vector<u8> buffer; |     std::shared_ptr<IStorageImpl> impl; | ||||||
| 
 |  | ||||||
|     friend class IStorageAccessor; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | ||||||
|  |  | ||||||
|  | @ -56,6 +56,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { | ||||||
| 
 | 
 | ||||||
|     auto out = std::move(out_channel.front()); |     auto out = std::move(out_channel.front()); | ||||||
|     out_channel.pop_front(); |     out_channel.pop_front(); | ||||||
|  |     pop_out_data_event.writable->Clear(); | ||||||
|     return out; |     return out; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -74,6 +75,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { | ||||||
| 
 | 
 | ||||||
|     auto out = std::move(out_interactive_channel.front()); |     auto out = std::move(out_interactive_channel.front()); | ||||||
|     out_interactive_channel.pop_front(); |     out_interactive_channel.pop_front(); | ||||||
|  |     pop_interactive_out_data_event.writable->Clear(); | ||||||
|     return out; |     return out; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -186,7 +186,7 @@ void Error::Execute() { | ||||||
| 
 | 
 | ||||||
| void Error::DisplayCompleted() { | void Error::DisplayCompleted() { | ||||||
|     complete = true; |     complete = true; | ||||||
|     broker.PushNormalDataFromApplet(IStorage{{}}); |     broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}}); | ||||||
|     broker.SignalStateChanged(); |     broker.SignalStateChanged(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) { | ||||||
|     std::vector<u8> out(sizeof(Return)); |     std::vector<u8> out(sizeof(Return)); | ||||||
|     std::memcpy(out.data(), &return_, sizeof(Return)); |     std::memcpy(out.data(), &return_, sizeof(Return)); | ||||||
| 
 | 
 | ||||||
|     broker.PushNormalDataFromApplet(IStorage{out}); |     broker.PushNormalDataFromApplet(IStorage{std::move(out)}); | ||||||
|     broker.SignalStateChanged(); |     broker.SignalStateChanged(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -198,7 +198,7 @@ void PhotoViewer::Execute() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PhotoViewer::ViewFinished() { | void PhotoViewer::ViewFinished() { | ||||||
|     broker.PushNormalDataFromApplet(IStorage{{}}); |     broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}}); | ||||||
|     broker.SignalStateChanged(); |     broker.SignalStateChanged(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() { | ||||||
| 
 | 
 | ||||||
| void ProfileSelect::Execute() { | void ProfileSelect::Execute() { | ||||||
|     if (complete) { |     if (complete) { | ||||||
|         broker.PushNormalDataFromApplet(IStorage{final_data}); |         broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { | ||||||
| 
 | 
 | ||||||
|     final_data = std::vector<u8>(sizeof(UserSelectionOutput)); |     final_data = std::vector<u8>(sizeof(UserSelectionOutput)); | ||||||
|     std::memcpy(final_data.data(), &output, final_data.size()); |     std::memcpy(final_data.data(), &output, final_data.size()); | ||||||
|     broker.PushNormalDataFromApplet(IStorage{final_data}); |     broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); | ||||||
|     broker.SignalStateChanged(); |     broker.SignalStateChanged(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -102,7 +102,8 @@ void SoftwareKeyboard::ExecuteInteractive() { | ||||||
| 
 | 
 | ||||||
| void SoftwareKeyboard::Execute() { | void SoftwareKeyboard::Execute() { | ||||||
|     if (complete) { |     if (complete) { | ||||||
|         broker.PushNormalDataFromApplet(IStorage{final_data}); |         broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); | ||||||
|  |         broker.SignalStateChanged(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -119,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | ||||||
|         std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); |         std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); | ||||||
| 
 | 
 | ||||||
|         if (config.utf_8) { |         if (config.utf_8) { | ||||||
|             const u64 size = text->size() + 8; |             const u64 size = text->size() + sizeof(u64); | ||||||
|             const auto new_text = Common::UTF16ToUTF8(*text); |             const auto new_text = Common::UTF16ToUTF8(*text); | ||||||
| 
 | 
 | ||||||
|             std::memcpy(output_sub.data(), &size, sizeof(u64)); |             std::memcpy(output_sub.data(), &size, sizeof(u64)); | ||||||
|  | @ -130,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | ||||||
|             std::memcpy(output_main.data() + 4, new_text.data(), |             std::memcpy(output_main.data() + 4, new_text.data(), | ||||||
|                         std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); |                         std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); | ||||||
|         } else { |         } else { | ||||||
|             const u64 size = text->size() * 2 + 8; |             const u64 size = text->size() * 2 + sizeof(u64); | ||||||
|             std::memcpy(output_sub.data(), &size, sizeof(u64)); |             std::memcpy(output_sub.data(), &size, sizeof(u64)); | ||||||
|             std::memcpy(output_sub.data() + 8, text->data(), |             std::memcpy(output_sub.data() + 8, text->data(), | ||||||
|                         std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); |                         std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); | ||||||
|  | @ -144,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | ||||||
|         final_data = output_main; |         final_data = output_main; | ||||||
| 
 | 
 | ||||||
|         if (complete) { |         if (complete) { | ||||||
|             broker.PushNormalDataFromApplet(IStorage{output_main}); |             broker.PushNormalDataFromApplet(IStorage{std::move(output_main)}); | ||||||
|             broker.SignalStateChanged(); |             broker.SignalStateChanged(); | ||||||
|         } else { |         } else { | ||||||
|             broker.PushInteractiveDataFromApplet(IStorage{output_sub}); |             broker.PushInteractiveDataFromApplet(IStorage{std::move(output_sub)}); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         output_main[0] = 1; |         output_main[0] = 1; | ||||||
|         complete = true; |         complete = true; | ||||||
|         broker.PushNormalDataFromApplet(IStorage{output_main}); |         broker.PushNormalDataFromApplet(IStorage{std::move(output_main)}); | ||||||
|         broker.SignalStateChanged(); |         broker.SignalStateChanged(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -284,7 +284,7 @@ void WebBrowser::Finalize() { | ||||||
|     std::vector<u8> data(sizeof(WebCommonReturnValue)); |     std::vector<u8> data(sizeof(WebCommonReturnValue)); | ||||||
|     std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); |     std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); | ||||||
| 
 | 
 | ||||||
|     broker.PushNormalDataFromApplet(IStorage{data}); |     broker.PushNormalDataFromApplet(IStorage{std::move(data)}); | ||||||
|     broker.SignalStateChanged(); |     broker.SignalStateChanged(); | ||||||
| 
 | 
 | ||||||
|     if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { |     if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei