diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/ipc.h | 7 | ||||
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 170 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 444 | ||||
| -rw-r--r-- | src/core/hle/service/ptm/ptm.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/ptm/ptm.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/y2r_u.cpp | 8 |
6 files changed, 386 insertions, 257 deletions
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index cd9a5863d..3a5d481a5 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header | 13 | /// Offset into command buffer of header |
| 14 | static const int kCommandHeaderOffset = 0x80; | ||
| 14 | 15 | ||
| 15 | /** | 16 | /** |
| 16 | * Returns a pointer to the command buffer in the current thread's TLS | 17 | * Returns a pointer to the command buffer in the current thread's TLS |
| @@ -26,8 +27,8 @@ inline u32* GetCommandBuffer(const int offset = 0) { | |||
| 26 | offset); | 27 | offset); |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | static const int kStaticBuffersOffset = | 30 | /// Offset into static buffers, relative to command buffer header |
| 30 | 0x100; ///< Offset into static buffers, relative to command buffer header | 31 | static const int kStaticBuffersOffset = 0x100; |
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 33 | * Returns a pointer to the static buffers area in the current thread's TLS | 34 | * Returns a pointer to the static buffers area in the current thread's TLS |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 323158bb5..06c4c5a85 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -27,6 +27,24 @@ public: | |||
| 27 | DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", | 27 | DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", |
| 28 | header.raw); | 28 | header.raw); |
| 29 | } | 29 | } |
| 30 | |||
| 31 | void Skip(unsigned size_in_words, bool set_to_null) { | ||
| 32 | if (set_to_null) | ||
| 33 | memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); | ||
| 34 | index += size_in_words; | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | ||
| 38 | * @brief Retrieves the address of a static buffer, used when a buffer is needed for output | ||
| 39 | * @param buffer_id The index of the static buffer | ||
| 40 | * @param data_size If non-null, will store the size of the buffer | ||
| 41 | */ | ||
| 42 | VAddr PeekStaticBuffer(u8 buffer_id, size_t* data_size = nullptr) const { | ||
| 43 | u32* static_buffer = cmdbuf + Kernel::kStaticBuffersOffset / sizeof(u32) + buffer_id * 2; | ||
| 44 | if (data_size) | ||
| 45 | *data_size = StaticBufferDescInfo{static_buffer[0]}.size; | ||
| 46 | return static_buffer[1]; | ||
| 47 | } | ||
| 30 | }; | 48 | }; |
| 31 | 49 | ||
| 32 | class RequestBuilder : public RequestHelperBase { | 50 | class RequestBuilder : public RequestHelperBase { |
| @@ -50,14 +68,8 @@ public: | |||
| 50 | template <typename T> | 68 | template <typename T> |
| 51 | void Push(T value); | 69 | void Push(T value); |
| 52 | 70 | ||
| 53 | void Push(u32 value) { | ||
| 54 | cmdbuf[index++] = value; | ||
| 55 | } | ||
| 56 | template <typename First, typename... Other> | 71 | template <typename First, typename... Other> |
| 57 | void Push(const First& first_value, const Other&... other_values) { | 72 | void Push(const First& first_value, const Other&... other_values); |
| 58 | Push(first_value); | ||
| 59 | Push(other_values...); | ||
| 60 | } | ||
| 61 | 73 | ||
| 62 | /** | 74 | /** |
| 63 | * @brief Copies the content of the given trivially copyable class to the buffer as a normal | 75 | * @brief Copies the content of the given trivially copyable class to the buffer as a normal |
| @@ -65,59 +77,96 @@ public: | |||
| 65 | * @note: The input class must be correctly packed/padded to fit hardware layout. | 77 | * @note: The input class must be correctly packed/padded to fit hardware layout. |
| 66 | */ | 78 | */ |
| 67 | template <typename T> | 79 | template <typename T> |
| 68 | void PushRaw(const T& value) { | 80 | void PushRaw(const T& value); |
| 69 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 70 | std::memcpy(cmdbuf + index, &value, sizeof(T)); | ||
| 71 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 72 | } | ||
| 73 | 81 | ||
| 74 | // TODO : ensure that translate params are added after all regular params | 82 | // TODO : ensure that translate params are added after all regular params |
| 75 | template <typename... H> | 83 | template <typename... H> |
| 76 | void PushCopyHandles(H... handles) { | 84 | void PushCopyHandles(H... handles); |
| 77 | Push(CopyHandleDesc(sizeof...(H))); | ||
| 78 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 79 | } | ||
| 80 | 85 | ||
| 81 | template <typename... H> | 86 | template <typename... H> |
| 82 | void PushMoveHandles(H... handles) { | 87 | void PushMoveHandles(H... handles); |
| 83 | Push(MoveHandleDesc(sizeof...(H))); | ||
| 84 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 85 | } | ||
| 86 | 88 | ||
| 87 | void PushCurrentPIDHandle() { | 89 | void PushCurrentPIDHandle(); |
| 88 | Push(CallingPidDesc()); | ||
| 89 | Push(u32(0)); | ||
| 90 | } | ||
| 91 | 90 | ||
| 92 | void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { | 91 | void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id); |
| 93 | Push(StaticBufferDesc(size, buffer_id)); | ||
| 94 | Push(buffer_vaddr); | ||
| 95 | } | ||
| 96 | 92 | ||
| 97 | void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms) { | 93 | void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms); |
| 98 | Push(MappedBufferDesc(size, perms)); | ||
| 99 | Push(buffer_vaddr); | ||
| 100 | } | ||
| 101 | }; | 94 | }; |
| 102 | 95 | ||
| 103 | /// Push /// | 96 | /// Push /// |
| 104 | 97 | ||
| 105 | template <> | 98 | template <> |
| 106 | inline void RequestBuilder::Push<u32>(u32 value) { | 99 | inline void RequestBuilder::Push(u32 value) { |
| 107 | Push(value); | 100 | cmdbuf[index++] = value; |
| 101 | } | ||
| 102 | |||
| 103 | template <typename T> | ||
| 104 | void RequestBuilder::PushRaw(const T& value) { | ||
| 105 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 106 | std::memcpy(cmdbuf + index, &value, sizeof(T)); | ||
| 107 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | template <> | 110 | template <> |
| 111 | inline void RequestBuilder::Push<u64>(u64 value) { | 111 | inline void RequestBuilder::Push(u8 value) { |
| 112 | PushRaw(value); | ||
| 113 | } | ||
| 114 | |||
| 115 | template <> | ||
| 116 | inline void RequestBuilder::Push(u16 value) { | ||
| 117 | PushRaw(value); | ||
| 118 | } | ||
| 119 | |||
| 120 | template <> | ||
| 121 | inline void RequestBuilder::Push(u64 value) { | ||
| 112 | Push(static_cast<u32>(value)); | 122 | Push(static_cast<u32>(value)); |
| 113 | Push(static_cast<u32>(value >> 32)); | 123 | Push(static_cast<u32>(value >> 32)); |
| 114 | } | 124 | } |
| 115 | 125 | ||
| 116 | template <> | 126 | template <> |
| 117 | inline void RequestBuilder::Push<ResultCode>(ResultCode value) { | 127 | inline void RequestBuilder::Push(bool value) { |
| 128 | Push(static_cast<u8>(value)); | ||
| 129 | } | ||
| 130 | |||
| 131 | template <> | ||
| 132 | inline void RequestBuilder::Push(ResultCode value) { | ||
| 118 | Push(value.raw); | 133 | Push(value.raw); |
| 119 | } | 134 | } |
| 120 | 135 | ||
| 136 | template <typename First, typename... Other> | ||
| 137 | void RequestBuilder::Push(const First& first_value, const Other&... other_values) { | ||
| 138 | Push(first_value); | ||
| 139 | Push(other_values...); | ||
| 140 | } | ||
| 141 | |||
| 142 | template <typename... H> | ||
| 143 | inline void RequestBuilder::PushCopyHandles(H... handles) { | ||
| 144 | Push(CopyHandleDesc(sizeof...(H))); | ||
| 145 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 146 | } | ||
| 147 | |||
| 148 | template <typename... H> | ||
| 149 | inline void RequestBuilder::PushMoveHandles(H... handles) { | ||
| 150 | Push(MoveHandleDesc(sizeof...(H))); | ||
| 151 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 152 | } | ||
| 153 | |||
| 154 | inline void RequestBuilder::PushCurrentPIDHandle() { | ||
| 155 | Push(CallingPidDesc()); | ||
| 156 | Push(u32(0)); | ||
| 157 | } | ||
| 158 | |||
| 159 | inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { | ||
| 160 | Push(StaticBufferDesc(size, buffer_id)); | ||
| 161 | Push(buffer_vaddr); | ||
| 162 | } | ||
| 163 | |||
| 164 | inline void RequestBuilder::PushMappedBuffer(VAddr buffer_vaddr, u32 size, | ||
| 165 | MappedBufferPermissions perms) { | ||
| 166 | Push(MappedBufferDesc(size, perms)); | ||
| 167 | Push(buffer_vaddr); | ||
| 168 | } | ||
| 169 | |||
| 121 | class RequestParser : public RequestHelperBase { | 170 | class RequestParser : public RequestHelperBase { |
| 122 | public: | 171 | public: |
| 123 | RequestParser(u32* command_buffer, Header command_header) | 172 | RequestParser(u32* command_buffer, Header command_header) |
| @@ -185,24 +234,60 @@ public: | |||
| 185 | */ | 234 | */ |
| 186 | template <typename T> | 235 | template <typename T> |
| 187 | void PopRaw(T& value); | 236 | void PopRaw(T& value); |
| 237 | |||
| 238 | /** | ||
| 239 | * @brief Reads the next normal parameters as a struct, by copying it into a new value | ||
| 240 | * @note: The output class must be correctly packed/padded to fit hardware layout. | ||
| 241 | */ | ||
| 242 | template <typename T> | ||
| 243 | T PopRaw(); | ||
| 188 | }; | 244 | }; |
| 189 | 245 | ||
| 190 | /// Pop /// | 246 | /// Pop /// |
| 191 | 247 | ||
| 192 | template <> | 248 | template <> |
| 193 | inline u32 RequestParser::Pop<u32>() { | 249 | inline u32 RequestParser::Pop() { |
| 194 | return cmdbuf[index++]; | 250 | return cmdbuf[index++]; |
| 195 | } | 251 | } |
| 196 | 252 | ||
| 253 | template <typename T> | ||
| 254 | void RequestParser::PopRaw(T& value) { | ||
| 255 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 256 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||
| 257 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 258 | } | ||
| 259 | |||
| 260 | template <typename T> | ||
| 261 | T RequestParser::PopRaw() { | ||
| 262 | T value; | ||
| 263 | PopRaw(value); | ||
| 264 | return value; | ||
| 265 | } | ||
| 266 | |||
| 267 | template <> | ||
| 268 | inline u8 RequestParser::Pop() { | ||
| 269 | return PopRaw<u8>(); | ||
| 270 | } | ||
| 271 | |||
| 197 | template <> | 272 | template <> |
| 198 | inline u64 RequestParser::Pop<u64>() { | 273 | inline u16 RequestParser::Pop() { |
| 274 | return PopRaw<u16>(); | ||
| 275 | } | ||
| 276 | |||
| 277 | template <> | ||
| 278 | inline u64 RequestParser::Pop() { | ||
| 199 | const u64 lsw = Pop<u32>(); | 279 | const u64 lsw = Pop<u32>(); |
| 200 | const u64 msw = Pop<u32>(); | 280 | const u64 msw = Pop<u32>(); |
| 201 | return msw << 32 | lsw; | 281 | return msw << 32 | lsw; |
| 202 | } | 282 | } |
| 203 | 283 | ||
| 204 | template <> | 284 | template <> |
| 205 | inline ResultCode RequestParser::Pop<ResultCode>() { | 285 | inline bool RequestParser::Pop() { |
| 286 | return Pop<u8>() != 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | template <> | ||
| 290 | inline ResultCode RequestParser::Pop() { | ||
| 206 | return ResultCode{Pop<u32>()}; | 291 | return ResultCode{Pop<u32>()}; |
| 207 | } | 292 | } |
| 208 | 293 | ||
| @@ -265,11 +350,4 @@ inline VAddr RequestParser::PopMappedBuffer(size_t* data_size, | |||
| 265 | return Pop<VAddr>(); | 350 | return Pop<VAddr>(); |
| 266 | } | 351 | } |
| 267 | 352 | ||
| 268 | template <typename T> | ||
| 269 | void RequestParser::PopRaw(T& value) { | ||
| 270 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 271 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||
| 272 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 273 | } | ||
| 274 | |||
| 275 | } // namespace IPC | 353 | } // namespace IPC |
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 1517d3a2f..366d1eacf 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -49,13 +49,13 @@ void SendParameter(const MessageParameter& parameter) { | |||
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | void Initialize(Service::Interface* self) { | 51 | void Initialize(Service::Interface* self) { |
| 52 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 52 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 |
| 53 | u32 app_id = cmd_buff[1]; | 53 | u32 app_id = rp.Pop<u32>(); |
| 54 | u32 flags = cmd_buff[2]; | 54 | u32 flags = rp.Pop<u32>(); |
| 55 | 55 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); | |
| 56 | cmd_buff[2] = IPC::CopyHandleDesc(2); | 56 | rb.Push(RESULT_SUCCESS); |
| 57 | cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); | 57 | rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).MoveFrom(), |
| 58 | cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom(); | 58 | Kernel::g_handle_table.Create(parameter_event).MoveFrom()); |
| 59 | 59 | ||
| 60 | // TODO(bunnei): Check if these events are cleared every time Initialize is called. | 60 | // TODO(bunnei): Check if these events are cleared every time Initialize is called. |
| 61 | notification_event->Clear(); | 61 | notification_event->Clear(); |
| @@ -64,18 +64,16 @@ void Initialize(Service::Interface* self) { | |||
| 64 | ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); | 64 | ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); |
| 65 | lock->Release(); | 65 | lock->Release(); |
| 66 | 66 | ||
| 67 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 68 | |||
| 69 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); | 67 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); |
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | void GetSharedFont(Service::Interface* self) { | 70 | void GetSharedFont(Service::Interface* self) { |
| 73 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 71 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000 |
| 74 | 72 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | |
| 75 | if (!shared_font_mem) { | 73 | if (!shared_font_mem) { |
| 76 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); | 74 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); |
| 77 | cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); | 75 | rb.Push<u32>(-1); // TODO: Find the right error code |
| 78 | cmd_buff[1] = -1; // TODO: Find the right error code | 76 | rb.Skip(1 + 2, true); |
| 79 | return; | 77 | return; |
| 80 | } | 78 | } |
| 81 | 79 | ||
| @@ -87,103 +85,110 @@ void GetSharedFont(Service::Interface* self) { | |||
| 87 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); | 85 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); |
| 88 | shared_font_relocated = true; | 86 | shared_font_relocated = true; |
| 89 | } | 87 | } |
| 90 | cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); | 88 | |
| 91 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 89 | rb.Push(RESULT_SUCCESS); // No error |
| 92 | // Since the SharedMemory interface doesn't provide the address at which the memory was | 90 | // Since the SharedMemory interface doesn't provide the address at which the memory was |
| 93 | // allocated, the real APT service calculates this address by scanning the entire address space | 91 | // allocated, the real APT service calculates this address by scanning the entire address space |
| 94 | // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font. | 92 | // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font. |
| 95 | cmd_buff[2] = target_address; | 93 | rb.Push(target_address); |
| 96 | cmd_buff[3] = IPC::CopyHandleDesc(); | 94 | rb.PushCopyHandles(Kernel::g_handle_table.Create(shared_font_mem).MoveFrom()); |
| 97 | cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); | ||
| 98 | } | 95 | } |
| 99 | 96 | ||
| 100 | void NotifyToWait(Service::Interface* self) { | 97 | void NotifyToWait(Service::Interface* self) { |
| 101 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 98 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x43, 1, 0); // 0x430040 |
| 102 | u32 app_id = cmd_buff[1]; | 99 | u32 app_id = rp.Pop<u32>(); |
| 103 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 100 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 101 | rb.Push(RESULT_SUCCESS); // No error | ||
| 104 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | 102 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |
| 105 | } | 103 | } |
| 106 | 104 | ||
| 107 | void GetLockHandle(Service::Interface* self) { | 105 | void GetLockHandle(Service::Interface* self) { |
| 108 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 106 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1, 1, 0); // 0x10040 |
| 107 | |||
| 109 | // Bits [0:2] are the applet type (System, Library, etc) | 108 | // Bits [0:2] are the applet type (System, Library, etc) |
| 110 | // Bit 5 tells the application that there's a pending APT parameter, | 109 | // Bit 5 tells the application that there's a pending APT parameter, |
| 111 | // this will cause the app to wait until parameter_event is signaled. | 110 | // this will cause the app to wait until parameter_event is signaled. |
| 112 | u32 applet_attributes = cmd_buff[1]; | 111 | u32 applet_attributes = rp.Pop<u32>(); |
| 113 | 112 | IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); | |
| 114 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 113 | rb.Push(RESULT_SUCCESS); // No error |
| 115 | 114 | rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. | |
| 116 | cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable. | 115 | rb.Push<u32>(0); // Least significant bit = power button state |
| 117 | cmd_buff[3] = 0; // Least significant bit = power button state | 116 | Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).MoveFrom(); |
| 118 | cmd_buff[4] = IPC::CopyHandleDesc(); | 117 | rb.PushCopyHandles(handle_copy); |
| 119 | cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); | 118 | |
| 120 | 119 | LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", handle_copy, | |
| 121 | LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], | ||
| 122 | applet_attributes); | 120 | applet_attributes); |
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | void Enable(Service::Interface* self) { | 123 | void Enable(Service::Interface* self) { |
| 126 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 124 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040 |
| 127 | u32 attributes = cmd_buff[1]; | 125 | u32 attributes = rp.Pop<u32>(); |
| 128 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 126 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 129 | parameter_event->Signal(); // Let the application know that it has been started | 127 | rb.Push(RESULT_SUCCESS); // No error |
| 128 | parameter_event->Signal(); // Let the application know that it has been started | ||
| 130 | LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); | 129 | LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); |
| 131 | } | 130 | } |
| 132 | 131 | ||
| 133 | void GetAppletManInfo(Service::Interface* self) { | 132 | void GetAppletManInfo(Service::Interface* self) { |
| 134 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 133 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 1, 0); // 0x50040 |
| 135 | u32 unk = cmd_buff[1]; | 134 | u32 unk = rp.Pop<u32>(); |
| 136 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 135 | IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); |
| 137 | cmd_buff[2] = 0; | 136 | rb.Push(RESULT_SUCCESS); // No error |
| 138 | cmd_buff[3] = 0; | 137 | rb.Push<u32>(0); |
| 139 | cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID | 138 | rb.Push<u32>(0); |
| 140 | cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly | 139 | rb.Push(static_cast<u32>(AppletId::HomeMenu)); // Home menu AppID |
| 140 | rb.Push(static_cast<u32>(AppletId::Application)); // TODO(purpasmart96): Do this correctly | ||
| 141 | 141 | ||
| 142 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | 142 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | void IsRegistered(Service::Interface* self) { | 145 | void IsRegistered(Service::Interface* self) { |
| 146 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 146 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040 |
| 147 | u32 app_id = cmd_buff[1]; | 147 | u32 app_id = rp.Pop<u32>(); |
| 148 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 148 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 149 | rb.Push(RESULT_SUCCESS); // No error | ||
| 149 | 150 | ||
| 150 | // TODO(Subv): An application is considered "registered" if it has already called APT::Enable | 151 | // TODO(Subv): An application is considered "registered" if it has already called APT::Enable |
| 151 | // handle this properly once we implement multiprocess support. | 152 | // handle this properly once we implement multiprocess support. |
| 152 | cmd_buff[2] = 0; // Set to not registered by default | 153 | bool is_registered = false; // Set to not registered by default |
| 153 | 154 | ||
| 154 | if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { | 155 | if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { |
| 155 | cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0; | 156 | is_registered = HLE::Applets::IsLibraryAppletRunning(); |
| 156 | } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { | 157 | } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { |
| 157 | cmd_buff[2] = 1; // Set to registered | 158 | is_registered = true; // Set to registered |
| 158 | } | 159 | } |
| 160 | rb.Push(is_registered); | ||
| 161 | |||
| 159 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | 162 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |
| 160 | } | 163 | } |
| 161 | 164 | ||
| 162 | void InquireNotification(Service::Interface* self) { | 165 | void InquireNotification(Service::Interface* self) { |
| 163 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 166 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 1, 0); // 0xB0040 |
| 164 | u32 app_id = cmd_buff[1]; | 167 | u32 app_id = rp.Pop<u32>(); |
| 165 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 168 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 166 | cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type | 169 | rb.Push(RESULT_SUCCESS); // No error |
| 170 | rb.Push(static_cast<u32>(SignalType::None)); // Signal type | ||
| 167 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | 171 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |
| 168 | } | 172 | } |
| 169 | 173 | ||
| 170 | void SendParameter(Service::Interface* self) { | 174 | void SendParameter(Service::Interface* self) { |
| 171 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 175 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104 |
| 172 | u32 src_app_id = cmd_buff[1]; | 176 | u32 src_app_id = rp.Pop<u32>(); |
| 173 | u32 dst_app_id = cmd_buff[2]; | 177 | u32 dst_app_id = rp.Pop<u32>(); |
| 174 | u32 signal_type = cmd_buff[3]; | 178 | u32 signal_type = rp.Pop<u32>(); |
| 175 | u32 buffer_size = cmd_buff[4]; | 179 | u32 buffer_size = rp.Pop<u32>(); |
| 176 | u32 value = cmd_buff[5]; | 180 | Kernel::Handle handle = rp.PopHandle(); |
| 177 | u32 handle = cmd_buff[6]; | 181 | size_t size; |
| 178 | u32 size = cmd_buff[7]; | 182 | VAddr buffer = rp.PopStaticBuffer(&size); |
| 179 | u32 buffer = cmd_buff[8]; | ||
| 180 | 183 | ||
| 181 | std::shared_ptr<HLE::Applets::Applet> dest_applet = | 184 | std::shared_ptr<HLE::Applets::Applet> dest_applet = |
| 182 | HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); | 185 | HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); |
| 183 | 186 | ||
| 187 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 188 | |||
| 184 | if (dest_applet == nullptr) { | 189 | if (dest_applet == nullptr) { |
| 185 | LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); | 190 | LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); |
| 186 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | 191 | rb.Push<u32>(-1); // TODO(Subv): Find the right error code |
| 187 | return; | 192 | return; |
| 188 | } | 193 | } |
| 189 | 194 | ||
| @@ -195,88 +200,104 @@ void SendParameter(Service::Interface* self) { | |||
| 195 | param.buffer.resize(buffer_size); | 200 | param.buffer.resize(buffer_size); |
| 196 | Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); | 201 | Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); |
| 197 | 202 | ||
| 198 | cmd_buff[1] = dest_applet->ReceiveParameter(param).raw; | 203 | rb.Push(dest_applet->ReceiveParameter(param)); |
| 199 | 204 | ||
| 200 | LOG_WARNING( | 205 | LOG_WARNING(Service_APT, |
| 201 | Service_APT, | 206 | "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," |
| 202 | "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | 207 | "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", |
| 203 | "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", | 208 | src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); |
| 204 | src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer); | ||
| 205 | } | 209 | } |
| 206 | 210 | ||
| 207 | void ReceiveParameter(Service::Interface* self) { | 211 | void ReceiveParameter(Service::Interface* self) { |
| 208 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 212 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080 |
| 209 | u32 app_id = cmd_buff[1]; | 213 | u32 app_id = rp.Pop<u32>(); |
| 210 | u32 buffer_size = cmd_buff[2]; | 214 | u32 buffer_size = rp.Pop<u32>(); |
| 211 | VAddr buffer = cmd_buff[0x104 >> 2]; | 215 | |
| 212 | 216 | size_t static_buff_size; | |
| 213 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 217 | VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); |
| 214 | cmd_buff[2] = next_parameter.sender_id; | 218 | if (buffer_size > static_buff_size) |
| 215 | cmd_buff[3] = next_parameter.signal; // Signal type | 219 | LOG_WARNING( |
| 216 | cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size | 220 | Service_APT, |
| 217 | cmd_buff[5] = 0x10; | 221 | "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", |
| 218 | cmd_buff[6] = 0; | 222 | buffer_size, static_buff_size); |
| 219 | if (next_parameter.object != nullptr) | 223 | |
| 220 | cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | 224 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); |
| 221 | cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; | 225 | rb.Push(RESULT_SUCCESS); // No error |
| 222 | cmd_buff[8] = buffer; | 226 | rb.Push(next_parameter.sender_id); |
| 227 | rb.Push(next_parameter.signal); // Signal type | ||
| 228 | ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||
| 229 | rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size | ||
| 230 | |||
| 231 | rb.PushMoveHandles((next_parameter.object != nullptr) | ||
| 232 | ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom() | ||
| 233 | : 0); | ||
| 234 | rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); | ||
| 223 | 235 | ||
| 224 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); | 236 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); |
| 225 | 237 | ||
| 226 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 238 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); |
| 227 | } | 239 | } |
| 228 | 240 | ||
| 229 | void GlanceParameter(Service::Interface* self) { | 241 | void GlanceParameter(Service::Interface* self) { |
| 230 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 242 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080 |
| 231 | u32 app_id = cmd_buff[1]; | 243 | u32 app_id = rp.Pop<u32>(); |
| 232 | u32 buffer_size = cmd_buff[2]; | 244 | u32 buffer_size = rp.Pop<u32>(); |
| 233 | VAddr buffer = cmd_buff[0x104 >> 2]; | 245 | |
| 246 | size_t static_buff_size; | ||
| 247 | VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 248 | if (buffer_size > static_buff_size) | ||
| 249 | LOG_WARNING( | ||
| 250 | Service_APT, | ||
| 251 | "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 252 | buffer_size, static_buff_size); | ||
| 253 | |||
| 254 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||
| 255 | rb.Push(RESULT_SUCCESS); // No error | ||
| 256 | rb.Push(next_parameter.sender_id); | ||
| 257 | rb.Push(next_parameter.signal); // Signal type | ||
| 258 | ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||
| 259 | rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size | ||
| 234 | 260 | ||
| 235 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 261 | rb.PushCopyHandles((next_parameter.object != nullptr) |
| 236 | cmd_buff[2] = next_parameter.sender_id; | 262 | ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom() |
| 237 | cmd_buff[3] = next_parameter.signal; // Signal type | 263 | : 0); |
| 238 | cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size | 264 | rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); |
| 239 | cmd_buff[5] = 0x10; | ||
| 240 | cmd_buff[6] = 0; | ||
| 241 | if (next_parameter.object != nullptr) | ||
| 242 | cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | ||
| 243 | cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; | ||
| 244 | cmd_buff[8] = buffer; | ||
| 245 | 265 | ||
| 246 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), | 266 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); |
| 247 | std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size())); | ||
| 248 | 267 | ||
| 249 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 268 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); |
| 250 | } | 269 | } |
| 251 | 270 | ||
| 252 | void CancelParameter(Service::Interface* self) { | 271 | void CancelParameter(Service::Interface* self) { |
| 253 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 272 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100 |
| 254 | u32 flag1 = cmd_buff[1]; | ||
| 255 | u32 unk = cmd_buff[2]; | ||
| 256 | u32 flag2 = cmd_buff[3]; | ||
| 257 | u32 app_id = cmd_buff[4]; | ||
| 258 | 273 | ||
| 259 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 274 | u32 check_sender = rp.Pop<u32>(); |
| 260 | cmd_buff[2] = 1; // Set to Success | 275 | u32 sender_appid = rp.Pop<u32>(); |
| 276 | u32 check_receiver = rp.Pop<u32>(); | ||
| 277 | u32 receiver_appid = rp.Pop<u32>(); | ||
| 278 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 279 | rb.Push(RESULT_SUCCESS); // No error | ||
| 280 | rb.Push(true); // Set to Success | ||
| 261 | 281 | ||
| 262 | LOG_WARNING(Service_APT, | 282 | LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, " |
| 263 | "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1, | 283 | "check_receiver=0x%08X, receiver_appid=0x%08X", |
| 264 | unk, flag2, app_id); | 284 | check_sender, sender_appid, check_receiver, receiver_appid); |
| 265 | } | 285 | } |
| 266 | 286 | ||
| 267 | void PrepareToStartApplication(Service::Interface* self) { | 287 | void PrepareToStartApplication(Service::Interface* self) { |
| 268 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 288 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x15, 5, 0); // 0x00150140 |
| 269 | u32 title_info1 = cmd_buff[1]; | 289 | u32 title_info1 = rp.Pop<u32>(); |
| 270 | u32 title_info2 = cmd_buff[2]; | 290 | u32 title_info2 = rp.Pop<u32>(); |
| 271 | u32 title_info3 = cmd_buff[3]; | 291 | u32 title_info3 = rp.Pop<u32>(); |
| 272 | u32 title_info4 = cmd_buff[4]; | 292 | u32 title_info4 = rp.Pop<u32>(); |
| 273 | u32 flags = cmd_buff[5]; | 293 | u32 flags = rp.Pop<u32>(); |
| 274 | 294 | ||
| 275 | if (flags & 0x00000100) { | 295 | if (flags & 0x00000100) { |
| 276 | unknown_ns_state_field = 1; | 296 | unknown_ns_state_field = 1; |
| 277 | } | 297 | } |
| 278 | 298 | ||
| 279 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 299 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 300 | rb.Push(RESULT_SUCCESS); // No error | ||
| 280 | 301 | ||
| 281 | LOG_WARNING(Service_APT, | 302 | LOG_WARNING(Service_APT, |
| 282 | "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," | 303 | "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," |
| @@ -285,172 +306,188 @@ void PrepareToStartApplication(Service::Interface* self) { | |||
| 285 | } | 306 | } |
| 286 | 307 | ||
| 287 | void StartApplication(Service::Interface* self) { | 308 | void StartApplication(Service::Interface* self) { |
| 288 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 309 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 3, 4); // 0x001B00C4 |
| 289 | u32 buffer1_size = cmd_buff[1]; | 310 | u32 buffer1_size = rp.Pop<u32>(); |
| 290 | u32 buffer2_size = cmd_buff[2]; | 311 | u32 buffer2_size = rp.Pop<u32>(); |
| 291 | u32 flag = cmd_buff[3]; | 312 | u32 flag = rp.Pop<u32>(); |
| 292 | u32 size1 = cmd_buff[4]; | 313 | size_t size1; |
| 293 | u32 buffer1_ptr = cmd_buff[5]; | 314 | VAddr buffer1_ptr = rp.PopStaticBuffer(&size1); |
| 294 | u32 size2 = cmd_buff[6]; | 315 | size_t size2; |
| 295 | u32 buffer2_ptr = cmd_buff[7]; | 316 | VAddr buffer2_ptr = rp.PopStaticBuffer(&size2); |
| 296 | 317 | ||
| 297 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 318 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 319 | rb.Push(RESULT_SUCCESS); // No error | ||
| 298 | 320 | ||
| 299 | LOG_WARNING(Service_APT, | 321 | LOG_WARNING(Service_APT, |
| 300 | "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," | 322 | "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," |
| 301 | "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X", | 323 | "size1=0x%08zX, buffer1_ptr=0x%08X, size2=0x%08zX, buffer2_ptr=0x%08X", |
| 302 | buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); | 324 | buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); |
| 303 | } | 325 | } |
| 304 | 326 | ||
| 305 | void AppletUtility(Service::Interface* self) { | 327 | void AppletUtility(Service::Interface* self) { |
| 306 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 328 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4B, 3, 2); // 0x004B00C2 |
| 307 | 329 | ||
| 308 | // These are from 3dbrew - I'm not really sure what they're used for. | 330 | // These are from 3dbrew - I'm not really sure what they're used for. |
| 309 | u32 command = cmd_buff[1]; | 331 | u32 utility_command = rp.Pop<u32>(); |
| 310 | u32 buffer1_size = cmd_buff[2]; | 332 | u32 input_size = rp.Pop<u32>(); |
| 311 | u32 buffer2_size = cmd_buff[3]; | 333 | u32 output_size = rp.Pop<u32>(); |
| 312 | u32 buffer1_addr = cmd_buff[5]; | 334 | VAddr input_addr = rp.PopStaticBuffer(); |
| 313 | u32 buffer2_addr = cmd_buff[65]; | 335 | |
| 336 | VAddr output_addr = rp.PeekStaticBuffer(0); | ||
| 314 | 337 | ||
| 315 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 338 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 339 | rb.Push(RESULT_SUCCESS); // No error | ||
| 316 | 340 | ||
| 317 | LOG_WARNING(Service_APT, | 341 | LOG_WARNING(Service_APT, |
| 318 | "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " | 342 | "(STUBBED) called command=0x%08X, input_size=0x%08X, output_size=0x%08X, " |
| 319 | "buffer1_addr=0x%08X, buffer2_addr=0x%08X", | 343 | "input_addr=0x%08X, output_addr=0x%08X", |
| 320 | command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr); | 344 | utility_command, input_size, output_size, input_addr, output_addr); |
| 321 | } | 345 | } |
| 322 | 346 | ||
| 323 | void SetAppCpuTimeLimit(Service::Interface* self) { | 347 | void SetAppCpuTimeLimit(Service::Interface* self) { |
| 324 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 348 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4F, 2, 0); // 0x4F0080 |
| 325 | u32 value = cmd_buff[1]; | 349 | u32 value = rp.Pop<u32>(); |
| 326 | cpu_percent = cmd_buff[2]; | 350 | cpu_percent = rp.Pop<u32>(); |
| 327 | 351 | ||
| 328 | if (value != 1) { | 352 | if (value != 1) { |
| 329 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | 353 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); |
| 330 | } | 354 | } |
| 331 | 355 | ||
| 332 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 356 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 357 | rb.Push(RESULT_SUCCESS); // No error | ||
| 333 | 358 | ||
| 334 | LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); | 359 | LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); |
| 335 | } | 360 | } |
| 336 | 361 | ||
| 337 | void GetAppCpuTimeLimit(Service::Interface* self) { | 362 | void GetAppCpuTimeLimit(Service::Interface* self) { |
| 338 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 363 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x50, 1, 0); // 0x500040 |
| 339 | u32 value = cmd_buff[1]; | 364 | u32 value = rp.Pop<u32>(); |
| 340 | 365 | ||
| 341 | if (value != 1) { | 366 | if (value != 1) { |
| 342 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | 367 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); |
| 343 | } | 368 | } |
| 344 | 369 | ||
| 345 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 370 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 346 | cmd_buff[2] = cpu_percent; | 371 | rb.Push(RESULT_SUCCESS); // No error |
| 372 | rb.Push(cpu_percent); | ||
| 347 | 373 | ||
| 348 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); | 374 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); |
| 349 | } | 375 | } |
| 350 | 376 | ||
| 351 | void PrepareToStartLibraryApplet(Service::Interface* self) { | 377 | void PrepareToStartLibraryApplet(Service::Interface* self) { |
| 352 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 378 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 1, 0); // 0x180040 |
| 353 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | 379 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 380 | |||
| 381 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 354 | auto applet = HLE::Applets::Applet::Get(applet_id); | 382 | auto applet = HLE::Applets::Applet::Get(applet_id); |
| 355 | if (applet) { | 383 | if (applet) { |
| 356 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | 384 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); |
| 357 | cmd_buff[1] = RESULT_SUCCESS.raw; | 385 | rb.Push(RESULT_SUCCESS); |
| 358 | } else { | 386 | } else { |
| 359 | cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; | 387 | rb.Push(HLE::Applets::Applet::Create(applet_id)); |
| 360 | } | 388 | } |
| 361 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | 389 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |
| 362 | } | 390 | } |
| 363 | 391 | ||
| 364 | void PreloadLibraryApplet(Service::Interface* self) { | 392 | void PreloadLibraryApplet(Service::Interface* self) { |
| 365 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 393 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x16, 1, 0); // 0x160040 |
| 366 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | 394 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 395 | |||
| 396 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 367 | auto applet = HLE::Applets::Applet::Get(applet_id); | 397 | auto applet = HLE::Applets::Applet::Get(applet_id); |
| 368 | if (applet) { | 398 | if (applet) { |
| 369 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | 399 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); |
| 370 | cmd_buff[1] = RESULT_SUCCESS.raw; | 400 | rb.Push(RESULT_SUCCESS); |
| 371 | } else { | 401 | } else { |
| 372 | cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; | 402 | rb.Push(HLE::Applets::Applet::Create(applet_id)); |
| 373 | } | 403 | } |
| 374 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | 404 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |
| 375 | } | 405 | } |
| 376 | 406 | ||
| 377 | void StartLibraryApplet(Service::Interface* self) { | 407 | void StartLibraryApplet(Service::Interface* self) { |
| 378 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 408 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 2, 4); // 0x1E0084 |
| 379 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | 409 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 380 | std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); | 410 | std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); |
| 381 | 411 | ||
| 382 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | 412 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |
| 383 | 413 | ||
| 384 | if (applet == nullptr) { | 414 | if (applet == nullptr) { |
| 385 | LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); | 415 | LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); |
| 386 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | 416 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0, false); |
| 417 | rb.Push<u32>(-1); // TODO(Subv): Find the right error code | ||
| 387 | return; | 418 | return; |
| 388 | } | 419 | } |
| 389 | 420 | ||
| 390 | size_t buffer_size = cmd_buff[2]; | 421 | size_t buffer_size = rp.Pop<u32>(); |
| 391 | VAddr buffer_addr = cmd_buff[6]; | 422 | Kernel::Handle handle = rp.PopHandle(); |
| 423 | VAddr buffer_addr = rp.PopStaticBuffer(); | ||
| 392 | 424 | ||
| 393 | AppletStartupParameter parameter; | 425 | AppletStartupParameter parameter; |
| 394 | parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]); | 426 | parameter.object = Kernel::g_handle_table.GetGeneric(handle); |
| 395 | parameter.buffer.resize(buffer_size); | 427 | parameter.buffer.resize(buffer_size); |
| 396 | Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); | 428 | Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); |
| 397 | 429 | ||
| 398 | cmd_buff[1] = applet->Start(parameter).raw; | 430 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 431 | rb.Push(applet->Start(parameter)); | ||
| 399 | } | 432 | } |
| 400 | 433 | ||
| 401 | void CancelLibraryApplet(Service::Interface* self) { | 434 | void CancelLibraryApplet(Service::Interface* self) { |
| 402 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 435 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3B, 1, 0); // 0x003B0040 |
| 403 | u32 exiting = cmd_buff[1] & 0xFF; | 436 | bool exiting = rp.Pop<bool>(); |
| 404 | 437 | ||
| 405 | cmd_buff[1] = 1; // TODO: Find the return code meaning | 438 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 439 | rb.Push<u32>(1); // TODO: Find the return code meaning | ||
| 406 | 440 | ||
| 407 | LOG_WARNING(Service_APT, "(STUBBED) called exiting=%u", exiting); | 441 | LOG_WARNING(Service_APT, "(STUBBED) called exiting=%d", exiting); |
| 408 | } | 442 | } |
| 409 | 443 | ||
| 410 | void SetScreenCapPostPermission(Service::Interface* self) { | 444 | void SetScreenCapPostPermission(Service::Interface* self) { |
| 411 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 445 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x55, 1, 0); // 0x00550040 |
| 412 | 446 | ||
| 413 | screen_capture_post_permission = static_cast<ScreencapPostPermission>(cmd_buff[1] & 0xF); | 447 | screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); |
| 414 | 448 | ||
| 415 | cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0); | 449 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 416 | cmd_buff[1] = RESULT_SUCCESS.raw; | 450 | rb.Push(RESULT_SUCCESS); // No error |
| 417 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | 451 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", |
| 418 | screen_capture_post_permission); | 452 | screen_capture_post_permission); |
| 419 | } | 453 | } |
| 420 | 454 | ||
| 421 | void GetScreenCapPostPermission(Service::Interface* self) { | 455 | void GetScreenCapPostPermission(Service::Interface* self) { |
| 422 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 456 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x56, 0, 0); // 0x00560000 |
| 423 | 457 | ||
| 424 | cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0); | 458 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 425 | cmd_buff[1] = RESULT_SUCCESS.raw; | 459 | rb.Push(RESULT_SUCCESS); // No error |
| 426 | cmd_buff[2] = static_cast<u32>(screen_capture_post_permission); | 460 | rb.Push(static_cast<u32>(screen_capture_post_permission)); |
| 427 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | 461 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", |
| 428 | screen_capture_post_permission); | 462 | screen_capture_post_permission); |
| 429 | } | 463 | } |
| 430 | 464 | ||
| 431 | void GetAppletInfo(Service::Interface* self) { | 465 | void GetAppletInfo(Service::Interface* self) { |
| 432 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 466 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x6, 1, 0); // 0x60040 |
| 433 | auto app_id = static_cast<AppletId>(cmd_buff[1]); | 467 | auto app_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 434 | 468 | ||
| 435 | if (auto applet = HLE::Applets::Applet::Get(app_id)) { | 469 | if (auto applet = HLE::Applets::Applet::Get(app_id)) { |
| 436 | // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] | 470 | // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] |
| 437 | cmd_buff[1] = RESULT_SUCCESS.raw; | 471 | IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); |
| 438 | cmd_buff[4] = static_cast<u32>(Service::FS::MediaType::NAND); | 472 | rb.Push(RESULT_SUCCESS); |
| 439 | cmd_buff[5] = 1; // Registered | 473 | u64 title_id = 0; |
| 440 | cmd_buff[6] = 1; // Loaded | 474 | rb.Push(title_id); |
| 441 | cmd_buff[7] = 0; // Applet Attributes | 475 | rb.Push(static_cast<u32>(Service::FS::MediaType::NAND)); |
| 476 | rb.Push(true); // Registered | ||
| 477 | rb.Push(true); // Loaded | ||
| 478 | rb.Push<u32>(0); // Applet Attributes | ||
| 442 | } else { | 479 | } else { |
| 443 | cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, | 480 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 444 | ErrorSummary::NotFound, ErrorLevel::Status) | 481 | rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, |
| 445 | .raw; | 482 | ErrorLevel::Status)); |
| 446 | } | 483 | } |
| 447 | LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); | 484 | LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); |
| 448 | } | 485 | } |
| 449 | 486 | ||
| 450 | void GetStartupArgument(Service::Interface* self) { | 487 | void GetStartupArgument(Service::Interface* self) { |
| 451 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 488 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x51, 2, 0); // 0x00510080 |
| 452 | u32 parameter_size = cmd_buff[1]; | 489 | u32 parameter_size = rp.Pop<u32>(); |
| 453 | StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]); | 490 | StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>()); |
| 454 | 491 | ||
| 455 | if (parameter_size >= 0x300) { | 492 | if (parameter_size >= 0x300) { |
| 456 | LOG_ERROR( | 493 | LOG_ERROR( |
| @@ -460,7 +497,14 @@ void GetStartupArgument(Service::Interface* self) { | |||
| 460 | return; | 497 | return; |
| 461 | } | 498 | } |
| 462 | 499 | ||
| 463 | u32 addr = cmd_buff[65]; | 500 | size_t static_buff_size; |
| 501 | VAddr addr = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 502 | if (parameter_size > static_buff_size) | ||
| 503 | LOG_WARNING( | ||
| 504 | Service_APT, | ||
| 505 | "parameter_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 506 | parameter_size, static_buff_size); | ||
| 507 | |||
| 464 | if (addr && parameter_size) { | 508 | if (addr && parameter_size) { |
| 465 | Memory::ZeroBlock(addr, parameter_size); | 509 | Memory::ZeroBlock(addr, parameter_size); |
| 466 | } | 510 | } |
| @@ -468,8 +512,10 @@ void GetStartupArgument(Service::Interface* self) { | |||
| 468 | LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", | 512 | LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", |
| 469 | startup_argument_type, parameter_size); | 513 | startup_argument_type, parameter_size); |
| 470 | 514 | ||
| 471 | cmd_buff[1] = RESULT_SUCCESS.raw; | 515 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); |
| 472 | cmd_buff[2] = 0; | 516 | rb.Push(RESULT_SUCCESS); |
| 517 | rb.Push<u32>(0); | ||
| 518 | rb.PushStaticBuffer(addr, parameter_size, 0); | ||
| 473 | } | 519 | } |
| 474 | 520 | ||
| 475 | void Wrap(Service::Interface* self) { | 521 | void Wrap(Service::Interface* self) { |
| @@ -574,25 +620,25 @@ void Unwrap(Service::Interface* self) { | |||
| 574 | } | 620 | } |
| 575 | 621 | ||
| 576 | void CheckNew3DSApp(Service::Interface* self) { | 622 | void CheckNew3DSApp(Service::Interface* self) { |
| 577 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 623 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x101, 0, 0); // 0x01010000 |
| 578 | 624 | ||
| 625 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 579 | if (unknown_ns_state_field) { | 626 | if (unknown_ns_state_field) { |
| 580 | cmd_buff[1] = RESULT_SUCCESS.raw; | 627 | rb.Push(RESULT_SUCCESS); |
| 581 | cmd_buff[2] = 0; | 628 | rb.Push<u32>(0); |
| 582 | } else { | 629 | } else { |
| 583 | PTM::CheckNew3DS(self); | 630 | PTM::CheckNew3DS(rb); |
| 584 | } | 631 | } |
| 585 | 632 | ||
| 586 | cmd_buff[0] = IPC::MakeHeader(0x101, 2, 0); | ||
| 587 | LOG_WARNING(Service_APT, "(STUBBED) called"); | 633 | LOG_WARNING(Service_APT, "(STUBBED) called"); |
| 588 | } | 634 | } |
| 589 | 635 | ||
| 590 | void CheckNew3DS(Service::Interface* self) { | 636 | void CheckNew3DS(Service::Interface* self) { |
| 591 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 637 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x102, 0, 0); // 0x01020000 |
| 638 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 592 | 639 | ||
| 593 | PTM::CheckNew3DS(self); | 640 | PTM::CheckNew3DS(rb); |
| 594 | 641 | ||
| 595 | cmd_buff[0] = IPC::MakeHeader(0x102, 2, 0); | ||
| 596 | LOG_WARNING(Service_APT, "(STUBBED) called"); | 642 | LOG_WARNING(Service_APT, "(STUBBED) called"); |
| 597 | } | 643 | } |
| 598 | 644 | ||
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 2542f8303..e373ed47a 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp | |||
| @@ -92,8 +92,7 @@ void GetSoftwareClosedFlag(Service::Interface* self) { | |||
| 92 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | 92 | LOG_WARNING(Service_PTM, "(STUBBED) called"); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void CheckNew3DS(Service::Interface* self) { | 95 | void CheckNew3DS(IPC::RequestBuilder& rb) { |
| 96 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 97 | const bool is_new_3ds = Settings::values.is_new_3ds; | 96 | const bool is_new_3ds = Settings::values.is_new_3ds; |
| 98 | 97 | ||
| 99 | if (is_new_3ds) { | 98 | if (is_new_3ds) { |
| @@ -101,12 +100,17 @@ void CheckNew3DS(Service::Interface* self) { | |||
| 101 | "settings. Citra does not fully support New 3DS emulation yet!"); | 100 | "settings. Citra does not fully support New 3DS emulation yet!"); |
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | cmd_buff[1] = RESULT_SUCCESS.raw; | 103 | rb.Push(RESULT_SUCCESS); |
| 105 | cmd_buff[2] = is_new_3ds ? 1 : 0; | 104 | rb.Push(is_new_3ds); |
| 106 | 105 | ||
| 107 | LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); | 106 | LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); |
| 108 | } | 107 | } |
| 109 | 108 | ||
| 109 | void CheckNew3DS(Service::Interface* self) { | ||
| 110 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x40A, 0, 0); // 0x040A0000 | ||
| 111 | CheckNew3DS(rb); | ||
| 112 | } | ||
| 113 | |||
| 110 | void Init() { | 114 | void Init() { |
| 111 | AddService(new PTM_Gets); | 115 | AddService(new PTM_Gets); |
| 112 | AddService(new PTM_Play); | 116 | AddService(new PTM_Play); |
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index a1a628012..683fb445b 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 8 | 9 | ||
| 9 | namespace Service { | 10 | namespace Service { |
| 10 | 11 | ||
| @@ -97,6 +98,7 @@ void GetSoftwareClosedFlag(Interface* self); | |||
| 97 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. | 98 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. |
| 98 | */ | 99 | */ |
| 99 | void CheckNew3DS(Interface* self); | 100 | void CheckNew3DS(Interface* self); |
| 101 | void CheckNew3DS(IPC::RequestBuilder& rb); | ||
| 100 | 102 | ||
| 101 | /// Initialize the PTM service | 103 | /// Initialize the PTM service |
| 102 | void Init(); | 104 | void Init(); |
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 907d9c8fa..c0837d49d 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp | |||
| @@ -189,11 +189,9 @@ static void SetSpacialDithering(Interface* self) { | |||
| 189 | * 2 : u8, 0 = Disabled, 1 = Enabled | 189 | * 2 : u8, 0 = Disabled, 1 = Enabled |
| 190 | */ | 190 | */ |
| 191 | static void GetSpacialDithering(Interface* self) { | 191 | static void GetSpacialDithering(Interface* self) { |
| 192 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 192 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0xA, 2, 0); |
| 193 | 193 | rb.Push(RESULT_SUCCESS); | |
| 194 | cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); | 194 | rb.Push(spacial_dithering_enabled != 0); |
| 195 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 196 | cmd_buff[2] = spacial_dithering_enabled; | ||
| 197 | 195 | ||
| 198 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | 196 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); |
| 199 | } | 197 | } |