Merge pull request #13152 from Naim2000/sdlock

SDIO: report write lock status
This commit is contained in:
Jordan Woyak 2025-11-20 15:04:39 -06:00 committed by GitHub
commit 4f30aaf1ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 77 additions and 60 deletions

View File

@ -237,18 +237,23 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
case SEND_CSD: case SEND_CSD:
{ {
const std::array<u32, 4> csd = m_protocol == SDProtocol::V1 ? GetCSDv1() : GetCSDv2(); const std::array<u32, 4> csd = m_protocol == SDProtocol::V1 ? GetCSDv1() : GetCSDv2();
memory.CopyToEmuSwapped(buffer_out, csd.data(), csd.size() * sizeof(u32)); memory.Write_U32(csd[0], buffer_out + 12);
memory.Write_U32(csd[1], buffer_out + 8);
memory.Write_U32(csd[2], buffer_out + 4);
memory.Write_U32(csd[3], buffer_out + 0);
} }
break; break;
case ALL_SEND_CID: case ALL_SEND_CID:
case SEND_CID: case SEND_CID:
{
INFO_LOG_FMT(IOS_SD, "(ALL_)SEND_CID"); INFO_LOG_FMT(IOS_SD, "(ALL_)SEND_CID");
memory.Write_U32(0x80114d1c, buffer_out); memory.Write_U32(0x00D0444F, buffer_out + 12);
memory.Write_U32(0x80080000, buffer_out + 4); memory.Write_U32(0x4C504849, buffer_out + 8);
memory.Write_U32(0x8007b520, buffer_out + 8); memory.Write_U32(0x4E430403, buffer_out + 4);
memory.Write_U32(0x80080000, buffer_out + 12); memory.Write_U32(0xAC68006B, buffer_out + 0);
break; }
break;
case SET_BLOCKLEN: case SET_BLOCKLEN:
m_block_length = req.arg; m_block_length = req.arg;
@ -279,24 +284,21 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
INFO_LOG_FMT(IOS_SD, "{}Read {} Block(s) from {:#010x} bsize {} into {:#010x}!", INFO_LOG_FMT(IOS_SD, "{}Read {} Block(s) from {:#010x} bsize {} into {:#010x}!",
req.isDMA ? "DMA " : "", req.blocks, req.arg, req.bsize, req.addr); req.isDMA ? "DMA " : "", req.blocks, req.arg, req.bsize, req.addr);
if (m_card) const u32 size = req.bsize * req.blocks;
const u64 address = GetAddressFromRequest(req.arg);
if (!m_card.Seek(address, File::SeekOrigin::Begin))
ERROR_LOG_FMT(IOS_SD, "Seek failed");
if (m_card.ReadBytes(memory.GetPointerForRange(req.addr, size), size))
{ {
const u32 size = req.bsize * req.blocks; DEBUG_LOG_FMT(IOS_SD, "Outbuffer size {} got {}", rw_buffer_size, size);
const u64 address = GetAddressFromRequest(req.arg); }
else
if (!m_card.Seek(address, File::SeekOrigin::Begin)) {
ERROR_LOG_FMT(IOS_SD, "Seek failed"); ERROR_LOG_FMT(IOS_SD, "Read Failed - error: {}, eof: {}", std::ferror(m_card.GetHandle()),
std::feof(m_card.GetHandle()));
if (m_card.ReadBytes(memory.GetPointerForRange(req.addr, size), size)) ret = RET_FAIL;
{
DEBUG_LOG_FMT(IOS_SD, "Outbuffer size {} got {}", rw_buffer_size, size);
}
else
{
ERROR_LOG_FMT(IOS_SD, "Read Failed - error: {}, eof: {}", std::ferror(m_card.GetHandle()),
std::feof(m_card.GetHandle()));
ret = RET_FAIL;
}
} }
} }
memory.Write_U32(0x900, buffer_out); memory.Write_U32(0x900, buffer_out);
@ -309,7 +311,12 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
INFO_LOG_FMT(IOS_SD, "{}Write {} Block(s) from {:#010x} bsize {} to offset {:#010x}!", INFO_LOG_FMT(IOS_SD, "{}Write {} Block(s) from {:#010x} bsize {} to offset {:#010x}!",
req.isDMA ? "DMA " : "", req.blocks, req.addr, req.bsize, req.arg); req.isDMA ? "DMA " : "", req.blocks, req.addr, req.bsize, req.arg);
if (m_card && Config::Get(Config::MAIN_ALLOW_SD_WRITES)) if (!Config::Get(Config::MAIN_ALLOW_SD_WRITES))
{
ERROR_LOG_FMT(IOS_SD, "Write attempted while locked.");
ret = RET_LOCKED;
}
else
{ {
const u32 size = req.bsize * req.blocks; const u32 size = req.bsize * req.blocks;
const u64 address = GetAddressFromRequest(req.arg); const u64 address = GetAddressFromRequest(req.arg);
@ -465,34 +472,35 @@ std::optional<IPCReply> SDIOSlot0Device::SendCommand(const IOCtlRequest& request
IPCReply SDIOSlot0Device::GetStatus(const IOCtlRequest& request) IPCReply SDIOSlot0Device::GetStatus(const IOCtlRequest& request)
{ {
// Since IOS does the SD initialization itself, we just say we're always initialized. // Since IOS does the SD initialization itself, we just say we're always initialized.
if (m_card) if (m_card.GetSize() <= SDSC_MAX_SIZE)
{ {
if (m_card.GetSize() <= SDSC_MAX_SIZE) // No further initialization required.
m_status |= CARD_INITIALIZED;
}
else
{
// Some IOS versions support SDHC.
// Others will work if they are manually initialized (SEND_IF_COND)
if (m_sdhc_supported)
{ {
// No further initialization required. // All of the initialization is done internally by IOS, so we get to skip some steps.
m_status |= CARD_INITIALIZED; InitSDHC();
}
else
{
// Some IOS versions support SDHC.
// Others will work if they are manually initialized (SEND_IF_COND)
if (m_sdhc_supported)
{
// All of the initialization is done internally by IOS, so we get to skip some steps.
InitSDHC();
}
m_status |= CARD_SDHC;
} }
m_status |= CARD_SDHC;
} }
// Evaluate whether a card is currently inserted (config value). // Evaluate whether a card is currently inserted (config value).
// Make sure we don't modify m_status so we don't lose track of whether the card is SDHC. // Make sure we don't modify m_status so we don't lose track of whether the card is SDHC.
const bool sd_card_inserted = Config::Get(Config::MAIN_WII_SD_CARD); const bool sd_card_inserted = Config::Get(Config::MAIN_WII_SD_CARD);
const u32 status = sd_card_inserted ? (m_status | CARD_INSERTED) : CARD_NOT_EXIST; const bool sd_card_locked = !Config::Get(Config::MAIN_ALLOW_SD_WRITES);
const u32 status = sd_card_inserted ?
(m_status | CARD_INSERTED | (sd_card_locked ? CARD_LOCKED : 0)) :
CARD_NOT_EXIST;
INFO_LOG_FMT(IOS_SD, "IOCTL_GETSTATUS. Replying that {} card is {}{}", INFO_LOG_FMT(IOS_SD, "IOCTL_GETSTATUS. Replying that {} card is {}{}{}",
(status & CARD_SDHC) ? "SDHC" : "SD", (status & CARD_SDHC) ? "SDHC" : "SD",
(status & CARD_INSERTED) ? "inserted" : "not present", (status & CARD_INSERTED) ? "inserted" : "not present",
(status & CARD_LOCKED) ? " and locked" : "",
(status & CARD_INITIALIZED) ? " and initialized" : ""); (status & CARD_INITIALIZED) ? " and initialized" : "");
auto& system = GetSystem(); auto& system = GetSystem();
@ -543,9 +551,8 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv1() const
{ {
u64 size = m_card.GetSize(); u64 size = m_card.GetSize();
// 2048 bytes/sector // 512 bytes/sector. A 2GB card should only ever have to bump this up to 10
// We could make this dynamic to support a wider range of file sizes u32 read_bl_len = 9;
constexpr u32 read_bl_len = 11;
// size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len)) // size = (c_size + 1) * (1 << (2 + c_size_mult + read_bl_len))
u32 c_size_mult = 0; u32 c_size_mult = 0;
@ -554,7 +561,7 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv1() const
{ {
invalid_size |= size & 1; invalid_size |= size & 1;
size >>= 1; size >>= 1;
if (++c_size_mult >= 8 + 2 + read_bl_len) if (++c_size_mult > 7 + 2 + read_bl_len && ++read_bl_len > 15)
{ {
ERROR_LOG_FMT(IOS_SD, "SD Card is too big!"); ERROR_LOG_FMT(IOS_SD, "SD Card is too big!");
// Set max values // Set max values
@ -567,9 +574,14 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv1() const
const u32 c_size(size); const u32 c_size(size);
if (invalid_size) if (invalid_size)
{
WARN_LOG_FMT(IOS_SD, "SD Card size is invalid"); WARN_LOG_FMT(IOS_SD, "SD Card size is invalid");
}
else else
INFO_LOG_FMT(IOS_SD, "SD C_SIZE = {}, C_SIZE_MULT = {}", c_size, c_size_mult); {
INFO_LOG_FMT(IOS_SD, "SD C_SIZE = {}, C_SIZE_MULT = {}, READ_BL_LEN = {}", c_size, c_size_mult,
read_bl_len);
}
// 0b00 CSD_STRUCTURE (SDv1) // 0b00 CSD_STRUCTURE (SDv1)
// 0b000000 reserved // 0b000000 reserved
@ -578,7 +590,7 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv1() const
// 0b00110010 TRAN_SPEED (2.5 * 10 Mbit/s, max operating frequency) // 0b00110010 TRAN_SPEED (2.5 * 10 Mbit/s, max operating frequency)
// 0b010110110101 CCC // 0b010110110101 CCC
// 0b1111 READ_BL_LEN (2048 bytes) // 0b???? READ_BL_LEN
// 0b1 READ_BL_PARTIAL // 0b1 READ_BL_PARTIAL
// 0b0 WRITE_BL_MISALIGN // 0b0 WRITE_BL_MISALIGN
// 0b0 READ_BLK_MISALIGN // 0b0 READ_BLK_MISALIGN
@ -599,7 +611,7 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv1() const
// 0b0 WP_GRP_ENABLE (no write protection) // 0b0 WP_GRP_ENABLE (no write protection)
// 0b00 reserved // 0b00 reserved
// 0b001 R2W_FACTOR (write half as fast as read) // 0b001 R2W_FACTOR (write half as fast as read)
// 0b1111 WRITE_BL_LEN (= READ_BL_LEN) // 0b???? WRITE_BL_LEN (= READ_BL_LEN)
// 0b0 WRITE_BL_PARTIAL (no partial block writes) // 0b0 WRITE_BL_PARTIAL (no partial block writes)
// 0b00000 reserved // 0b00000 reserved
// 0b0 FILE_FORMAT_GRP (default) // 0b0 FILE_FORMAT_GRP (default)
@ -612,14 +624,16 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv1() const
// 0b1 reserved // 0b1 reserved
// TODO: CRC7 (but so far it looks like nobody is actually verifying this) // TODO: CRC7 (but so far it looks like nobody is actually verifying this)
constexpr u32 crc = 0; // constexpr u32 crc = 0; // The CRC doesn't seem to be sent any at all.
// Additionally, the entire response seems to be shifted to the right by 8 bits. Or the entire CSD
// was sent in reverse and IOS is only flipping the endianness of the four words.... It's weird.
// Form the csd using the description above // Form the csd using the description above
return {{ return {{
0x007f003, 0x000007f0,
0x5b5f8000 | (c_size >> 2), 0x035b5080 | (read_bl_len << 8) | (c_size >> 10),
0x3ffc7f80 | (c_size << 30) | (c_size_mult << 15), 0x003ffc7f | (c_size << 22) | (c_size_mult << 7),
0x07c04001 | (crc << 1), 0x80040040 | (read_bl_len << 18),
}}; }};
} }
@ -668,15 +682,16 @@ std::array<u32, 4> SDIOSlot0Device::GetCSDv2() const
// 0b0000000 CRC // 0b0000000 CRC
// 0b1 reserved // 0b1 reserved
// TODO: CRC7 (but so far it looks like nobody is actually verifying this) // TODO: CRC7 (but so far it looks like nobody is actually verifying this) // See GetCSDv1 notes
constexpr u32 crc = 0; // on this
// constexpr u32 crc = 0;
// Form the csd using the description above // Form the csd using the description above
return {{ return {{
0x400e005a, 0x00400e00,
0x5f590000 | (c_size >> 16), 0x5a5f5900,
0x00007f80 | (c_size << 16), 0x0000007f | (c_size << 8),
0x0a400001 | (crc << 1), 0x800a4000,
}}; }};
} }

View File

@ -63,6 +63,7 @@ private:
{ {
RET_OK, RET_OK,
RET_FAIL, RET_FAIL,
RET_LOCKED = -10,
RET_EVENT_REGISTER, // internal state only - not actually returned RET_EVENT_REGISTER, // internal state only - not actually returned
}; };
@ -70,7 +71,8 @@ private:
enum enum
{ {
CARD_NOT_EXIST = 0, CARD_NOT_EXIST = 0,
CARD_INSERTED = 1, CARD_INSERTED = 0x1,
CARD_LOCKED = 0x4,
CARD_INITIALIZED = 0x10000, CARD_INITIALIZED = 0x10000,
CARD_SDHC = 0x100000, CARD_SDHC = 0x100000,
}; };