Fix SDIO HLE writing garbage to memory.

When servicing a write-register request, it wrote the contents to the
register offset plus 0x8d070000, which corresponds to the actual
hardware registers, presumably in case the application wanted to read
them directly rather than with a read-register request.  WriteToHardware
doesn't handle cached writes to registers, so it decided the address was
RAM, applied RAM_MASK, and happily wrote the register contents to
0x81070000, causing random corruption.  Since the PPC does not normally
have access to those registers, there is no reason to be doing this in
the first place.  Use a member to store these values instead.

(Also add a proper DoState.)
This commit is contained in:
comex 2013-09-09 23:33:42 -04:00
parent a3ef35a1bf
commit 4add0f55e0
2 changed files with 44 additions and 12 deletions

View file

@ -22,6 +22,19 @@ CWII_IPC_HLE_Device_sdio_slot0::CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, co
, m_Card(NULL)
{}
void CWII_IPC_HLE_Device_sdio_slot0::DoState(PointerWrap& p)
{
DoStateShared(p);
if (p.GetMode() == PointerWrap::MODE_READ)
{
OpenInternal();
}
p.Do(m_Status);
p.Do(m_BlockLength);
p.Do(m_BusWidth);
p.Do(m_Registers);
}
void CWII_IPC_HLE_Device_sdio_slot0::EventNotify()
{
if ((SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_INSERT) ||
@ -34,10 +47,8 @@ void CWII_IPC_HLE_Device_sdio_slot0::EventNotify()
}
}
bool CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode)
void CWII_IPC_HLE_Device_sdio_slot0::OpenInternal()
{
INFO_LOG(WII_IPC_SD, "Open");
const std::string filename = File::GetUserPath(D_WIIUSER_IDX) + "sd.raw";
m_Card.Open(filename, "r+b");
if (!m_Card)
@ -53,8 +64,16 @@ bool CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode)
ERROR_LOG(WII_IPC_SD, "Could not open SD Card image or create a new one, are you running from a read-only directory?");
}
}
}
bool CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode)
{
INFO_LOG(WII_IPC_SD, "Open");
OpenInternal();
Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4);
memset(m_Registers, 0, sizeof(m_Registers));
m_Active = true;
return true;
}
@ -96,20 +115,26 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR 0x%08x - 0x%08x", reg, val);
if (reg >= 0x200)
{
DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR out of range");
break;
}
if ((reg == HCR_CLOCKCONTROL) && (val & 1))
{
// Clock is set to oscillate, enable bit 1 to say it's stable
Memory::Write_U32(val | 2, SDIO_BASE + reg);
m_Registers[reg] = val | 2;
}
else if ((reg == HCR_SOFTWARERESET) && val)
{
// When a reset is specified, the register gets cleared
Memory::Write_U32(0, SDIO_BASE + reg);
m_Registers[reg] = 0;
}
else
{
// Default to just storing the new value
Memory::Write_U32(val, SDIO_BASE + reg);
m_Registers[reg] = val;
}
}
break;
@ -117,9 +142,16 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
case IOCTL_READHCR:
{
u32 reg = Memory::Read_U32(BufferIn);
u32 val = Memory::Read_U32(SDIO_BASE + reg);
if (reg >= 0x200)
{
DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR out of range");
break;
}
u32 val = m_Registers[reg];
DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR 0x%08x - 0x%08x", reg, val);
// Just reading the register
Memory::Write_U32(val, BufferOut);
}

View file

@ -15,6 +15,8 @@ public:
CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName);
virtual void DoState(PointerWrap& p);
bool Open(u32 _CommandAddress, u32 _Mode);
bool Close(u32 _CommandAddress, bool _bForce);
bool IOCtl(u32 _CommandAddress);
@ -24,11 +26,6 @@ public:
private:
enum
{
SDIO_BASE = 0x8d070000,
};
// SD Host Controller Registers
enum
{
@ -119,11 +116,14 @@ private:
u32 m_BlockLength;
u32 m_BusWidth;
u32 m_Registers[0x200/4];
File::IOFile m_Card;
u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize,
u32 BufferIn2, u32 BufferInSize2,
u32 _BufferOut, u32 BufferOutSize);
void OpenInternal();
};
#endif