diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/service/dsp_dsp.cpp | 194 |
1 files changed, 151 insertions, 43 deletions
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 22e85cfc6..3ba24d466 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp | |||
| @@ -58,10 +58,10 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) { | |||
| 58 | 58 | ||
| 59 | u32 addr = cmd_buff[1]; | 59 | u32 addr = cmd_buff[1]; |
| 60 | 60 | ||
| 61 | cmd_buff[1] = 0; // No error | 61 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 62 | cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); | 62 | cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); |
| 63 | 63 | ||
| 64 | LOG_TRACE(Service_DSP, "addr=0x%08X", addr); | 64 | LOG_DEBUG(Service_DSP, "addr=0x%08X", addr); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | /** | 67 | /** |
| @@ -142,8 +142,7 @@ static void FlushDataCache(Service::Interface* self) { | |||
| 142 | 142 | ||
| 143 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 143 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 144 | 144 | ||
| 145 | LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X", | 145 | LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process); |
| 146 | address, size, process); | ||
| 147 | } | 146 | } |
| 148 | 147 | ||
| 149 | /** | 148 | /** |
| @@ -167,14 +166,14 @@ static void RegisterInterruptEvents(Service::Interface* self) { | |||
| 167 | if (evt) { | 166 | if (evt) { |
| 168 | interrupt_events[std::make_pair(interrupt, channel)] = evt; | 167 | interrupt_events[std::make_pair(interrupt, channel)] = evt; |
| 169 | cmd_buff[1] = RESULT_SUCCESS.raw; | 168 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 170 | LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); | 169 | LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); |
| 171 | } else { | 170 | } else { |
| 172 | cmd_buff[1] = -1; | 171 | LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); |
| 173 | LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); | 172 | ASSERT(false); // This should really be handled at a IPC translation layer. |
| 174 | } | 173 | } |
| 175 | } else { | 174 | } else { |
| 176 | interrupt_events.erase(std::make_pair(interrupt, channel)); | 175 | interrupt_events.erase(std::make_pair(interrupt, channel)); |
| 177 | LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); | 176 | LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); |
| 178 | } | 177 | } |
| 179 | } | 178 | } |
| 180 | 179 | ||
| @@ -188,7 +187,7 @@ static void RegisterInterruptEvents(Service::Interface* self) { | |||
| 188 | static void SetSemaphore(Service::Interface* self) { | 187 | static void SetSemaphore(Service::Interface* self) { |
| 189 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 188 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 190 | 189 | ||
| 191 | cmd_buff[1] = 0; // No error | 190 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 192 | 191 | ||
| 193 | LOG_WARNING(Service_DSP, "(STUBBED) called"); | 192 | LOG_WARNING(Service_DSP, "(STUBBED) called"); |
| 194 | } | 193 | } |
| @@ -207,21 +206,12 @@ static void SetSemaphore(Service::Interface* self) { | |||
| 207 | static void WriteProcessPipe(Service::Interface* self) { | 206 | static void WriteProcessPipe(Service::Interface* self) { |
| 208 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 207 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 209 | 208 | ||
| 210 | u32 channel = cmd_buff[1]; | 209 | DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); |
| 211 | u32 size = cmd_buff[2]; | 210 | u32 size = cmd_buff[2]; |
| 212 | u32 buffer = cmd_buff[4]; | 211 | u32 buffer = cmd_buff[4]; |
| 213 | 212 | ||
| 214 | if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) { | 213 | ASSERT_MSG(IPC::StaticBufferDesc(size, 1) == cmd_buff[3], "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe, size, buffer); |
| 215 | LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). channel=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], channel, size, buffer); | 214 | ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); |
| 216 | cmd_buff[1] = -1; // TODO | ||
| 217 | return; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (!Memory::GetPointer(buffer)) { | ||
| 221 | LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); | ||
| 222 | cmd_buff[1] = -1; // TODO | ||
| 223 | return; | ||
| 224 | } | ||
| 225 | 215 | ||
| 226 | std::vector<u8> message(size); | 216 | std::vector<u8> message(size); |
| 227 | 217 | ||
| @@ -229,11 +219,11 @@ static void WriteProcessPipe(Service::Interface* self) { | |||
| 229 | message[i] = Memory::Read8(buffer + i); | 219 | message[i] = Memory::Read8(buffer + i); |
| 230 | } | 220 | } |
| 231 | 221 | ||
| 232 | DSP::HLE::PipeWrite(channel, message); | 222 | DSP::HLE::PipeWrite(pipe, message); |
| 233 | 223 | ||
| 234 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 224 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 235 | 225 | ||
| 236 | LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); | 226 | LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); |
| 237 | } | 227 | } |
| 238 | 228 | ||
| 239 | /** | 229 | /** |
| @@ -245,7 +235,7 @@ static void WriteProcessPipe(Service::Interface* self) { | |||
| 245 | * 1 : Pipe Number | 235 | * 1 : Pipe Number |
| 246 | * 2 : Unknown | 236 | * 2 : Unknown |
| 247 | * 3 : Size in bytes of read (observed only lower half word used) | 237 | * 3 : Size in bytes of read (observed only lower half word used) |
| 248 | * 0x41 : Virtual address to read from DSP pipe to in memory | 238 | * 0x41 : Virtual address of memory buffer to write pipe contents to |
| 249 | * Outputs: | 239 | * Outputs: |
| 250 | * 1 : Result of function, 0 on success, otherwise error code | 240 | * 1 : Result of function, 0 on success, otherwise error code |
| 251 | * 2 : Number of bytes read from pipe | 241 | * 2 : Number of bytes read from pipe |
| @@ -253,25 +243,82 @@ static void WriteProcessPipe(Service::Interface* self) { | |||
| 253 | static void ReadPipeIfPossible(Service::Interface* self) { | 243 | static void ReadPipeIfPossible(Service::Interface* self) { |
| 254 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 244 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 255 | 245 | ||
| 256 | u32 pipe = cmd_buff[1]; | 246 | DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); |
| 257 | u32 unk2 = cmd_buff[2]; | 247 | u32 unknown = cmd_buff[2]; |
| 258 | u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size | 248 | u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size |
| 259 | VAddr addr = cmd_buff[0x41]; | 249 | VAddr addr = cmd_buff[0x41]; |
| 260 | 250 | ||
| 261 | if (!Memory::GetPointer(addr)) { | 251 | ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); |
| 262 | LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); | 252 | |
| 263 | cmd_buff[1] = -1; // TODO | 253 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 264 | return; | 254 | if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { |
| 255 | std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); | ||
| 256 | |||
| 257 | Memory::WriteBlock(addr, response.data(), response.size()); | ||
| 258 | |||
| 259 | cmd_buff[2] = static_cast<u32>(response.size()); | ||
| 260 | } else { | ||
| 261 | cmd_buff[2] = 0; // Return no data | ||
| 265 | } | 262 | } |
| 266 | 263 | ||
| 267 | std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); | 264 | LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); |
| 265 | } | ||
| 268 | 266 | ||
| 269 | Memory::WriteBlock(addr, response.data(), response.size()); | 267 | /** |
| 268 | * DSP_DSP::ReadPipe service function | ||
| 269 | * Inputs: | ||
| 270 | * 1 : Pipe Number | ||
| 271 | * 2 : Unknown | ||
| 272 | * 3 : Size in bytes of read (observed only lower half word used) | ||
| 273 | * 0x41 : Virtual address of memory buffer to write pipe contents to | ||
| 274 | * Outputs: | ||
| 275 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 276 | * 2 : Number of bytes read from pipe | ||
| 277 | */ | ||
| 278 | static void ReadPipe(Service::Interface* self) { | ||
| 279 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 280 | |||
| 281 | DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); | ||
| 282 | u32 unknown = cmd_buff[2]; | ||
| 283 | u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size | ||
| 284 | VAddr addr = cmd_buff[0x41]; | ||
| 270 | 285 | ||
| 271 | cmd_buff[1] = 0; // No error | 286 | ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); |
| 272 | cmd_buff[2] = (u32)response.size(); | ||
| 273 | 287 | ||
| 274 | LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); | 288 | if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { |
| 289 | std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); | ||
| 290 | |||
| 291 | Memory::WriteBlock(addr, response.data(), response.size()); | ||
| 292 | |||
| 293 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 294 | cmd_buff[2] = static_cast<u32>(response.size()); | ||
| 295 | } else { | ||
| 296 | // No more data is in pipe. Hardware hangs in this case; this should never happen. | ||
| 297 | UNREACHABLE(); | ||
| 298 | } | ||
| 299 | |||
| 300 | LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | ||
| 304 | * DSP_DSP::GetPipeReadableSize service function | ||
| 305 | * Inputs: | ||
| 306 | * 1 : Pipe Number | ||
| 307 | * 2 : Unknown | ||
| 308 | * Outputs: | ||
| 309 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 310 | * 2 : Number of bytes readable from pipe | ||
| 311 | */ | ||
| 312 | static void GetPipeReadableSize(Service::Interface* self) { | ||
| 313 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 314 | |||
| 315 | DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); | ||
| 316 | u32 unknown = cmd_buff[2]; | ||
| 317 | |||
| 318 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 319 | cmd_buff[2] = DSP::HLE::GetPipeReadableSize(pipe); | ||
| 320 | |||
| 321 | LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, cmd_buff[2]); | ||
| 275 | } | 322 | } |
| 276 | 323 | ||
| 277 | /** | 324 | /** |
| @@ -306,12 +353,73 @@ static void GetHeadphoneStatus(Service::Interface* self) { | |||
| 306 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 353 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 307 | cmd_buff[2] = 0; // Not using headphones? | 354 | cmd_buff[2] = 0; // Not using headphones? |
| 308 | 355 | ||
| 309 | LOG_DEBUG(Service_DSP, "(STUBBED) called"); | 356 | LOG_WARNING(Service_DSP, "(STUBBED) called"); |
| 357 | } | ||
| 358 | |||
| 359 | /** | ||
| 360 | * DSP_DSP::RecvData service function | ||
| 361 | * This function reads a value out of a DSP register. | ||
| 362 | * Inputs: | ||
| 363 | * 1 : Register Number | ||
| 364 | * Outputs: | ||
| 365 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 366 | * 2 : Value in the register | ||
| 367 | * Notes: | ||
| 368 | * This function has only been observed being called with a register number of 0. | ||
| 369 | */ | ||
| 370 | static void RecvData(Service::Interface* self) { | ||
| 371 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 372 | |||
| 373 | u32 register_number = cmd_buff[1]; | ||
| 374 | |||
| 375 | ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); | ||
| 376 | |||
| 377 | // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept. | ||
| 378 | |||
| 379 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 380 | switch (DSP::HLE::GetDspState()) { | ||
| 381 | case DSP::HLE::DspState::On: | ||
| 382 | cmd_buff[2] = 0; | ||
| 383 | break; | ||
| 384 | case DSP::HLE::DspState::Off: | ||
| 385 | case DSP::HLE::DspState::Sleeping: | ||
| 386 | cmd_buff[2] = 1; | ||
| 387 | break; | ||
| 388 | default: | ||
| 389 | UNREACHABLE(); | ||
| 390 | break; | ||
| 391 | } | ||
| 392 | |||
| 393 | LOG_DEBUG(Service_DSP, "register_number=%u", register_number); | ||
| 394 | } | ||
| 395 | |||
| 396 | /** | ||
| 397 | * DSP_DSP::RecvDataIsReady service function | ||
| 398 | * This function checks whether a DSP register is ready to be read. | ||
| 399 | * Inputs: | ||
| 400 | * 1 : Register Number | ||
| 401 | * Outputs: | ||
| 402 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 403 | * 2 : non-zero == ready | ||
| 404 | * Note: | ||
| 405 | * This function has only been observed being called with a register number of 0. | ||
| 406 | */ | ||
| 407 | static void RecvDataIsReady(Service::Interface* self) { | ||
| 408 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 409 | |||
| 410 | u32 register_number = cmd_buff[1]; | ||
| 411 | |||
| 412 | ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); | ||
| 413 | |||
| 414 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 415 | cmd_buff[2] = 1; // Ready to read | ||
| 416 | |||
| 417 | LOG_DEBUG(Service_DSP, "register_number=%u", register_number); | ||
| 310 | } | 418 | } |
| 311 | 419 | ||
| 312 | const Interface::FunctionInfo FunctionTable[] = { | 420 | const Interface::FunctionInfo FunctionTable[] = { |
| 313 | {0x00010040, nullptr, "RecvData"}, | 421 | {0x00010040, RecvData, "RecvData"}, |
| 314 | {0x00020040, nullptr, "RecvDataIsReady"}, | 422 | {0x00020040, RecvDataIsReady, "RecvDataIsReady"}, |
| 315 | {0x00030080, nullptr, "SendData"}, | 423 | {0x00030080, nullptr, "SendData"}, |
| 316 | {0x00040040, nullptr, "SendDataIsEmpty"}, | 424 | {0x00040040, nullptr, "SendDataIsEmpty"}, |
| 317 | {0x000500C2, nullptr, "SendFifoEx"}, | 425 | {0x000500C2, nullptr, "SendFifoEx"}, |
| @@ -323,8 +431,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 323 | {0x000B0000, nullptr, "CheckSemaphoreRequest"}, | 431 | {0x000B0000, nullptr, "CheckSemaphoreRequest"}, |
| 324 | {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, | 432 | {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, |
| 325 | {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, | 433 | {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, |
| 326 | {0x000E00C0, nullptr, "ReadPipe"}, | 434 | {0x000E00C0, ReadPipe, "ReadPipe"}, |
| 327 | {0x000F0080, nullptr, "GetPipeReadableSize"}, | 435 | {0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"}, |
| 328 | {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, | 436 | {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, |
| 329 | {0x001100C2, LoadComponent, "LoadComponent"}, | 437 | {0x001100C2, LoadComponent, "LoadComponent"}, |
| 330 | {0x00120000, nullptr, "UnloadComponent"}, | 438 | {0x00120000, nullptr, "UnloadComponent"}, |