DSP: Implement Pipe 2

Pipe 2 is a DSP pipe that is used to initialize both the DSP hardware (the
application signals to the DSP to initialize) and the application (the DSP
provides the memory location of structures in the shared memory region).
This commit is contained in:
MerryMage 2016-03-06 21:13:12 +00:00
parent 2d40891b45
commit 004991d79e
4 changed files with 346 additions and 78 deletions

View file

@ -58,10 +58,10 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
u32 addr = cmd_buff[1];
cmd_buff[1] = 0; // No error
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
LOG_TRACE(Service_DSP, "addr=0x%08X", addr);
LOG_DEBUG(Service_DSP, "addr=0x%08X", addr);
}
/**
@ -142,8 +142,7 @@ static void FlushDataCache(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X",
address, size, process);
LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process);
}
/**
@ -167,14 +166,14 @@ static void RegisterInterruptEvents(Service::Interface* self) {
if (evt) {
interrupt_events[std::make_pair(interrupt, channel)] = evt;
cmd_buff[1] = RESULT_SUCCESS.raw;
LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
} else {
cmd_buff[1] = -1;
LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
ASSERT(false); // This should really be handled at a IPC translation layer.
}
} else {
interrupt_events.erase(std::make_pair(interrupt, channel));
LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
}
}
@ -188,7 +187,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
static void SetSemaphore(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = 0; // No error
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_DSP, "(STUBBED) called");
}
@ -207,21 +206,12 @@ static void SetSemaphore(Service::Interface* self) {
static void WriteProcessPipe(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 channel = cmd_buff[1];
u32 size = cmd_buff[2];
u32 buffer = cmd_buff[4];
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
u32 size = cmd_buff[2];
u32 buffer = cmd_buff[4];
if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) {
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);
cmd_buff[1] = -1; // TODO
return;
}
if (!Memory::GetPointer(buffer)) {
LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
cmd_buff[1] = -1; // TODO
return;
}
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);
ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
std::vector<u8> message(size);
@ -229,11 +219,11 @@ static void WriteProcessPipe(Service::Interface* self) {
message[i] = Memory::Read8(buffer + i);
}
DSP::HLE::PipeWrite(channel, message);
DSP::HLE::PipeWrite(pipe, message);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
}
/**
@ -245,7 +235,7 @@ static void WriteProcessPipe(Service::Interface* self) {
* 1 : Pipe Number
* 2 : Unknown
* 3 : Size in bytes of read (observed only lower half word used)
* 0x41 : Virtual address to read from DSP pipe to in memory
* 0x41 : Virtual address of memory buffer to write pipe contents to
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Number of bytes read from pipe
@ -253,25 +243,82 @@ static void WriteProcessPipe(Service::Interface* self) {
static void ReadPipeIfPossible(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 pipe = cmd_buff[1];
u32 unk2 = cmd_buff[2];
u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
u32 unknown = cmd_buff[2];
u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size
VAddr addr = cmd_buff[0x41];
if (!Memory::GetPointer(addr)) {
LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr);
cmd_buff[1] = -1; // TODO
return;
ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
Memory::WriteBlock(addr, response.data(), response.size());
cmd_buff[2] = static_cast<u32>(response.size());
} else {
cmd_buff[2] = 0; // Return no data
}
std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
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]);
}
Memory::WriteBlock(addr, response.data(), response.size());
/**
* DSP_DSP::ReadPipe service function
* Inputs:
* 1 : Pipe Number
* 2 : Unknown
* 3 : Size in bytes of read (observed only lower half word used)
* 0x41 : Virtual address of memory buffer to write pipe contents to
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Number of bytes read from pipe
*/
static void ReadPipe(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = 0; // No error
cmd_buff[2] = (u32)response.size();
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
u32 unknown = cmd_buff[2];
u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size
VAddr addr = cmd_buff[0x41];
LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr);
ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
Memory::WriteBlock(addr, response.data(), response.size());
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = static_cast<u32>(response.size());
} else {
// No more data is in pipe. Hardware hangs in this case; this should never happen.
UNREACHABLE();
}
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]);
}
/**
* DSP_DSP::GetPipeReadableSize service function
* Inputs:
* 1 : Pipe Number
* 2 : Unknown
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Number of bytes readable from pipe
*/
static void GetPipeReadableSize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
u32 unknown = cmd_buff[2];
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = DSP::HLE::GetPipeReadableSize(pipe);
LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, cmd_buff[2]);
}
/**
@ -306,12 +353,73 @@ static void GetHeadphoneStatus(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0; // Not using headphones?
LOG_DEBUG(Service_DSP, "(STUBBED) called");
LOG_WARNING(Service_DSP, "(STUBBED) called");
}
/**
* DSP_DSP::RecvData service function
* This function reads a value out of a DSP register.
* Inputs:
* 1 : Register Number
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Value in the register
* Notes:
* This function has only been observed being called with a register number of 0.
*/
static void RecvData(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 register_number = cmd_buff[1];
ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
// Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept.
cmd_buff[1] = RESULT_SUCCESS.raw;
switch (DSP::HLE::GetDspState()) {
case DSP::HLE::DspState::On:
cmd_buff[2] = 0;
break;
case DSP::HLE::DspState::Off:
case DSP::HLE::DspState::Sleeping:
cmd_buff[2] = 1;
break;
default:
UNREACHABLE();
break;
}
LOG_DEBUG(Service_DSP, "register_number=%u", register_number);
}
/**
* DSP_DSP::RecvDataIsReady service function
* This function checks whether a DSP register is ready to be read.
* Inputs:
* 1 : Register Number
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : non-zero == ready
* Note:
* This function has only been observed being called with a register number of 0.
*/
static void RecvDataIsReady(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 register_number = cmd_buff[1];
ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 1; // Ready to read
LOG_DEBUG(Service_DSP, "register_number=%u", register_number);
}
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, nullptr, "RecvData"},
{0x00020040, nullptr, "RecvDataIsReady"},
{0x00010040, RecvData, "RecvData"},
{0x00020040, RecvDataIsReady, "RecvDataIsReady"},
{0x00030080, nullptr, "SendData"},
{0x00040040, nullptr, "SendDataIsEmpty"},
{0x000500C2, nullptr, "SendFifoEx"},
@ -323,8 +431,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
{0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
{0x000D0082, WriteProcessPipe, "WriteProcessPipe"},
{0x000E00C0, nullptr, "ReadPipe"},
{0x000F0080, nullptr, "GetPipeReadableSize"},
{0x000E00C0, ReadPipe, "ReadPipe"},
{0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"},
{0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
{0x001100C2, LoadComponent, "LoadComponent"},
{0x00120000, nullptr, "UnloadComponent"},