From 4fbeddb088d886be3fb69ddb896df3142177d3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 20 Jun 2024 18:51:01 +0200 Subject: [PATCH 01/19] bswap: Add st24_be_p() to store 24 bits in big-endian order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 14180d6221 ("bswap: Add the ability to store to an unaligned 24 bit field") added st24_le_p() for little endianness, add st24_be_p() equivalent for bit one. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Reviewed-by: Richard Henderson Message-Id: <20240621075607.17902-1-philmd@linaro.org> --- include/qemu/bswap.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index bd67468e5e..ad22910a5d 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -38,12 +38,14 @@ static inline void bswap64s(uint64_t *s) #if HOST_BIG_ENDIAN #define be_bswap(v, size) (v) #define le_bswap(v, size) glue(__builtin_bswap, size)(v) +#define be_bswap24(v) (v) #define le_bswap24(v) bswap24(v) #define be_bswaps(v, size) #define le_bswaps(p, size) \ do { *p = glue(__builtin_bswap, size)(*p); } while (0) #else #define le_bswap(v, size) (v) +#define be_bswap24(v) bswap24(v) #define le_bswap24(v) (v) #define be_bswap(v, size) glue(__builtin_bswap, size)(v) #define le_bswaps(v, size) @@ -357,6 +359,11 @@ static inline void stw_be_p(void *ptr, uint16_t v) stw_he_p(ptr, be_bswap(v, 16)); } +static inline void st24_be_p(void *ptr, uint32_t v) +{ + st24_he_p(ptr, be_bswap24(v)); +} + static inline void stl_be_p(void *ptr, uint32_t v) { stl_he_p(ptr, be_bswap(v, 32)); From c2e857b4cac0186d4ba1521fcfeb9b5322831676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 8 Apr 2024 15:38:11 +0200 Subject: [PATCH 02/19] hw/sd/sdcard: Avoid OOB in sd_read_byte() during unexpected CMD switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For multi-bytes commands, our implementation uses the @data_start and @data_offset fields to track byte access. We initialize the command start/offset in buffer once. Malicious guest might abuse by switching command while staying in the 'transfer' state, switching command buffer size, and our implementation can access out of buffer boundary. For example, CMD17 (READ_SINGLE_BLOCK) allows to read up to 512 bytes, and CMD13 (SEND_STATUS) up to 64 bytes. By switching from CMD17 to CMD13 (see reproducer below), bytes [64-511] are out of the 'status' buffer. Our implementation return R0 status code for unexpected commands. Such in-transaction command switch is unexpected and returns R0. This is a good place to reset the start/offset fields to avoid malicious accesses. Can be reproduced running: $ export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 $ cat << EOF | qemu-system-i386 \ -display none -nographic \ -machine accel=qtest -m 512M \ -nodefaults \ -device sdhci-pci,sd-spec-version=3 \ -device sd-card,drive=mydrive \ -drive if=none,index=0,file=null-co://,format=raw,id=mydrive \ -qtest stdio -trace sd\* -trace -sdbus_read outl 0xcf8 0x80001010 outl 0xcfc 0xe0000000 outl 0xcf8 0x80001004 outw 0xcfc 0x02 write 0xe000002c 0x1 0x05 write 0xe000000f 0x1 0x37 write 0xe000000a 0x1 0x01 write 0xe000000f 0x1 0x29 write 0xe000000f 0x1 0x02 write 0xe000000f 0x1 0x03 write 0xe000000c 0x1 0x32 write 0xe000000f 0x1 0x06 write 0xe0000005 0x1 0x01 write 0xe0000007 0x1 0x01 write 0xe0000003 0x1 0x00 write 0xe000000f 0x1 0x11 write 0xe000002a 0x1 0x01 write 0xe000002a 0x1 0x02 write 0xe000000f 0x1 0x0d write 0xe000002a 0x1 0x01 write 0xe000002a 0x1 0x02 EOF hw/sd/sd.c:1984:15: runtime error: index 256 out of bounds for type 'uint8_t [64]' #0 sd_read_byte hw/sd/sd.c:1984:15 #1 sdbus_read_data hw/sd/core.c:157:23 #2 sdhci_read_block_from_card hw/sd/sdhci.c:423:9 #3 sdhci_blkgap_write hw/sd/sdhci.c:1074:13 #4 sdhci_write hw/sd/sdhci.c:1195:13 #5 memory_region_write_accessor softmmu/memory.c:492:5 #6 access_with_adjusted_size softmmu/memory.c:554:18 #7 memory_region_dispatch_write softmmu/memory.c #8 flatview_write_continue softmmu/physmem.c:2778:23 #9 flatview_write softmmu/physmem.c:2818:14 #10 address_space_write softmmu/physmem.c:2910:18 SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior hw/sd/sd.c:1984:15 Reported-by: Alexander Bulekov Resolves: https://gitlab.com/qemu-project/qemu/-/issues/487 Buglink: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=36240 Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240408141717.66154-2-philmd@linaro.org> --- hw/sd/sd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 807b5d3de3..6a7a10501b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1826,6 +1826,13 @@ send_response: break; case sd_r0: + /* + * Invalid state transition, reset implementation + * fields to avoid OOB abuse. + */ + sd->data_start = 0; + sd->data_offset = 0; + /* fall-through */ case sd_illegal: rsplen = 0; break; From 8d380565adf45fa456832d7e2cbbf7be359ebbd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Jun 2024 16:19:41 +0200 Subject: [PATCH 03/19] hw/sd/sdcard: Correct code indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix mis-alignment from commits 793d04f495 and 6380cd2052 ("Add sd_cmd_SEND_TUNING_BLOCK" and "Add sd_cmd_SET_BLOCK_COUNT"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-2-philmd@linaro.org> --- hw/sd/sd.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 6a7a10501b..ba7f165cb5 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1069,33 +1069,33 @@ static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { - if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { - return sd_cmd_illegal(sd, req); - } + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + return sd_cmd_illegal(sd, req); + } - if (sd->state != sd_transfer_state) { - return sd_invalid_state_for_cmd(sd, req); - } + if (sd->state != sd_transfer_state) { + return sd_invalid_state_for_cmd(sd, req); + } - sd->state = sd_sendingdata_state; - sd->data_offset = 0; + sd->state = sd_sendingdata_state; + sd->data_offset = 0; - return sd_r1; + return sd_r1; } static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) { - if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { - return sd_cmd_illegal(sd, req); - } + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + return sd_cmd_illegal(sd, req); + } - if (sd->state != sd_transfer_state) { - return sd_invalid_state_for_cmd(sd, req); - } + if (sd->state != sd_transfer_state) { + return sd_invalid_state_for_cmd(sd, req); + } - sd->multi_blk_cnt = req.arg; + sd->multi_blk_cnt = req.arg; - return sd_r1; + return sd_r1; } static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) From d00e614f61e1a90ee905e783d3363752e63df8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Jun 2024 16:58:29 +0200 Subject: [PATCH 04/19] hw/sd/sdcard: Rewrite sd_cmd_ALL_SEND_CID using switch case (CMD2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep this handler style in sync with other handlers by using a switch() case, which might become handy to handle other states. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-3-philmd@linaro.org> --- hw/sd/sd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index ba7f165cb5..46388a140a 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1044,13 +1044,13 @@ static sd_rsp_type_t sd_cmd_SEND_OP_CMD(SDState *sd, SDRequest req) static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) { - if (sd->state != sd_ready_state) { + switch (sd->state) { + case sd_ready_state: + sd->state = sd_identification_state; + return sd_r2_i; + default: return sd_invalid_state_for_cmd(sd, req); } - - sd->state = sd_identification_state; - - return sd_r2_i; } static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) From 3dc5d349a32d741d3b432cc53f2ed518ff3c5f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Jun 2024 05:11:12 +0200 Subject: [PATCH 05/19] hw/sd/sdcard: Fix typo in SEND_OP_COND command name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no SEND_OP_CMD but SEND_OP_COND. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-4-philmd@linaro.org> --- hw/sd/sd.c | 6 +++--- hw/sd/sdmmc-internal.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 46388a140a..72d71259d3 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1035,7 +1035,7 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) return sd_is_spi(sd) ? sd_r1 : sd_r0; } -static sd_rsp_type_t sd_cmd_SEND_OP_CMD(SDState *sd, SDRequest req) +static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req) { sd->state = sd_transfer_state; @@ -2150,7 +2150,7 @@ static const SDProto sd_proto_spi = { .name = "SPI", .cmd = { [0] = sd_cmd_GO_IDLE_STATE, - [1] = sd_cmd_SEND_OP_CMD, + [1] = spi_cmd_SEND_OP_COND, [2 ... 4] = sd_cmd_illegal, [5] = sd_cmd_illegal, [7] = sd_cmd_illegal, @@ -2160,7 +2160,7 @@ static const SDProto sd_proto_spi = { }, .acmd = { [6] = sd_cmd_unimplemented, - [41] = sd_cmd_SEND_OP_CMD, + [41] = spi_cmd_SEND_OP_COND, }, }; diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c index 8648a7808d..c1d5508ae6 100644 --- a/hw/sd/sdmmc-internal.c +++ b/hw/sd/sdmmc-internal.c @@ -14,7 +14,7 @@ const char *sd_cmd_name(uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [0] = "GO_IDLE_STATE", [1] = "SEND_OP_CMD", + [0] = "GO_IDLE_STATE", [1] = "SEND_OP_COND", [2] = "ALL_SEND_CID", [3] = "SEND_RELATIVE_ADDR", [4] = "SET_DSR", [5] = "IO_SEND_OP_COND", [6] = "SWITCH_FUNC", [7] = "SELECT/DESELECT_CARD", From f17fb69c55c7020b90cc1a9eaefe716902a5bc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Oct 2020 19:36:59 +0100 Subject: [PATCH 06/19] hw/sd/sdcard: Use HWBLOCK_SHIFT definition instead of magic values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-5-philmd@linaro.org> --- hw/sd/sd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 72d71259d3..a14c5ff147 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -596,7 +596,7 @@ static void sd_reset(DeviceState *dev) } else { sect = 0; } - size = sect << 9; + size = sect << HWBLOCK_SHIFT; sect = sd_addr_to_wpnum(size) + 1; @@ -822,8 +822,8 @@ static void sd_erase(SDState *sd) if (FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { /* High capacity memory card: erase units are 512 byte blocks */ - erase_start *= 512; - erase_end *= 512; + erase_start <<= HWBLOCK_SHIFT; + erase_end <<= HWBLOCK_SHIFT; sdsc = false; } From 904547845c559d7530a20792d599a77d8e2ae442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Jun 2024 13:03:56 +0200 Subject: [PATCH 07/19] hw/sd/sdcard: Use registerfield CSR::CURRENT_STATE definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use registerfield-generated definitions to update card_status. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-6-philmd@linaro.org> --- hw/sd/sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a14c5ff147..64270dec0f 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1788,8 +1788,8 @@ int sd_do_command(SDState *sd, SDRequest *req, * (Do this now so they appear in r1 responses.) */ sd->current_cmd = req->cmd; - sd->card_status &= ~CURRENT_STATE; - sd->card_status |= (last_state << 9); + sd->card_status = FIELD_DP32(sd->card_status, CSR, + CURRENT_STATE, last_state); } send_response: From eac7ce3de78ee96c3e2b3eb2678682e44078bcdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 20 Jun 2024 18:47:27 +0200 Subject: [PATCH 08/19] hw/sd/sdcard: Use Load/Store API to fill some CID/CSD registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ld/st API helps noticing CID or CSD bytes refer to the same field. Multi-bytes fields are stored MSB first in CID / CSD. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-7-philmd@linaro.org> --- hw/sd/sd.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 64270dec0f..6e346e28ca 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -393,10 +393,7 @@ static void sd_set_cid(SDState *sd) sd->cid[6] = PNM[3]; sd->cid[7] = PNM[4]; sd->cid[8] = PRV; /* Fake product revision (PRV) */ - sd->cid[9] = 0xde; /* Fake serial number (PSN) */ - sd->cid[10] = 0xad; - sd->cid[11] = 0xbe; - sd->cid[12] = 0xef; + stl_be_p(&sd->cid[9], 0xdeadbeef); /* Fake serial number (PSN) */ sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ ((MDT_YR - 2000) / 10); sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; @@ -462,9 +459,7 @@ static void sd_set_csd(SDState *sd, uint64_t size) sd->csd[4] = 0x5b; sd->csd[5] = 0x59; sd->csd[6] = 0x00; - sd->csd[7] = (size >> 16) & 0xff; - sd->csd[8] = (size >> 8) & 0xff; - sd->csd[9] = (size & 0xff); + st24_be_p(&sd->csd[7], size); sd->csd[10] = 0x7f; sd->csd[11] = 0x80; sd->csd[12] = 0x0a; From 3b87fff1cd34a1f7cbf2884e615cfd69c28c8ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 20 Jun 2024 14:43:13 +0200 Subject: [PATCH 09/19] hw/sd/sdcard: Remove ACMD6 handler for SPI mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no ACMD6 command in SPI mode, remove the pointless handler introduced in commit 946897ce18 ("sdcard: handles more commands in SPI mode"). Keep sd_cmd_unimplemented() since we'll reuse it later. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-8-philmd@linaro.org> --- hw/sd/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 6e346e28ca..08a6d0aff8 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1012,6 +1012,7 @@ static sd_rsp_type_t sd_cmd_illegal(SDState *sd, SDRequest req) } /* Commands that are recognised but not yet implemented. */ +__attribute__((unused)) static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) { qemu_log_mask(LOG_UNIMP, "%s: CMD%i not implemented\n", @@ -2154,7 +2155,6 @@ static const SDProto sd_proto_spi = { [52 ... 54] = sd_cmd_illegal, }, .acmd = { - [6] = sd_cmd_unimplemented, [41] = spi_cmd_SEND_OP_COND, }, }; From 913638464c5cc244545af0a7f2a1c32c5780d6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Jun 2024 05:14:05 +0200 Subject: [PATCH 10/19] hw/sd/sdcard: Remove explicit entries for illegal commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NULL handler is already handled as illegal, no need to duplicate (that keeps this array simpler to maintain). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-9-philmd@linaro.org> --- hw/sd/sd.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 08a6d0aff8..4afb6988c7 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2147,12 +2147,6 @@ static const SDProto sd_proto_spi = { .cmd = { [0] = sd_cmd_GO_IDLE_STATE, [1] = spi_cmd_SEND_OP_COND, - [2 ... 4] = sd_cmd_illegal, - [5] = sd_cmd_illegal, - [7] = sd_cmd_illegal, - [15] = sd_cmd_illegal, - [26] = sd_cmd_illegal, - [52 ... 54] = sd_cmd_illegal, }, .acmd = { [41] = spi_cmd_SEND_OP_COND, @@ -2163,15 +2157,10 @@ static const SDProto sd_proto_sd = { .name = "SD", .cmd = { [0] = sd_cmd_GO_IDLE_STATE, - [1] = sd_cmd_illegal, [2] = sd_cmd_ALL_SEND_CID, [3] = sd_cmd_SEND_RELATIVE_ADDR, - [5] = sd_cmd_illegal, [19] = sd_cmd_SEND_TUNING_BLOCK, [23] = sd_cmd_SET_BLOCK_COUNT, - [52 ... 54] = sd_cmd_illegal, - [58] = sd_cmd_illegal, - [59] = sd_cmd_illegal, }, }; From 0e93b3b30b29b3e23eabf5ba759315cece761a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 14 Jun 2024 01:20:22 +0200 Subject: [PATCH 11/19] hw/sd/sdcard: Trace update of block count (CMD23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-12-philmd@linaro.org> --- hw/sd/sd.c | 1 + hw/sd/trace-events | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 4afb6988c7..44225bae9b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1090,6 +1090,7 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) } sd->multi_blk_cnt = req.arg; + trace_sdcard_set_block_count(sd->multi_blk_cnt); return sd_r1; } diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 94a00557b2..724365efc3 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -43,7 +43,8 @@ sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)" sdcard_powerup(void) "" sdcard_inquiry_cmd41(void) "" sdcard_reset(void) "" -sdcard_set_blocklen(uint16_t length) "0x%03x" +sdcard_set_blocklen(uint16_t length) "block len 0x%03x" +sdcard_set_block_count(uint32_t cnt) "block cnt 0x%"PRIx32 sdcard_inserted(bool readonly) "read_only: %u" sdcard_ejected(void) "" sdcard_erase(uint32_t first, uint32_t last) "addr first 0x%" PRIx32" last 0x%" PRIx32 From eded0d1a485f3e6279142b88edf444e5e764c9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Jun 2024 05:28:51 +0200 Subject: [PATCH 12/19] hw/sd/sdcard: Have cmd_valid_while_locked() return a boolean value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-14-philmd@linaro.org> --- hw/sd/sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 44225bae9b..04b141784b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1717,7 +1717,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd, return sd_illegal; } -static int cmd_valid_while_locked(SDState *sd, const uint8_t cmd) +static bool cmd_valid_while_locked(SDState *sd, unsigned cmd) { /* Valid commands in locked state: * basic class (0) @@ -1731,7 +1731,7 @@ static int cmd_valid_while_locked(SDState *sd, const uint8_t cmd) return cmd == 41 || cmd == 42; } if (cmd == 16 || cmd == 55) { - return 1; + return true; } return sd_cmd_class[cmd] == 0 || sd_cmd_class[cmd] == 7; } From 0ab318ca3c0b370ff82e9fabf80633cc93d0574e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Jun 2024 16:38:01 +0200 Subject: [PATCH 13/19] hw/sd/sdcard: Factor sd_req_get_rca() method out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract sd_req_get_rca() so we can re-use it in various SDProto handlers. Return a 16-bit value since RCA is 16-bit. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-15-philmd@linaro.org> --- hw/sd/sd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 04b141784b..b909a85d53 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -474,6 +474,14 @@ static void sd_set_rca(SDState *sd) sd->rca += 0x4567; } +static uint16_t sd_req_get_rca(SDState *s, SDRequest req) +{ + if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc) { + return req.arg >> 16; + } + return 0; +} + FIELD(CSR, AKE_SEQ_ERROR, 3, 1) FIELD(CSR, APP_CMD, 5, 1) FIELD(CSR, FX_EVENT, 6, 1) @@ -1097,7 +1105,7 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { - uint32_t rca = 0x0000; + uint16_t rca = sd_req_get_rca(sd, req); uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg; /* CMD55 precedes an ACMD, so we are not interested in tracing it. @@ -1112,11 +1120,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Not interpreting this as an app command */ sd->card_status &= ~APP_CMD; - if (sd_cmd_type[req.cmd] == sd_ac - || sd_cmd_type[req.cmd] == sd_adtc) { - rca = req.arg >> 16; - } - /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25 * if not, its effects are cancelled */ if (sd->multi_blk_cnt != 0 && !(req.cmd == 18 || req.cmd == 25)) { From 4a829730c85a8e44f142aeca6c95b8b07742c96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 19 Jun 2024 22:12:35 +0200 Subject: [PATCH 14/19] hw/sd/sdcard: Only call sd_req_get_rca() where RCA is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be useful later to assert only AC commands (Addressed point-to-point Commands, defined as the 'sd_ac' enum) extract the RCA value from the command argument. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-16-philmd@linaro.org> --- hw/sd/sd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index b909a85d53..912b2f8984 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1105,7 +1105,7 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { - uint16_t rca = sd_req_get_rca(sd, req); + uint16_t rca; uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg; /* CMD55 precedes an ACMD, so we are not interested in tracing it. @@ -1162,6 +1162,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 7: /* CMD7: SELECT/DESELECT_CARD */ + rca = sd_req_get_rca(sd, req); switch (sd->state) { case sd_standby_state: if (sd->rca != rca) @@ -1216,6 +1217,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r7; case 9: /* CMD9: SEND_CSD */ + rca = sd_req_get_rca(sd, req); switch (sd->state) { case sd_standby_state: if (sd->rca != rca) @@ -1239,6 +1241,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 10: /* CMD10: SEND_CID */ + rca = sd_req_get_rca(sd, req); switch (sd->state) { case sd_standby_state: if (sd->rca != rca) @@ -1279,6 +1282,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 13: /* CMD13: SEND_STATUS */ + rca = sd_req_get_rca(sd, req); switch (sd->mode) { case sd_data_transfer_mode: if (!sd_is_spi(sd) && sd->rca != rca) { @@ -1293,6 +1297,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 15: /* CMD15: GO_INACTIVE_STATE */ + rca = sd_req_get_rca(sd, req); switch (sd->mode) { case sd_data_transfer_mode: if (sd->rca != rca) @@ -1525,6 +1530,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Application specific commands (Class 8) */ case 55: /* CMD55: APP_CMD */ + rca = sd_req_get_rca(sd, req); switch (sd->state) { case sd_ready_state: case sd_identification_state: From 8b91a5613ca1520286b7c3ffe19ebecf144c781a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Jun 2024 16:50:30 +0200 Subject: [PATCH 15/19] hw/sd/sdcard: Factor sd_req_get_address() method out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract sd_cmd_get_address() so we can re-use it in various SDProto handlers. Use CARD_CAPACITY and HWBLOCK_SHIFT definitions instead of magic values. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-17-philmd@linaro.org> --- hw/sd/sd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 912b2f8984..51ab7cd003 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -582,6 +582,14 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response) stl_be_p(response, sd->vhs); } +static uint64_t sd_req_get_address(SDState *sd, SDRequest req) +{ + if (FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { + return (uint64_t) req.arg << HWBLOCK_SHIFT; + } + return req.arg; +} + static inline uint64_t sd_addr_to_wpnum(uint64_t addr) { return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); @@ -1106,7 +1114,7 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; - uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg; + uint64_t addr = sd_req_get_address(sd, req); /* CMD55 precedes an ACMD, so we are not interested in tracing it. * However there is no ACMD55, so we want to trace this particular case. From 6a226b2cab40f9d40be5de59230d80d9aa11bc42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 20 Jun 2024 14:29:46 +0200 Subject: [PATCH 16/19] hw/sd/sdcard: Only call sd_req_get_address() where address is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be useful later to assert only ADTC commands (Addressed point-to-point Data Transfer Commands, defined as the 'sd_adtc' enum) extract the address value from the command argument. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-18-philmd@linaro.org> --- hw/sd/sd.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 51ab7cd003..3e4eb656e1 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1114,7 +1114,7 @@ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint16_t rca; - uint64_t addr = sd_req_get_address(sd, req); + uint64_t addr; /* CMD55 precedes an ACMD, so we are not interested in tracing it. * However there is no ACMD55, so we want to trace this particular case. @@ -1239,7 +1239,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } sd->state = sd_sendingdata_state; memcpy(sd->data, sd->csd, 16); - sd->data_start = addr; + sd->data_start = sd_req_get_address(sd, req); sd->data_offset = 0; return sd_r1; @@ -1263,7 +1263,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } sd->state = sd_sendingdata_state; memcpy(sd->data, sd->cid, 16); - sd->data_start = addr; + sd->data_start = sd_req_get_address(sd, req); sd->data_offset = 0; return sd_r1; @@ -1339,6 +1339,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 17: /* CMD17: READ_SINGLE_BLOCK */ case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + addr = sd_req_get_address(sd, req); switch (sd->state) { case sd_transfer_state: @@ -1359,6 +1360,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ + addr = sd_req_get_address(sd, req); switch (sd->state) { case sd_transfer_state: @@ -1417,7 +1419,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->size > SDSC_MAX_CAPACITY) { return sd_illegal; } - + addr = sd_req_get_address(sd, req); switch (sd->state) { case sd_transfer_state: if (!address_in_range(sd, "SET_WRITE_PROT", addr, 1)) { @@ -1439,7 +1441,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->size > SDSC_MAX_CAPACITY) { return sd_illegal; } - + addr = sd_req_get_address(sd, req); switch (sd->state) { case sd_transfer_state: if (!address_in_range(sd, "CLR_WRITE_PROT", addr, 1)) { @@ -1461,7 +1463,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) if (sd->size > SDSC_MAX_CAPACITY) { return sd_illegal; } - + addr = sd_req_get_address(sd, req); switch (sd->state) { case sd_transfer_state: if (!address_in_range(sd, "SEND_WRITE_PROT", From 9ee9292b75fcce4c32ebfe009c950d8437a267f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 13 Jun 2024 22:45:43 +0200 Subject: [PATCH 17/19] hw/sd/sdcard: Add sd_invalid_mode_for_cmd to report invalid mode switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having the mode switch displayed help to track incomplete command implementations. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-19-philmd@linaro.org> --- hw/sd/sd.c | 75 +++++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 3e4eb656e1..969340e5cb 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -178,6 +178,17 @@ static const char *sd_version_str(enum SDPhySpecificationVersion version) return sdphy_version[version]; } +static const char *sd_mode_name(enum SDCardModes mode) +{ + static const char *mode_name[] = { + [sd_inactive] = "inactive", + [sd_card_identification_mode] = "identification", + [sd_data_transfer_mode] = "transfer", + }; + assert(mode < ARRAY_SIZE(mode_name)); + return mode_name[mode]; +} + static const char *sd_state_name(enum SDCardStates state) { static const char *state_name[] = { @@ -1018,6 +1029,15 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req) return sd_illegal; } +static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong mode: %s (spec %s)\n", + sd_proto(sd)->name, req.cmd, sd_mode_name(sd->mode), + sd_version_str(sd->spec_version)); + + return sd_illegal; +} + static sd_rsp_type_t sd_cmd_illegal(SDState *sd, SDRequest req) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown CMD%i for spec %s\n", @@ -1156,18 +1176,14 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 6: /* CMD6: SWITCH_FUNCTION */ - switch (sd->mode) { - case sd_data_transfer_mode: - sd_function_switch(sd, req.arg); - sd->state = sd_sendingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; + if (sd->mode != sd_data_transfer_mode) { + return sd_invalid_mode_for_cmd(sd, req); } - break; + sd_function_switch(sd, req.arg); + sd->state = sd_sendingdata_state; + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; case 7: /* CMD7: SELECT/DESELECT_CARD */ rca = sd_req_get_rca(sd, req); @@ -1291,33 +1307,24 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 13: /* CMD13: SEND_STATUS */ rca = sd_req_get_rca(sd, req); - switch (sd->mode) { - case sd_data_transfer_mode: - if (!sd_is_spi(sd) && sd->rca != rca) { - return sd_r0; - } - - return sd_r1; - - default: - break; + if (sd->mode != sd_data_transfer_mode) { + return sd_invalid_mode_for_cmd(sd, req); } - break; + if (!sd_is_spi(sd) && sd->rca != rca) { + return sd_r0; + } + + return sd_r1; case 15: /* CMD15: GO_INACTIVE_STATE */ - rca = sd_req_get_rca(sd, req); - switch (sd->mode) { - case sd_data_transfer_mode: - if (sd->rca != rca) - return sd_r0; - - sd->state = sd_inactive_state; - return sd_r0; - - default: - break; + if (sd->mode != sd_data_transfer_mode) { + return sd_invalid_mode_for_cmd(sd, req); } - break; + rca = sd_req_get_rca(sd, req); + if (sd->rca == rca) { + sd->state = sd_inactive_state; + } + return sd_r0; /* Block read commands (Class 2) */ case 16: /* CMD16: SET_BLOCKLEN */ From cd44ccee18e2a8856f7ddc0b00bbc40dfa9fd5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 8 Apr 2024 15:41:56 +0200 Subject: [PATCH 18/19] hw/sd/sdcard: Inline BLK_READ_BLOCK / BLK_WRITE_BLOCK macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These macros only save 3 chars and make the code harder to maintain, simply remove them. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-20-philmd@linaro.org> --- hw/sd/sd.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 969340e5cb..d4e3d079a8 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -819,8 +819,6 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) } } -#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len) -#define BLK_WRITE_BLOCK(a, len) sd_blk_write(sd, a, len) #define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len) #define APP_WRITE_BLOCK(a, len) @@ -872,7 +870,7 @@ static void sd_erase(SDState *sd) continue; } } - BLK_WRITE_BLOCK(erase_addr, erase_len); + sd_blk_write(sd, erase_addr, erase_len); } } @@ -1903,7 +1901,7 @@ void sd_write_byte(SDState *sd, uint8_t value) if (sd->data_offset >= sd->blk_len) { /* TODO: Check CRC before committing */ sd->state = sd_programming_state; - BLK_WRITE_BLOCK(sd->data_start, sd->data_offset); + sd_blk_write(sd, sd->data_start, sd->data_offset); sd->blk_written ++; sd->csd[14] |= 0x40; /* Bzzzzzzztt .... Operation complete. */ @@ -1929,7 +1927,7 @@ void sd_write_byte(SDState *sd, uint8_t value) if (sd->data_offset >= sd->blk_len) { /* TODO: Check CRC before committing */ sd->state = sd_programming_state; - BLK_WRITE_BLOCK(sd->data_start, sd->data_offset); + sd_blk_write(sd, sd->data_start, sd->data_offset); sd->blk_written++; sd->data_start += sd->blk_len; sd->data_offset = 0; @@ -2077,8 +2075,9 @@ uint8_t sd_read_byte(SDState *sd) break; case 17: /* CMD17: READ_SINGLE_BLOCK */ - if (sd->data_offset == 0) - BLK_READ_BLOCK(sd->data_start, io_len); + if (sd->data_offset == 0) { + sd_blk_read(sd, sd->data_start, io_len); + } ret = sd->data[sd->data_offset ++]; if (sd->data_offset >= io_len) @@ -2091,7 +2090,7 @@ uint8_t sd_read_byte(SDState *sd) sd->data_start, io_len)) { return 0x00; } - BLK_READ_BLOCK(sd->data_start, io_len); + sd_blk_read(sd, sd->data_start, io_len); } ret = sd->data[sd->data_offset ++]; From 76ae9a231487a2b127c90bcb657fd42a1f6c06f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Oct 2020 20:17:47 +0100 Subject: [PATCH 19/19] hw/sd/sdcard: Add comments around registers and commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Message-Id: <20240621080554.18986-21-philmd@linaro.org> --- hw/sd/sd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d4e3d079a8..a48010cfc1 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -315,6 +315,8 @@ static uint8_t sd_crc7(const void *message, size_t width) return shift_reg; } +/* Operation Conditions register */ + #define OCR_POWER_DELAY_NS 500000 /* 0.5ms */ FIELD(OCR, VDD_VOLTAGE_WINDOW, 0, 24) @@ -364,6 +366,8 @@ static void sd_set_ocr(SDState *sd) } } +/* SD Configuration register */ + static void sd_set_scr(SDState *sd) { sd->scr[0] = 0 << 4; /* SCR structure version 1.0 */ @@ -386,6 +390,8 @@ static void sd_set_scr(SDState *sd) sd->scr[7] = 0x00; } +/* Card IDentification register */ + #define MID 0xaa #define OID "XY" #define PNM "QEMU!" @@ -411,6 +417,8 @@ static void sd_set_cid(SDState *sd) sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; } +/* Card-Specific Data register */ + #define HWBLOCK_SHIFT 9 /* 512 bytes */ #define SECTOR_SHIFT 5 /* 16 kilobytes */ #define WPGROUP_SHIFT 7 /* 2 megs */ @@ -480,6 +488,8 @@ static void sd_set_csd(SDState *sd, uint64_t size) sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; } +/* Relative Card Address register */ + static void sd_set_rca(SDState *sd) { sd->rca += 0x4567; @@ -493,6 +503,8 @@ static uint16_t sd_req_get_rca(SDState *s, SDRequest req) return 0; } +/* Card Status register */ + FIELD(CSR, AKE_SEQ_ERROR, 3, 1) FIELD(CSR, APP_CMD, 5, 1) FIELD(CSR, FX_EVENT, 6, 1) @@ -623,6 +635,8 @@ static void sd_reset(DeviceState *dev) sect = sd_addr_to_wpnum(size) + 1; sd->state = sd_idle_state; + + /* card registers */ sd->rca = 0x0000; sd->size = size; sd_set_ocr(sd); @@ -1055,6 +1069,7 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) return sd_illegal; } +/* CMD0 */ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) { if (sd->state != sd_inactive_state) { @@ -1065,6 +1080,7 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) return sd_is_spi(sd) ? sd_r1 : sd_r0; } +/* CMD1 */ static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req) { sd->state = sd_transfer_state; @@ -1072,6 +1088,7 @@ static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req) return sd_r1; } +/* CMD2 */ static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) { switch (sd->state) { @@ -1083,6 +1100,7 @@ static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) } } +/* CMD3 */ static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) { switch (sd->state) { @@ -1097,6 +1115,7 @@ static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) } } +/* CMD19 */ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) { if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { @@ -1113,6 +1132,7 @@ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) return sd_r1; } +/* CMD23 */ static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) { if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {