SDHC and SDXC memory commands always transfer 512-byte blocks regardless
of the length selected by CMD16. QEMU stores that selected length for
LOCK_UNLOCK but also used it directly for several memory command paths.
Route single- and multi-block memory sizing through the existing helper
that distinguishes high-capacity cards from SDSC.
This lets PolarFire SoC HSS validate the complete GPT header and locate
its boot partition instead of receiving only the eight-byte signature.
Fixes: 2d7adea4fe57 ("hw/sd: Support SDHC size cards")
Cc: [email protected]
Signed-off-by: Bin Meng <[email protected]>
---
hw/sd/sd.c | 43 +++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 18 deletions(-)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index a30c541df0..7832117a58 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1975,18 +1975,20 @@ static sd_rsp_type_t sd_cmd_SET_BLOCKLEN(SDState *sd,
SDRequest req)
static sd_rsp_type_t sd_cmd_READ_SINGLE_BLOCK(SDState *sd, SDRequest req)
{
uint64_t addr;
+ uint32_t blk_len;
if (sd->state != sd_transfer_state) {
return sd_invalid_state_for_cmd(sd, req);
}
+ blk_len = sd_blk_len(sd);
addr = sd_req_get_address(sd, req);
- if (!address_in_range(sd, "READ_SINGLE_BLOCK", addr, sd->blk_len)) {
+ if (!address_in_range(sd, "READ_SINGLE_BLOCK", addr, blk_len)) {
return sd_r1;
}
- sd_blk_read(sd, addr, sd->blk_len);
- return sd_cmd_to_sendingdata(sd, req, addr, NULL, sd->blk_len);
+ sd_blk_read(sd, addr, blk_len);
+ return sd_cmd_to_sendingdata(sd, req, addr, NULL, blk_len);
}
/* CMD19 */
@@ -2025,13 +2027,15 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState
*sd, SDRequest req)
static sd_rsp_type_t sd_cmd_WRITE_SINGLE_BLOCK(SDState *sd, SDRequest req)
{
uint64_t addr;
+ uint32_t blk_len;
if (sd->state != sd_transfer_state) {
return sd_invalid_state_for_cmd(sd, req);
}
+ blk_len = sd_blk_len(sd);
addr = sd_req_get_address(sd, req);
- if (!address_in_range(sd, "WRITE_SINGLE_BLOCK", addr, sd->blk_len)) {
+ if (!address_in_range(sd, "WRITE_SINGLE_BLOCK", addr, blk_len)) {
return sd_r1;
}
@@ -2045,7 +2049,7 @@ static sd_rsp_type_t sd_cmd_WRITE_SINGLE_BLOCK(SDState
*sd, SDRequest req)
}
sd->blk_written = 0;
- return sd_cmd_to_receivingdata(sd, req, addr, sd->blk_len);
+ return sd_cmd_to_receivingdata(sd, req, addr, blk_len);
}
/* CMD26 */
@@ -2372,7 +2376,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
SDRequest req)
switch (sd->state) {
case sd_transfer_state:
- if (!address_in_range(sd, "READ_BLOCK", addr, sd->blk_len)) {
+ if (!address_in_range(sd, "READ_BLOCK", addr, sd_blk_len(sd))) {
return sd_r1;
}
@@ -2392,7 +2396,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
SDRequest req)
switch (sd->state) {
case sd_transfer_state:
- if (!address_in_range(sd, "WRITE_BLOCK", addr, sd->blk_len)) {
+ if (!address_in_range(sd, "WRITE_BLOCK", addr,
+ sd_blk_len(sd))) {
return sd_r1;
}
@@ -2662,6 +2667,7 @@ static void sdcard_write_data_dump(const char *proto,
const char *cmd_desc,
static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
{
unsigned int partition_access;
+ uint32_t blk_len;
int i;
const uint8_t *value = buf;
@@ -2678,6 +2684,7 @@ static size_t sd_write_data(SDState *sd, const void *buf,
size_t length)
if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
return length;
+ blk_len = sd_blk_len(sd);
sdcard_write_data_dump(sd->proto->name,
sd->last_cmd_name,
sd->current_cmd, sd->data_offset, buf, length);
@@ -2704,7 +2711,7 @@ static size_t sd_write_data(SDState *sd, const void *buf,
size_t length)
if (sd->data_offset == 0) {
/* Start of the block - let's check the address is valid */
if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK",
- sd->data_start, sd->blk_len)) {
+ sd->data_start, blk_len)) {
break;
}
if (sd->size <= SDSC_MAX_CAPACITY) {
@@ -2715,7 +2722,7 @@ static size_t sd_write_data(SDState *sd, const void *buf,
size_t length)
}
}
sd->data[sd->data_offset++] = value[0];
- if (sd->data_offset >= sd->blk_len) {
+ if (sd->data_offset >= blk_len) {
/* TODO: Check CRC before committing */
sd->state = sd_programming_state;
partition_access = sd->ext_csd[EXT_CSD_PART_CONFIG]
@@ -2726,7 +2733,7 @@ static size_t sd_write_data(SDState *sd, const void *buf,
size_t length)
sd_blk_write(sd, sd->data_start, sd->data_offset);
}
sd->blk_written++;
- sd->data_start += sd->blk_len;
+ sd->data_start += blk_len;
sd->data_offset = 0;
sd->csd[14] |= 0x40;
@@ -2810,7 +2817,7 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t
length)
/* TODO: Append CRCs */
const uint8_t dummy_byte = 0x00;
unsigned int partition_access;
- uint32_t io_len;
+ uint32_t blk_len;
uint8_t *value = buf;
if (!sd->blk || !blk_is_inserted(sd->blk)) {
@@ -2830,11 +2837,11 @@ static size_t sd_read_data(SDState *sd, void *buf,
size_t length)
return length;
}
- io_len = sd_blk_len(sd);
+ blk_len = sd_blk_len(sd);
trace_sdcard_read_data(sd->proto->name,
sd->last_cmd_name, sd->current_cmd,
- sd->data_offset, sd->data_size, io_len);
+ sd->data_offset, sd->data_size, blk_len);
switch (sd->current_cmd) {
case 6: /* CMD6: SWITCH_FUNCTION */
case 8: /* CMD8: SEND_EXT_CSD */
@@ -2859,22 +2866,22 @@ static size_t sd_read_data(SDState *sd, void *buf,
size_t length)
if (sd->data_offset == 0) {
if (!address_in_range(sd, "READ_MULTIPLE_BLOCK",
- sd->data_start, io_len)) {
+ sd->data_start, blk_len)) {
*value = dummy_byte;
return length;
}
partition_access = sd->ext_csd[EXT_CSD_PART_CONFIG]
& EXT_CSD_PART_CONFIG_ACC_MASK;
if (partition_access == EXT_CSD_PART_CONFIG_ACC_RPMB) {
- emmc_rpmb_blk_read(sd, sd->data_start, io_len);
+ emmc_rpmb_blk_read(sd, sd->data_start, blk_len);
} else {
- sd_blk_read(sd, sd->data_start, io_len);
+ sd_blk_read(sd, sd->data_start, blk_len);
}
}
*value = sd->data[sd->data_offset++];
- if (sd->data_offset >= io_len) {
- sd->data_start += io_len;
+ if (sd->data_offset >= blk_len) {
+ sd->data_start += blk_len;
sd->data_offset = 0;
if (sd->multi_blk_cnt != 0) {
--
2.34.1