mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #2533 from Lectem/apt_ipchelper
IpcHelper enhancement and APT refactor
This commit is contained in:
		
						commit
						26979cd6ef
					
				
					 6 changed files with 383 additions and 254 deletions
				
			
		|  | @ -10,7 +10,8 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
 | /// Offset into command buffer of header
 | ||||||
|  | static const int kCommandHeaderOffset = 0x80; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Returns a pointer to the command buffer in the current thread's TLS |  * Returns a pointer to the command buffer in the current thread's TLS | ||||||
|  | @ -26,8 +27,8 @@ inline u32* GetCommandBuffer(const int offset = 0) { | ||||||
|                                     offset); |                                     offset); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const int kStaticBuffersOffset = | /// Offset into static buffers, relative to command buffer header
 | ||||||
|     0x100; ///< Offset into static buffers, relative to command buffer header
 | static const int kStaticBuffersOffset = 0x100; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Returns a pointer to the static buffers area in the current thread's TLS |  * Returns a pointer to the static buffers area in the current thread's TLS | ||||||
|  |  | ||||||
|  | @ -27,6 +27,24 @@ public: | ||||||
|         DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", |         DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", | ||||||
|                          header.raw); |                          header.raw); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     void Skip(unsigned size_in_words, bool set_to_null) { | ||||||
|  |         if (set_to_null) | ||||||
|  |             memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); | ||||||
|  |         index += size_in_words; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Retrieves the address of a static buffer, used when a buffer is needed for output | ||||||
|  |      * @param buffer_id The index of the static buffer | ||||||
|  |      * @param data_size If non-null, will store the size of the buffer | ||||||
|  |      */ | ||||||
|  |     VAddr PeekStaticBuffer(u8 buffer_id, size_t* data_size = nullptr) const { | ||||||
|  |         u32* static_buffer = cmdbuf + Kernel::kStaticBuffersOffset / sizeof(u32) + buffer_id * 2; | ||||||
|  |         if (data_size) | ||||||
|  |             *data_size = StaticBufferDescInfo{static_buffer[0]}.size; | ||||||
|  |         return static_buffer[1]; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class RequestBuilder : public RequestHelperBase { | class RequestBuilder : public RequestHelperBase { | ||||||
|  | @ -50,14 +68,8 @@ public: | ||||||
|     template <typename T> |     template <typename T> | ||||||
|     void Push(T value); |     void Push(T value); | ||||||
| 
 | 
 | ||||||
|     void Push(u32 value) { |  | ||||||
|         cmdbuf[index++] = value; |  | ||||||
|     } |  | ||||||
|     template <typename First, typename... Other> |     template <typename First, typename... Other> | ||||||
|     void Push(const First& first_value, const Other&... other_values) { |     void Push(const First& first_value, const Other&... other_values); | ||||||
|         Push(first_value); |  | ||||||
|         Push(other_values...); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * @brief Copies the content of the given trivially copyable class to the buffer as a normal |      * @brief Copies the content of the given trivially copyable class to the buffer as a normal | ||||||
|  | @ -65,59 +77,96 @@ public: | ||||||
|      * @note: The input class must be correctly packed/padded to fit hardware layout. |      * @note: The input class must be correctly packed/padded to fit hardware layout. | ||||||
|      */ |      */ | ||||||
|     template <typename T> |     template <typename T> | ||||||
|     void PushRaw(const T& value) { |     void PushRaw(const T& value); | ||||||
|         static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); |  | ||||||
|         std::memcpy(cmdbuf + index, &value, sizeof(T)); |  | ||||||
|         index += (sizeof(T) + 3) / 4; // round up to word length
 |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // TODO : ensure that translate params are added after all regular params
 |     // TODO : ensure that translate params are added after all regular params
 | ||||||
|     template <typename... H> |     template <typename... H> | ||||||
|     void PushCopyHandles(H... handles) { |     void PushCopyHandles(H... handles); | ||||||
|         Push(CopyHandleDesc(sizeof...(H))); |  | ||||||
|         Push(static_cast<Kernel::Handle>(handles)...); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     template <typename... H> |     template <typename... H> | ||||||
|     void PushMoveHandles(H... handles) { |     void PushMoveHandles(H... handles); | ||||||
|         Push(MoveHandleDesc(sizeof...(H))); |  | ||||||
|         Push(static_cast<Kernel::Handle>(handles)...); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     void PushCurrentPIDHandle() { |     void PushCurrentPIDHandle(); | ||||||
|         Push(CallingPidDesc()); |  | ||||||
|         Push(u32(0)); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { |     void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id); | ||||||
|         Push(StaticBufferDesc(size, buffer_id)); |  | ||||||
|         Push(buffer_vaddr); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms) { |     void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms); | ||||||
|         Push(MappedBufferDesc(size, perms)); |  | ||||||
|         Push(buffer_vaddr); |  | ||||||
|     } |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Push ///
 | /// Push ///
 | ||||||
| 
 | 
 | ||||||
| template <> | template <> | ||||||
| inline void RequestBuilder::Push<u32>(u32 value) { | inline void RequestBuilder::Push(u32 value) { | ||||||
|     Push(value); |     cmdbuf[index++] = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | void RequestBuilder::PushRaw(const T& value) { | ||||||
|  |     static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||||||
|  |     std::memcpy(cmdbuf + index, &value, sizeof(T)); | ||||||
|  |     index += (sizeof(T) + 3) / 4; // round up to word length
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <> | template <> | ||||||
| inline void RequestBuilder::Push<u64>(u64 value) { | inline void RequestBuilder::Push(u8 value) { | ||||||
|  |     PushRaw(value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | inline void RequestBuilder::Push(u16 value) { | ||||||
|  |     PushRaw(value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | inline void RequestBuilder::Push(u64 value) { | ||||||
|     Push(static_cast<u32>(value)); |     Push(static_cast<u32>(value)); | ||||||
|     Push(static_cast<u32>(value >> 32)); |     Push(static_cast<u32>(value >> 32)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <> | template <> | ||||||
| inline void RequestBuilder::Push<ResultCode>(ResultCode value) { | inline void RequestBuilder::Push(bool value) { | ||||||
|  |     Push(static_cast<u8>(value)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | inline void RequestBuilder::Push(ResultCode value) { | ||||||
|     Push(value.raw); |     Push(value.raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | template <typename First, typename... Other> | ||||||
|  | void RequestBuilder::Push(const First& first_value, const Other&... other_values) { | ||||||
|  |     Push(first_value); | ||||||
|  |     Push(other_values...); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename... H> | ||||||
|  | inline void RequestBuilder::PushCopyHandles(H... handles) { | ||||||
|  |     Push(CopyHandleDesc(sizeof...(H))); | ||||||
|  |     Push(static_cast<Kernel::Handle>(handles)...); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename... H> | ||||||
|  | inline void RequestBuilder::PushMoveHandles(H... handles) { | ||||||
|  |     Push(MoveHandleDesc(sizeof...(H))); | ||||||
|  |     Push(static_cast<Kernel::Handle>(handles)...); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void RequestBuilder::PushCurrentPIDHandle() { | ||||||
|  |     Push(CallingPidDesc()); | ||||||
|  |     Push(u32(0)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { | ||||||
|  |     Push(StaticBufferDesc(size, buffer_id)); | ||||||
|  |     Push(buffer_vaddr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void RequestBuilder::PushMappedBuffer(VAddr buffer_vaddr, u32 size, | ||||||
|  |                                              MappedBufferPermissions perms) { | ||||||
|  |     Push(MappedBufferDesc(size, perms)); | ||||||
|  |     Push(buffer_vaddr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| class RequestParser : public RequestHelperBase { | class RequestParser : public RequestHelperBase { | ||||||
| public: | public: | ||||||
|     RequestParser(u32* command_buffer, Header command_header) |     RequestParser(u32* command_buffer, Header command_header) | ||||||
|  | @ -185,24 +234,60 @@ public: | ||||||
|      */ |      */ | ||||||
|     template <typename T> |     template <typename T> | ||||||
|     void PopRaw(T& value); |     void PopRaw(T& value); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Reads the next normal parameters as a struct, by copying it into a new value | ||||||
|  |      * @note: The output class must be correctly packed/padded to fit hardware layout. | ||||||
|  |      */ | ||||||
|  |     template <typename T> | ||||||
|  |     T PopRaw(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Pop ///
 | /// Pop ///
 | ||||||
| 
 | 
 | ||||||
| template <> | template <> | ||||||
| inline u32 RequestParser::Pop<u32>() { | inline u32 RequestParser::Pop() { | ||||||
|     return cmdbuf[index++]; |     return cmdbuf[index++]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | template <typename T> | ||||||
|  | void RequestParser::PopRaw(T& value) { | ||||||
|  |     static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||||||
|  |     std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||||||
|  |     index += (sizeof(T) + 3) / 4; // round up to word length
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | T RequestParser::PopRaw() { | ||||||
|  |     T value; | ||||||
|  |     PopRaw(value); | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| template <> | template <> | ||||||
| inline u64 RequestParser::Pop<u64>() { | inline u8 RequestParser::Pop() { | ||||||
|  |     return PopRaw<u8>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | inline u16 RequestParser::Pop() { | ||||||
|  |     return PopRaw<u16>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | inline u64 RequestParser::Pop() { | ||||||
|     const u64 lsw = Pop<u32>(); |     const u64 lsw = Pop<u32>(); | ||||||
|     const u64 msw = Pop<u32>(); |     const u64 msw = Pop<u32>(); | ||||||
|     return msw << 32 | lsw; |     return msw << 32 | lsw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <> | template <> | ||||||
| inline ResultCode RequestParser::Pop<ResultCode>() { | inline bool RequestParser::Pop() { | ||||||
|  |     return Pop<u8>() != 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | inline ResultCode RequestParser::Pop() { | ||||||
|     return ResultCode{Pop<u32>()}; |     return ResultCode{Pop<u32>()}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -265,11 +350,4 @@ inline VAddr RequestParser::PopMappedBuffer(size_t* data_size, | ||||||
|     return Pop<VAddr>(); |     return Pop<VAddr>(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> |  | ||||||
| void RequestParser::PopRaw(T& value) { |  | ||||||
|     static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); |  | ||||||
|     std::memcpy(&value, cmdbuf + index, sizeof(T)); |  | ||||||
|     index += (sizeof(T) + 3) / 4; // round up to word length
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace IPC
 | } // namespace IPC
 | ||||||
|  |  | ||||||
|  | @ -49,13 +49,13 @@ void SendParameter(const MessageParameter& parameter) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Initialize(Service::Interface* self) { | void Initialize(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080
 | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = rp.Pop<u32>(); | ||||||
|     u32 flags = cmd_buff[2]; |     u32 flags = rp.Pop<u32>(); | ||||||
| 
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); | ||||||
|     cmd_buff[2] = IPC::CopyHandleDesc(2); |     rb.Push(RESULT_SUCCESS); | ||||||
|     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); |     rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).MoveFrom(), | ||||||
|     cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom(); |                        Kernel::g_handle_table.Create(parameter_event).MoveFrom()); | ||||||
| 
 | 
 | ||||||
|     // TODO(bunnei): Check if these events are cleared every time Initialize is called.
 |     // TODO(bunnei): Check if these events are cleared every time Initialize is called.
 | ||||||
|     notification_event->Clear(); |     notification_event->Clear(); | ||||||
|  | @ -64,18 +64,16 @@ void Initialize(Service::Interface* self) { | ||||||
|     ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); |     ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); | ||||||
|     lock->Release(); |     lock->Release(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |  | ||||||
| 
 |  | ||||||
|     LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); |     LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetSharedFont(Service::Interface* self) { | void GetSharedFont(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000
 | ||||||
| 
 |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | ||||||
|     if (!shared_font_mem) { |     if (!shared_font_mem) { | ||||||
|         LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); |         LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); | ||||||
|         cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); |         rb.Push<u32>(-1); // TODO: Find the right error code
 | ||||||
|         cmd_buff[1] = -1; // TODO: Find the right error code
 |         rb.Skip(1 + 2, true); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -87,103 +85,110 @@ void GetSharedFont(Service::Interface* self) { | ||||||
|         BCFNT::RelocateSharedFont(shared_font_mem, target_address); |         BCFNT::RelocateSharedFont(shared_font_mem, target_address); | ||||||
|         shared_font_relocated = true; |         shared_font_relocated = true; | ||||||
|     } |     } | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     // Since the SharedMemory interface doesn't provide the address at which the memory was
 |     // Since the SharedMemory interface doesn't provide the address at which the memory was
 | ||||||
|     // allocated, the real APT service calculates this address by scanning the entire address space
 |     // allocated, the real APT service calculates this address by scanning the entire address space
 | ||||||
|     // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font.
 |     // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font.
 | ||||||
|     cmd_buff[2] = target_address; |     rb.Push(target_address); | ||||||
|     cmd_buff[3] = IPC::CopyHandleDesc(); |     rb.PushCopyHandles(Kernel::g_handle_table.Create(shared_font_mem).MoveFrom()); | ||||||
|     cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void NotifyToWait(Service::Interface* self) { | void NotifyToWait(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x43, 1, 0); // 0x430040
 | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = rp.Pop<u32>(); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetLockHandle(Service::Interface* self) { | void GetLockHandle(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1, 1, 0); // 0x10040
 | ||||||
|  | 
 | ||||||
|     // Bits [0:2] are the applet type (System, Library, etc)
 |     // Bits [0:2] are the applet type (System, Library, etc)
 | ||||||
|     // Bit 5 tells the application that there's a pending APT parameter,
 |     // Bit 5 tells the application that there's a pending APT parameter,
 | ||||||
|     // this will cause the app to wait until parameter_event is signaled.
 |     // this will cause the app to wait until parameter_event is signaled.
 | ||||||
|     u32 applet_attributes = cmd_buff[1]; |     u32 applet_attributes = rp.Pop<u32>(); | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); | ||||||
|  |     rb.Push(RESULT_SUCCESS);    // No error
 | ||||||
|  |     rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable.
 | ||||||
|  |     rb.Push<u32>(0);            // Least significant bit = power button state
 | ||||||
|  |     Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).MoveFrom(); | ||||||
|  |     rb.PushCopyHandles(handle_copy); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", handle_copy, | ||||||
| 
 |  | ||||||
|     cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable.
 |  | ||||||
|     cmd_buff[3] = 0;                 // Least significant bit = power button state
 |  | ||||||
|     cmd_buff[4] = IPC::CopyHandleDesc(); |  | ||||||
|     cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); |  | ||||||
| 
 |  | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], |  | ||||||
|                 applet_attributes); |                 applet_attributes); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Enable(Service::Interface* self) { | void Enable(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040
 | ||||||
|     u32 attributes = cmd_buff[1]; |     u32 attributes = rp.Pop<u32>(); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS);   // No error
 | ||||||
|     parameter_event->Signal(); // Let the application know that it has been started
 |     parameter_event->Signal(); // Let the application know that it has been started
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); |     LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetAppletManInfo(Service::Interface* self) { | void GetAppletManInfo(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 1, 0); // 0x50040
 | ||||||
|     u32 unk = cmd_buff[1]; |     u32 unk = rp.Pop<u32>(); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); | ||||||
|     cmd_buff[2] = 0; |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     cmd_buff[3] = 0; |     rb.Push<u32>(0); | ||||||
|     cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu);    // Home menu AppID
 |     rb.Push<u32>(0); | ||||||
|     cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
 |     rb.Push(static_cast<u32>(AppletId::HomeMenu));    // Home menu AppID
 | ||||||
|  |     rb.Push(static_cast<u32>(AppletId::Application)); // TODO(purpasmart96): Do this correctly
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); |     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IsRegistered(Service::Interface* self) { | void IsRegistered(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040
 | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = rp.Pop<u32>(); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): An application is considered "registered" if it has already called APT::Enable
 |     // TODO(Subv): An application is considered "registered" if it has already called APT::Enable
 | ||||||
|     // handle this properly once we implement multiprocess support.
 |     // handle this properly once we implement multiprocess support.
 | ||||||
|     cmd_buff[2] = 0; // Set to not registered by default
 |     bool is_registered = false; // Set to not registered by default
 | ||||||
| 
 | 
 | ||||||
|     if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { |     if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { | ||||||
|         cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0; |         is_registered = HLE::Applets::IsLibraryAppletRunning(); | ||||||
|     } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { |     } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { | ||||||
|         cmd_buff[2] = 1; // Set to registered
 |         is_registered = true; // Set to registered
 | ||||||
|     } |     } | ||||||
|  |     rb.Push(is_registered); | ||||||
|  | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void InquireNotification(Service::Interface* self) { | void InquireNotification(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 1, 0); // 0xB0040
 | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = rp.Pop<u32>(); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw;                 // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
 |     rb.Push(RESULT_SUCCESS);                     // No error
 | ||||||
|  |     rb.Push(static_cast<u32>(SignalType::None)); // Signal type
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SendParameter(Service::Interface* self) { | void SendParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104
 | ||||||
|     u32 src_app_id = cmd_buff[1]; |     u32 src_app_id = rp.Pop<u32>(); | ||||||
|     u32 dst_app_id = cmd_buff[2]; |     u32 dst_app_id = rp.Pop<u32>(); | ||||||
|     u32 signal_type = cmd_buff[3]; |     u32 signal_type = rp.Pop<u32>(); | ||||||
|     u32 buffer_size = cmd_buff[4]; |     u32 buffer_size = rp.Pop<u32>(); | ||||||
|     u32 value = cmd_buff[5]; |     Kernel::Handle handle = rp.PopHandle(); | ||||||
|     u32 handle = cmd_buff[6]; |     size_t size; | ||||||
|     u32 size = cmd_buff[7]; |     VAddr buffer = rp.PopStaticBuffer(&size); | ||||||
|     u32 buffer = cmd_buff[8]; |  | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<HLE::Applets::Applet> dest_applet = |     std::shared_ptr<HLE::Applets::Applet> dest_applet = | ||||||
|         HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); |         HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); | ||||||
| 
 | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  | 
 | ||||||
|     if (dest_applet == nullptr) { |     if (dest_applet == nullptr) { | ||||||
|         LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); |         LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); | ||||||
|         cmd_buff[1] = -1; // TODO(Subv): Find the right error code
 |         rb.Push<u32>(-1); // TODO(Subv): Find the right error code
 | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -195,88 +200,104 @@ void SendParameter(Service::Interface* self) { | ||||||
|     param.buffer.resize(buffer_size); |     param.buffer.resize(buffer_size); | ||||||
|     Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); |     Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = dest_applet->ReceiveParameter(param).raw; |     rb.Push(dest_applet->ReceiveParameter(param)); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING( |     LOG_WARNING(Service_APT, | ||||||
|         Service_APT, |  | ||||||
|                 "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," |                 "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | ||||||
|         "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", |                 "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", | ||||||
|         src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer); |                 src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ReceiveParameter(Service::Interface* self) { | void ReceiveParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080
 | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = rp.Pop<u32>(); | ||||||
|     u32 buffer_size = cmd_buff[2]; |     u32 buffer_size = rp.Pop<u32>(); | ||||||
|     VAddr buffer = cmd_buff[0x104 >> 2]; |  | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     size_t static_buff_size; | ||||||
|     cmd_buff[2] = next_parameter.sender_id; |     VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); | ||||||
|     cmd_buff[3] = next_parameter.signal;        // Signal type
 |     if (buffer_size > static_buff_size) | ||||||
|     cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
 |         LOG_WARNING( | ||||||
|     cmd_buff[5] = 0x10; |             Service_APT, | ||||||
|     cmd_buff[6] = 0; |             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||||||
|     if (next_parameter.object != nullptr) |             buffer_size, static_buff_size); | ||||||
|         cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | 
 | ||||||
|     cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; |     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||||||
|     cmd_buff[8] = buffer; |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|  |     rb.Push(next_parameter.sender_id); | ||||||
|  |     rb.Push(next_parameter.signal); // Signal type
 | ||||||
|  |     ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||||||
|  |     rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size
 | ||||||
|  | 
 | ||||||
|  |     rb.PushMoveHandles((next_parameter.object != nullptr) | ||||||
|  |                            ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom() | ||||||
|  |                            : 0); | ||||||
|  |     rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); | ||||||
| 
 | 
 | ||||||
|     Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); |     Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GlanceParameter(Service::Interface* self) { | void GlanceParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080
 | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = rp.Pop<u32>(); | ||||||
|     u32 buffer_size = cmd_buff[2]; |     u32 buffer_size = rp.Pop<u32>(); | ||||||
|     VAddr buffer = cmd_buff[0x104 >> 2]; |  | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     size_t static_buff_size; | ||||||
|     cmd_buff[2] = next_parameter.sender_id; |     VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); | ||||||
|     cmd_buff[3] = next_parameter.signal;        // Signal type
 |     if (buffer_size > static_buff_size) | ||||||
|     cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
 |         LOG_WARNING( | ||||||
|     cmd_buff[5] = 0x10; |             Service_APT, | ||||||
|     cmd_buff[6] = 0; |             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||||||
|     if (next_parameter.object != nullptr) |             buffer_size, static_buff_size); | ||||||
|         cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); |  | ||||||
|     cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; |  | ||||||
|     cmd_buff[8] = buffer; |  | ||||||
| 
 | 
 | ||||||
|     Memory::WriteBlock(buffer, next_parameter.buffer.data(), |     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||||||
|                        std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size())); |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|  |     rb.Push(next_parameter.sender_id); | ||||||
|  |     rb.Push(next_parameter.signal); // Signal type
 | ||||||
|  |     ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||||||
|  |     rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |     rb.PushCopyHandles((next_parameter.object != nullptr) | ||||||
|  |                            ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom() | ||||||
|  |                            : 0); | ||||||
|  |     rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); | ||||||
|  | 
 | ||||||
|  |     Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); | ||||||
|  | 
 | ||||||
|  |     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CancelParameter(Service::Interface* self) { | void CancelParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100
 | ||||||
|     u32 flag1 = cmd_buff[1]; |  | ||||||
|     u32 unk = cmd_buff[2]; |  | ||||||
|     u32 flag2 = cmd_buff[3]; |  | ||||||
|     u32 app_id = cmd_buff[4]; |  | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     u32 check_sender = rp.Pop<u32>(); | ||||||
|     cmd_buff[2] = 1;                  // Set to Success
 |     u32 sender_appid = rp.Pop<u32>(); | ||||||
|  |     u32 check_receiver = rp.Pop<u32>(); | ||||||
|  |     u32 receiver_appid = rp.Pop<u32>(); | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|  |     rb.Push(true);           // Set to Success
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, |     LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, " | ||||||
|                 "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1, |                              "check_receiver=0x%08X, receiver_appid=0x%08X", | ||||||
|                 unk, flag2, app_id); |                 check_sender, sender_appid, check_receiver, receiver_appid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PrepareToStartApplication(Service::Interface* self) { | void PrepareToStartApplication(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x15, 5, 0); // 0x00150140
 | ||||||
|     u32 title_info1 = cmd_buff[1]; |     u32 title_info1 = rp.Pop<u32>(); | ||||||
|     u32 title_info2 = cmd_buff[2]; |     u32 title_info2 = rp.Pop<u32>(); | ||||||
|     u32 title_info3 = cmd_buff[3]; |     u32 title_info3 = rp.Pop<u32>(); | ||||||
|     u32 title_info4 = cmd_buff[4]; |     u32 title_info4 = rp.Pop<u32>(); | ||||||
|     u32 flags = cmd_buff[5]; |     u32 flags = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     if (flags & 0x00000100) { |     if (flags & 0x00000100) { | ||||||
|         unknown_ns_state_field = 1; |         unknown_ns_state_field = 1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, |     LOG_WARNING(Service_APT, | ||||||
|                 "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," |                 "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," | ||||||
|  | @ -285,172 +306,188 @@ void PrepareToStartApplication(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void StartApplication(Service::Interface* self) { | void StartApplication(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 3, 4); // 0x001B00C4
 | ||||||
|     u32 buffer1_size = cmd_buff[1]; |     u32 buffer1_size = rp.Pop<u32>(); | ||||||
|     u32 buffer2_size = cmd_buff[2]; |     u32 buffer2_size = rp.Pop<u32>(); | ||||||
|     u32 flag = cmd_buff[3]; |     u32 flag = rp.Pop<u32>(); | ||||||
|     u32 size1 = cmd_buff[4]; |     size_t size1; | ||||||
|     u32 buffer1_ptr = cmd_buff[5]; |     VAddr buffer1_ptr = rp.PopStaticBuffer(&size1); | ||||||
|     u32 size2 = cmd_buff[6]; |     size_t size2; | ||||||
|     u32 buffer2_ptr = cmd_buff[7]; |     VAddr buffer2_ptr = rp.PopStaticBuffer(&size2); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, |     LOG_WARNING(Service_APT, | ||||||
|                 "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," |                 "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," | ||||||
|                 "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X", |                 "size1=0x%08zX, buffer1_ptr=0x%08X, size2=0x%08zX, buffer2_ptr=0x%08X", | ||||||
|                 buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); |                 buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AppletUtility(Service::Interface* self) { | void AppletUtility(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4B, 3, 2); // 0x004B00C2
 | ||||||
| 
 | 
 | ||||||
|     // These are from 3dbrew - I'm not really sure what they're used for.
 |     // These are from 3dbrew - I'm not really sure what they're used for.
 | ||||||
|     u32 command = cmd_buff[1]; |     u32 utility_command = rp.Pop<u32>(); | ||||||
|     u32 buffer1_size = cmd_buff[2]; |     u32 input_size = rp.Pop<u32>(); | ||||||
|     u32 buffer2_size = cmd_buff[3]; |     u32 output_size = rp.Pop<u32>(); | ||||||
|     u32 buffer1_addr = cmd_buff[5]; |     VAddr input_addr = rp.PopStaticBuffer(); | ||||||
|     u32 buffer2_addr = cmd_buff[65]; |  | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     VAddr output_addr = rp.PeekStaticBuffer(0); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, |     LOG_WARNING(Service_APT, | ||||||
|                 "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " |                 "(STUBBED) called command=0x%08X, input_size=0x%08X, output_size=0x%08X, " | ||||||
|                 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", |                 "input_addr=0x%08X, output_addr=0x%08X", | ||||||
|                 command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr); |                 utility_command, input_size, output_size, input_addr, output_addr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SetAppCpuTimeLimit(Service::Interface* self) { | void SetAppCpuTimeLimit(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4F, 2, 0); // 0x4F0080
 | ||||||
|     u32 value = cmd_buff[1]; |     u32 value = rp.Pop<u32>(); | ||||||
|     cpu_percent = cmd_buff[2]; |     cpu_percent = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     if (value != 1) { |     if (value != 1) { | ||||||
|         LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); |         LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); |     LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetAppCpuTimeLimit(Service::Interface* self) { | void GetAppCpuTimeLimit(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x50, 1, 0); // 0x500040
 | ||||||
|     u32 value = cmd_buff[1]; |     u32 value = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     if (value != 1) { |     if (value != 1) { | ||||||
|         LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); |         LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     cmd_buff[2] = cpu_percent; |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|  |     rb.Push(cpu_percent); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); |     LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PrepareToStartLibraryApplet(Service::Interface* self) { | void PrepareToStartLibraryApplet(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 1, 0); // 0x180040
 | ||||||
|     AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); |     AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     auto applet = HLE::Applets::Applet::Get(applet_id); |     auto applet = HLE::Applets::Applet::Get(applet_id); | ||||||
|     if (applet) { |     if (applet) { | ||||||
|         LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); |         LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | ||||||
|         cmd_buff[1] = RESULT_SUCCESS.raw; |         rb.Push(RESULT_SUCCESS); | ||||||
|     } else { |     } else { | ||||||
|         cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; |         rb.Push(HLE::Applets::Applet::Create(applet_id)); | ||||||
|     } |     } | ||||||
|     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PreloadLibraryApplet(Service::Interface* self) { | void PreloadLibraryApplet(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x16, 1, 0); // 0x160040
 | ||||||
|     AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); |     AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     auto applet = HLE::Applets::Applet::Get(applet_id); |     auto applet = HLE::Applets::Applet::Get(applet_id); | ||||||
|     if (applet) { |     if (applet) { | ||||||
|         LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); |         LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | ||||||
|         cmd_buff[1] = RESULT_SUCCESS.raw; |         rb.Push(RESULT_SUCCESS); | ||||||
|     } else { |     } else { | ||||||
|         cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; |         rb.Push(HLE::Applets::Applet::Create(applet_id)); | ||||||
|     } |     } | ||||||
|     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void StartLibraryApplet(Service::Interface* self) { | void StartLibraryApplet(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 2, 4); // 0x1E0084
 | ||||||
|     AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); |     AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||||||
|     std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); |     std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||||||
| 
 | 
 | ||||||
|     if (applet == nullptr) { |     if (applet == nullptr) { | ||||||
|         LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); |         LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); | ||||||
|         cmd_buff[1] = -1; // TODO(Subv): Find the right error code
 |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0, false); | ||||||
|  |         rb.Push<u32>(-1); // TODO(Subv): Find the right error code
 | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     size_t buffer_size = cmd_buff[2]; |     size_t buffer_size = rp.Pop<u32>(); | ||||||
|     VAddr buffer_addr = cmd_buff[6]; |     Kernel::Handle handle = rp.PopHandle(); | ||||||
|  |     VAddr buffer_addr = rp.PopStaticBuffer(); | ||||||
| 
 | 
 | ||||||
|     AppletStartupParameter parameter; |     AppletStartupParameter parameter; | ||||||
|     parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]); |     parameter.object = Kernel::g_handle_table.GetGeneric(handle); | ||||||
|     parameter.buffer.resize(buffer_size); |     parameter.buffer.resize(buffer_size); | ||||||
|     Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); |     Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = applet->Start(parameter).raw; |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(applet->Start(parameter)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CancelLibraryApplet(Service::Interface* self) { | void CancelLibraryApplet(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3B, 1, 0); // 0x003B0040
 | ||||||
|     u32 exiting = cmd_buff[1] & 0xFF; |     bool exiting = rp.Pop<bool>(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 1; // TODO: Find the return code meaning
 |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push<u32>(1); // TODO: Find the return code meaning
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called exiting=%u", exiting); |     LOG_WARNING(Service_APT, "(STUBBED) called exiting=%d", exiting); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SetScreenCapPostPermission(Service::Interface* self) { | void SetScreenCapPostPermission(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x55, 1, 0); // 0x00550040
 | ||||||
| 
 | 
 | ||||||
|     screen_capture_post_permission = static_cast<ScreencapPostPermission>(cmd_buff[1] & 0xF); |     screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", |     LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | ||||||
|                 screen_capture_post_permission); |                 screen_capture_post_permission); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetScreenCapPostPermission(Service::Interface* self) { | void GetScreenCapPostPermission(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x56, 0, 0); // 0x00560000
 | ||||||
| 
 | 
 | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     cmd_buff[2] = static_cast<u32>(screen_capture_post_permission); |     rb.Push(static_cast<u32>(screen_capture_post_permission)); | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", |     LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | ||||||
|                 screen_capture_post_permission); |                 screen_capture_post_permission); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetAppletInfo(Service::Interface* self) { | void GetAppletInfo(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x6, 1, 0); // 0x60040
 | ||||||
|     auto app_id = static_cast<AppletId>(cmd_buff[1]); |     auto app_id = static_cast<AppletId>(rp.Pop<u32>()); | ||||||
| 
 | 
 | ||||||
|     if (auto applet = HLE::Applets::Applet::Get(app_id)) { |     if (auto applet = HLE::Applets::Applet::Get(app_id)) { | ||||||
|         // TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
 |         // TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
 | ||||||
|         cmd_buff[1] = RESULT_SUCCESS.raw; |         IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); | ||||||
|         cmd_buff[4] = static_cast<u32>(Service::FS::MediaType::NAND); |         rb.Push(RESULT_SUCCESS); | ||||||
|         cmd_buff[5] = 1; // Registered
 |         u64 title_id = 0; | ||||||
|         cmd_buff[6] = 1; // Loaded
 |         rb.Push(title_id); | ||||||
|         cmd_buff[7] = 0; // Applet Attributes
 |         rb.Push(static_cast<u32>(Service::FS::MediaType::NAND)); | ||||||
|  |         rb.Push(true);   // Registered
 | ||||||
|  |         rb.Push(true);   // Loaded
 | ||||||
|  |         rb.Push<u32>(0); // Applet Attributes
 | ||||||
|     } else { |     } else { | ||||||
|         cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|                                  ErrorSummary::NotFound, ErrorLevel::Status) |         rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||||||
|                           .raw; |                            ErrorLevel::Status)); | ||||||
|     } |     } | ||||||
|     LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); |     LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetStartupArgument(Service::Interface* self) { | void GetStartupArgument(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x51, 2, 0); // 0x00510080
 | ||||||
|     u32 parameter_size = cmd_buff[1]; |     u32 parameter_size = rp.Pop<u32>(); | ||||||
|     StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]); |     StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>()); | ||||||
| 
 | 
 | ||||||
|     if (parameter_size >= 0x300) { |     if (parameter_size >= 0x300) { | ||||||
|         LOG_ERROR( |         LOG_ERROR( | ||||||
|  | @ -460,7 +497,14 @@ void GetStartupArgument(Service::Interface* self) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     u32 addr = cmd_buff[65]; |     size_t static_buff_size; | ||||||
|  |     VAddr addr = rp.PeekStaticBuffer(0, &static_buff_size); | ||||||
|  |     if (parameter_size > static_buff_size) | ||||||
|  |         LOG_WARNING( | ||||||
|  |             Service_APT, | ||||||
|  |             "parameter_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||||||
|  |             parameter_size, static_buff_size); | ||||||
|  | 
 | ||||||
|     if (addr && parameter_size) { |     if (addr && parameter_size) { | ||||||
|         Memory::ZeroBlock(addr, parameter_size); |         Memory::ZeroBlock(addr, parameter_size); | ||||||
|     } |     } | ||||||
|  | @ -468,8 +512,10 @@ void GetStartupArgument(Service::Interface* self) { | ||||||
|     LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", |     LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", | ||||||
|                 startup_argument_type, parameter_size); |                 startup_argument_type, parameter_size); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | ||||||
|     cmd_buff[2] = 0; |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.Push<u32>(0); | ||||||
|  |     rb.PushStaticBuffer(addr, parameter_size, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Wrap(Service::Interface* self) { | void Wrap(Service::Interface* self) { | ||||||
|  | @ -574,25 +620,25 @@ void Unwrap(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CheckNew3DSApp(Service::Interface* self) { | void CheckNew3DSApp(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x101, 0, 0); // 0x01010000
 | ||||||
| 
 | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     if (unknown_ns_state_field) { |     if (unknown_ns_state_field) { | ||||||
|         cmd_buff[1] = RESULT_SUCCESS.raw; |         rb.Push(RESULT_SUCCESS); | ||||||
|         cmd_buff[2] = 0; |         rb.Push<u32>(0); | ||||||
|     } else { |     } else { | ||||||
|         PTM::CheckNew3DS(self); |         PTM::CheckNew3DS(rb); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0x101, 2, 0); |  | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); |     LOG_WARNING(Service_APT, "(STUBBED) called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CheckNew3DS(Service::Interface* self) { | void CheckNew3DS(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x102, 0, 0); // 0x01020000
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
| 
 | 
 | ||||||
|     PTM::CheckNew3DS(self); |     PTM::CheckNew3DS(rb); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0x102, 2, 0); |  | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); |     LOG_WARNING(Service_APT, "(STUBBED) called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -92,8 +92,7 @@ void GetSoftwareClosedFlag(Service::Interface* self) { | ||||||
|     LOG_WARNING(Service_PTM, "(STUBBED) called"); |     LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CheckNew3DS(Service::Interface* self) { | void CheckNew3DS(IPC::RequestBuilder& rb) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |  | ||||||
|     const bool is_new_3ds = Settings::values.is_new_3ds; |     const bool is_new_3ds = Settings::values.is_new_3ds; | ||||||
| 
 | 
 | ||||||
|     if (is_new_3ds) { |     if (is_new_3ds) { | ||||||
|  | @ -101,12 +100,17 @@ void CheckNew3DS(Service::Interface* self) { | ||||||
|                                   "settings. Citra does not fully support New 3DS emulation yet!"); |                                   "settings. Citra does not fully support New 3DS emulation yet!"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |     rb.Push(RESULT_SUCCESS); | ||||||
|     cmd_buff[2] = is_new_3ds ? 1 : 0; |     rb.Push(is_new_3ds); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); |     LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void CheckNew3DS(Service::Interface* self) { | ||||||
|  |     IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x40A, 0, 0); // 0x040A0000
 | ||||||
|  |     CheckNew3DS(rb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Init() { | void Init() { | ||||||
|     AddService(new PTM_Gets); |     AddService(new PTM_Gets); | ||||||
|     AddService(new PTM_Play); |     AddService(new PTM_Play); | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "core/hle/ipc_helpers.h" | ||||||
| 
 | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| 
 | 
 | ||||||
|  | @ -97,6 +98,7 @@ void GetSoftwareClosedFlag(Interface* self); | ||||||
|  *      2: u8 output: 0 = Old3DS, 1 = New3DS. |  *      2: u8 output: 0 = Old3DS, 1 = New3DS. | ||||||
|  */ |  */ | ||||||
| void CheckNew3DS(Interface* self); | void CheckNew3DS(Interface* self); | ||||||
|  | void CheckNew3DS(IPC::RequestBuilder& rb); | ||||||
| 
 | 
 | ||||||
| /// Initialize the PTM service
 | /// Initialize the PTM service
 | ||||||
| void Init(); | void Init(); | ||||||
|  |  | ||||||
|  | @ -189,11 +189,9 @@ static void SetSpacialDithering(Interface* self) { | ||||||
|  *      2 : u8, 0 = Disabled, 1 = Enabled |  *      2 : u8, 0 = Disabled, 1 = Enabled | ||||||
|  */ |  */ | ||||||
| static void GetSpacialDithering(Interface* self) { | static void GetSpacialDithering(Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0xA, 2, 0); | ||||||
| 
 |     rb.Push(RESULT_SUCCESS); | ||||||
|     cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); |     rb.Push(spacial_dithering_enabled != 0); | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |  | ||||||
|     cmd_buff[2] = spacial_dithering_enabled; |  | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_Y2R, "(STUBBED) called"); |     LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue