aboutsummaryrefslogtreecommitdiff
path: root/hw/sd/sd.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/sd/sd.c')
-rw-r--r--hw/sd/sd.c742
1 files changed, 543 insertions, 199 deletions
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index a140a32..40a75a4 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -37,9 +37,8 @@
#include "qemu/cutils.h"
#include "hw/irq.h"
#include "hw/registerfields.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "hw/sd/sd.h"
-#include "hw/sd/sdcard_legacy.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/bitmap.h"
@@ -52,6 +51,7 @@
#include "qemu/module.h"
#include "sdmmc-internal.h"
#include "trace.h"
+#include "crypto/hmac.h"
//#define DEBUG_SD 1
@@ -62,6 +62,7 @@
typedef enum {
sd_r0 = 0, /* no response */
sd_r1, /* normal response command */
+ spi_r2, /* STATUS */
sd_r2_i, /* CID register */
sd_r2_s, /* CSD register */
sd_r3, /* OCR register */
@@ -71,6 +72,14 @@ typedef enum {
sd_illegal = -2,
} sd_rsp_type_t;
+typedef enum {
+ sd_spi,
+ sd_bc, /* broadcast -- no response */
+ sd_bcr, /* broadcast with response */
+ sd_ac, /* addressed -- no data transfer */
+ sd_adtc, /* addressed with data transfer */
+} sd_cmd_type_t;
+
enum SDCardModes {
sd_inactive,
sd_card_identification_mode,
@@ -109,13 +118,30 @@ typedef struct SDProto {
} cmd[SDMMC_CMD_MAX], acmd[SDMMC_CMD_MAX];
} SDProto;
+#define RPMB_STUFF_LEN 196
+#define RPMB_KEY_MAC_LEN 32
+#define RPMB_DATA_LEN 256 /* one RPMB block is half a sector */
+#define RPMB_NONCE_LEN 16
+#define RPMB_HASH_LEN 284
+
+typedef struct QEMU_PACKED {
+ uint8_t stuff_bytes[RPMB_STUFF_LEN];
+ uint8_t key_mac[RPMB_KEY_MAC_LEN];
+ uint8_t data[RPMB_DATA_LEN];
+ uint8_t nonce[RPMB_NONCE_LEN];
+ uint32_t write_counter;
+ uint16_t address;
+ uint16_t block_count;
+ uint16_t result;
+ uint16_t req_resp;
+} RPMBDataFrame;
+
+QEMU_BUILD_BUG_MSG(sizeof(RPMBDataFrame) != 512,
+ "invalid RPMBDataFrame size");
+
struct SDState {
DeviceState parent_obj;
- /* If true, created by sd_init() for a non-qdevified caller */
- /* TODO purge them with fire */
- bool me_no_qdev_me_kill_mammoth_with_rocks;
-
/* SD Memory Card Registers */
uint32_t ocr;
uint8_t scr[8];
@@ -136,6 +162,7 @@ struct SDState {
uint8_t spec_version;
uint64_t boot_part_size;
+ uint64_t rpmb_part_size;
BlockBackend *blk;
uint8_t boot_config;
@@ -143,7 +170,6 @@ struct SDState {
/* Runtime changeables */
- uint32_t mode; /* current card mode, one of SDCardModes */
int32_t state; /* current card state, one of SDCardStates */
uint32_t vhs;
bool wp_switch;
@@ -169,10 +195,13 @@ struct SDState {
uint32_t data_offset;
size_t data_size;
uint8_t data[512];
- qemu_irq readonly_cb;
- qemu_irq inserted_cb;
+ struct {
+ uint32_t write_counter;
+ uint8_t key[RPMB_KEY_MAC_LEN];
+ uint8_t key_set;
+ RPMBDataFrame result;
+ } rpmb;
QEMUTimer *ocr_power_timer;
- bool enable;
uint8_t dat_lines;
bool cmd_line;
};
@@ -195,7 +224,6 @@ static bool sd_is_emmc(SDState *sd)
static const char *sd_version_str(enum SDPhySpecificationVersion version)
{
static const char *sdphy_version[] = {
- [SD_PHY_SPECv1_10_VERS] = "v1.10",
[SD_PHY_SPECv2_00_VERS] = "v2.00",
[SD_PHY_SPECv3_01_VERS] = "v3.01",
};
@@ -247,6 +275,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
static const char *response_name[] = {
[sd_r0] = "RESP#0 (no response)",
[sd_r1] = "RESP#1 (normal cmd)",
+ [spi_r2] = "RESP#2 (STATUS reg)",
[sd_r2_i] = "RESP#2 (CID reg)",
[sd_r2_s] = "RESP#2 (CSD reg)",
[sd_r3] = "RESP#3 (OCR reg)",
@@ -291,12 +320,12 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd)
static uint8_t sd_get_dat_lines(SDState *sd)
{
- return sd->enable ? sd->dat_lines : 0;
+ return sd->dat_lines;
}
static bool sd_get_cmd_line(SDState *sd)
{
- return sd->enable ? sd->cmd_line : false;
+ return sd->cmd_line;
}
static void sd_set_voltage(SDState *sd, uint16_t millivolts)
@@ -313,27 +342,24 @@ static void sd_set_voltage(SDState *sd, uint16_t millivolts)
}
}
-static void sd_set_mode(SDState *sd)
+static enum SDCardModes sd_mode(SDState *sd)
{
switch (sd->state) {
case sd_inactive_state:
- sd->mode = sd_inactive;
- break;
-
+ return sd_inactive;
case sd_idle_state:
case sd_ready_state:
case sd_identification_state:
- sd->mode = sd_card_identification_mode;
- break;
-
+ return sd_card_identification_mode;
case sd_standby_state:
case sd_transfer_state:
case sd_sendingdata_state:
case sd_receivingdata_state:
case sd_programming_state:
case sd_disconnect_state:
- sd->mode = sd_data_transfer_mode;
- break;
+ return sd_data_transfer_mode;
+ default:
+ g_assert_not_reached();
}
}
@@ -409,11 +435,7 @@ static void sd_set_ocr(SDState *sd)
static void sd_set_scr(SDState *sd)
{
sd->scr[0] = 0 << 4; /* SCR structure version 1.0 */
- if (sd->spec_version == SD_PHY_SPECv1_10_VERS) {
- sd->scr[0] |= 1; /* Spec Version 1.10 */
- } else {
- sd->scr[0] |= 2; /* Spec Version 2.00 or Version 3.0X */
- }
+ sd->scr[0] |= 2; /* Spec Version 2.00 or Version 3.0X */
sd->scr[1] = (2 << 4) /* SDSC Card (Security Version 1.01) */
| 0b0101; /* 1-bit or 4-bit width bus modes */
sd->scr[2] = 0x00; /* Extended Security is not supported. */
@@ -513,7 +535,9 @@ static void emmc_set_ext_csd(SDState *sd, uint64_t size)
sd->ext_csd[205] = 0x46; /* Min read perf for 4bit@26Mhz */
sd->ext_csd[EXT_CSD_CARD_TYPE] = 0b11;
sd->ext_csd[EXT_CSD_STRUCTURE] = 2;
- sd->ext_csd[EXT_CSD_REV] = 3;
+ sd->ext_csd[EXT_CSD_REV] = 5;
+ sd->ext_csd[EXT_CSD_RPMB_MULT] = sd->rpmb_part_size / (128 * KiB);
+ sd->ext_csd[EXT_CSD_PARTITION_SUPPORT] = 0b111;
/* Mode segment (RW) */
sd->ext_csd[EXT_CSD_PART_CONFIG] = sd->boot_config;
@@ -729,16 +753,81 @@ static int sd_req_crc_validate(SDRequest *req)
return sd_crc7(buffer, 5) != req->crc; /* TODO */
}
+static size_t sd_response_size(SDState *sd, sd_rsp_type_t rtype)
+{
+ switch (rtype) {
+ case sd_r1:
+ case sd_r1b:
+ return sd_is_spi(sd) ? 1 : 4;
+
+ case spi_r2:
+ assert(sd_is_spi(sd));
+ return 2;
+
+ case sd_r2_i:
+ case sd_r2_s:
+ assert(!sd_is_spi(sd));
+ return 16;
+
+ case sd_r3:
+ case sd_r7:
+ return sd_is_spi(sd) ? 5 : 4;
+
+ case sd_r6:
+ assert(!sd_is_spi(sd));
+ return 4;
+
+ case sd_r0:
+ case sd_illegal:
+ return sd_is_spi(sd) ? 1 : 0;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void sd_response_r1_make(SDState *sd, uint8_t *response)
{
- stl_be_p(response, sd->card_status);
+ if (sd_is_spi(sd)) {
+ response[0] = sd->state == sd_idle_state;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_RESET) << 1;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ILLEGAL_COMMAND) << 2;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, COM_CRC_ERROR) << 3;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_SEQ_ERROR) << 4;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, ADDRESS_ERROR) << 5;
+ response[0] |= FIELD_EX32(sd->card_status, CSR, BLOCK_LEN_ERROR) << 6;
+ response[0] |= 0 << 7;
+ } else {
+ stl_be_p(response, sd->card_status);
+ }
/* Clear the "clear on read" status bits */
sd->card_status &= ~CARD_STATUS_C;
}
+static void spi_response_r2_make(SDState *sd, uint8_t *resp)
+{
+ /* Prepend R1 */
+ sd_response_r1_make(sd, resp);
+
+ resp[1] = FIELD_EX32(sd->card_status, CSR, CARD_IS_LOCKED) << 0;
+ resp[1] |= (FIELD_EX32(sd->card_status, CSR, LOCK_UNLOCK_FAILED)
+ || FIELD_EX32(sd->card_status, CSR, WP_ERASE_SKIP)) << 1;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, ERROR) << 2;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, CC_ERROR) << 3;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, CARD_ECC_FAILED) << 4;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, WP_VIOLATION) << 5;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, ERASE_PARAM) << 6;
+ resp[1] |= FIELD_EX32(sd->card_status, CSR, OUT_OF_RANGE) << 7;
+}
+
static void sd_response_r3_make(SDState *sd, uint8_t *response)
{
+ if (sd_is_spi(sd)) {
+ /* Prepend R1 */
+ sd_response_r1_make(sd, response);
+ response++;
+ }
stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
}
@@ -756,6 +845,11 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response)
static void sd_response_r7_make(SDState *sd, uint8_t *response)
{
+ if (sd_is_spi(sd)) {
+ /* Prepend R1 */
+ sd_response_r1_make(sd, response);
+ response++;
+ }
stl_be_p(response, sd->vhs);
}
@@ -769,21 +863,15 @@ static uint32_t sd_blk_len(SDState *sd)
/*
* This requires a disk image that has two boot partitions inserted at the
- * beginning of it. The size of the boot partitions is the "boot-size"
- * property.
+ * beginning of it, followed by an RPMB partition. The size of the boot
+ * partitions is the "boot-partition-size" property, the one of the RPMB
+ * partition is 'rpmb-partition-size'.
*/
-static uint32_t sd_bootpart_offset(SDState *sd)
+static uint32_t sd_part_offset(SDState *sd)
{
- bool partitions_enabled;
unsigned partition_access;
- if (!sd->boot_part_size || !sd_is_emmc(sd)) {
- return 0;
- }
-
- partitions_enabled = sd->ext_csd[EXT_CSD_PART_CONFIG]
- & EXT_CSD_PART_CONFIG_EN_MASK;
- if (!partitions_enabled) {
+ if (!sd_is_emmc(sd)) {
return 0;
}
@@ -791,11 +879,13 @@ static uint32_t sd_bootpart_offset(SDState *sd)
& EXT_CSD_PART_CONFIG_ACC_MASK;
switch (partition_access) {
case EXT_CSD_PART_CONFIG_ACC_DEFAULT:
- return sd->boot_part_size * 2;
- case EXT_CSD_PART_CONFIG_ACC_BOOT0:
+ return sd->boot_part_size * 2 + sd->rpmb_part_size;
+ case EXT_CSD_PART_CONFIG_ACC_BOOT1:
return 0;
- case EXT_CSD_PART_CONFIG_ACC_BOOT0 + 1:
+ case EXT_CSD_PART_CONFIG_ACC_BOOT2:
return sd->boot_part_size * 1;
+ case EXT_CSD_PART_CONFIG_ACC_RPMB:
+ return sd->boot_part_size * 2;
default:
g_assert_not_reached();
}
@@ -833,7 +923,9 @@ static void sd_reset(DeviceState *dev)
sect = 0;
}
size = sect << HWBLOCK_SHIFT;
- size -= sd_bootpart_offset(sd);
+ if (sd_is_emmc(sd)) {
+ size -= sd->boot_part_size * 2 + sd->rpmb_part_size;
+ }
sect = sd_addr_to_wpnum(size) + 1;
@@ -889,17 +981,10 @@ static void sd_cardchange(void *opaque, bool load, Error **errp)
trace_sdcard_ejected();
}
- if (sd->me_no_qdev_me_kill_mammoth_with_rocks) {
- qemu_set_irq(sd->inserted_cb, inserted);
- if (inserted) {
- qemu_set_irq(sd->readonly_cb, readonly);
- }
- } else {
- sdbus = SD_BUS(qdev_get_parent_bus(dev));
- sdbus_set_inserted(sdbus, inserted);
- if (inserted) {
- sdbus_set_readonly(sdbus, readonly);
- }
+ sdbus = SD_BUS(qdev_get_parent_bus(dev));
+ sdbus_set_inserted(sdbus, inserted);
+ if (inserted) {
+ sdbus_set_readonly(sdbus, readonly);
}
}
@@ -927,6 +1012,34 @@ static const VMStateDescription sd_ocr_vmstate = {
},
};
+static bool vmstate_needed_for_rpmb(void *opaque)
+{
+ SDState *sd = opaque;
+
+ return sd->rpmb_part_size > 0;
+}
+
+static const VMStateDescription emmc_rpmb_vmstate = {
+ .name = "sd-card/ext_csd_modes-state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = vmstate_needed_for_rpmb,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(rpmb.result.key_mac, SDState, RPMB_KEY_MAC_LEN),
+ VMSTATE_UINT8_ARRAY(rpmb.result.data, SDState, RPMB_DATA_LEN),
+ VMSTATE_UINT8_ARRAY(rpmb.result.nonce, SDState, RPMB_NONCE_LEN),
+ VMSTATE_UINT32(rpmb.result.write_counter, SDState),
+ VMSTATE_UINT16(rpmb.result.address, SDState),
+ VMSTATE_UINT16(rpmb.result.block_count, SDState),
+ VMSTATE_UINT16(rpmb.result.result, SDState),
+ VMSTATE_UINT16(rpmb.result.req_resp, SDState),
+ VMSTATE_UINT32(rpmb.write_counter, SDState),
+ VMSTATE_UINT8_ARRAY(rpmb.key, SDState, 32),
+ VMSTATE_UINT8(rpmb.key_set, SDState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static bool vmstate_needed_for_emmc(void *opaque)
{
SDState *sd = opaque;
@@ -964,7 +1077,7 @@ static const VMStateDescription sd_vmstate = {
.minimum_version_id = 2,
.pre_load = sd_vmstate_pre_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(mode, SDState),
+ VMSTATE_UNUSED(4),
VMSTATE_INT32(state, SDState),
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
@@ -987,74 +1100,218 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_UINT32(data_offset, SDState),
VMSTATE_UINT8_ARRAY(data, SDState, 512),
VMSTATE_UNUSED_V(1, 512),
- VMSTATE_BOOL(enable, SDState),
+ VMSTATE_UNUSED(1),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
&sd_ocr_vmstate,
&emmc_extcsd_vmstate,
+ &emmc_rpmb_vmstate,
NULL
},
};
-/* Legacy initialization function for use by non-qdevified callers */
-SDState *sd_init(BlockBackend *blk, bool is_spi)
+static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
+{
+ trace_sdcard_read_block(addr, len);
+ addr += sd_part_offset(sd);
+ if (!sd->blk || blk_pread(sd->blk, addr, len, sd->data, 0) < 0) {
+ fprintf(stderr, "sd_blk_read: read error on host side\n");
+ }
+}
+
+static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
{
- Object *obj;
- DeviceState *dev;
- SDState *sd;
+ trace_sdcard_write_block(addr, len);
+ addr += sd_part_offset(sd);
+ if (!sd->blk || blk_pwrite(sd->blk, addr, len, sd->data, 0) < 0) {
+ fprintf(stderr, "sd_blk_write: write error on host side\n");
+ }
+}
+
+static bool rpmb_calc_hmac(SDState *sd, const RPMBDataFrame *frame,
+ unsigned int num_blocks, uint8_t *mac)
+{
+ g_autoptr(QCryptoHmac) hmac = NULL;
+ size_t mac_len = RPMB_KEY_MAC_LEN;
+ bool success = true;
Error *err = NULL;
+ uint64_t offset;
- obj = object_new(is_spi ? TYPE_SD_CARD_SPI : TYPE_SD_CARD);
- dev = DEVICE(obj);
- if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) {
- error_reportf_err(err, "sd_init failed: ");
- return NULL;
+ hmac = qcrypto_hmac_new(QCRYPTO_HASH_ALGO_SHA256, sd->rpmb.key,
+ RPMB_KEY_MAC_LEN, &err);
+ if (!hmac) {
+ error_report_err(err);
+ return false;
}
/*
- * Realizing the device properly would put it into the QOM
- * composition tree even though it is not plugged into an
- * appropriate bus. That's a no-no. Hide the device from
- * QOM/qdev, and call its qdev realize callback directly.
+ * This implies a read request because we only support single-block write
+ * requests so far.
*/
- object_ref(obj);
- object_unparent(obj);
- sd_realize(dev, &err);
- if (err) {
- error_reportf_err(err, "sd_init failed: ");
- return NULL;
+ if (num_blocks > 1) {
+ /*
+ * Unfortunately, the underlying crypto libraries do not allow us to
+ * migrate an active QCryptoHmac state. Therefore, we have to calculate
+ * the HMAC in one run. To avoid buffering a complete read sequence in
+ * SDState, reconstruct all frames except for the last one.
+ */
+ void *buf = sd->data;
+
+ assert(RPMB_HASH_LEN <= sizeof(sd->data));
+
+ /*
+ * We will hash everything from data field to the end of RPMBDataFrame.
+ */
+ memcpy((uint8_t *)buf + RPMB_DATA_LEN,
+ (uint8_t *)frame + offsetof(RPMBDataFrame, nonce),
+ RPMB_HASH_LEN - RPMB_DATA_LEN);
+
+ offset = lduw_be_p(&frame->address) * RPMB_DATA_LEN + sd_part_offset(sd);
+ do {
+ if (blk_pread(sd->blk, offset, RPMB_DATA_LEN, buf, 0) < 0) {
+ error_report("sd_blk_read: read error on host side");
+ success = false;
+ break;
+ }
+ if (qcrypto_hmac_bytes(hmac, buf, RPMB_HASH_LEN, NULL, NULL,
+ &err) < 0) {
+ error_report_err(err);
+ success = false;
+ break;
+ }
+ offset += RPMB_DATA_LEN;
+ } while (--num_blocks > 1);
}
- sd = SD_CARD(dev);
- sd->me_no_qdev_me_kill_mammoth_with_rocks = true;
- return sd;
-}
+ if (success &&
+ qcrypto_hmac_bytes(hmac, frame->data, RPMB_HASH_LEN, &mac,
+ &mac_len, &err) < 0) {
+ error_report_err(err);
+ success = false;
+ }
+ assert(!success || mac_len == RPMB_KEY_MAC_LEN);
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
-{
- sd->readonly_cb = readonly;
- sd->inserted_cb = insert;
- qemu_set_irq(readonly, sd->blk ? !blk_is_writable(sd->blk) : 0);
- qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0);
+ return success;
}
-static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
+static void emmc_rpmb_blk_read(SDState *sd, uint64_t addr, uint32_t len)
{
- trace_sdcard_read_block(addr, len);
- addr += sd_bootpart_offset(sd);
- if (!sd->blk || blk_pread(sd->blk, addr, len, sd->data, 0) < 0) {
- fprintf(stderr, "sd_blk_read: read error on host side\n");
+ uint16_t resp = lduw_be_p(&sd->rpmb.result.req_resp);
+ uint16_t result = lduw_be_p(&sd->rpmb.result.result);
+ unsigned int curr_block = 0;
+
+ if ((result & ~RPMB_RESULT_COUTER_EXPIRED) == RPMB_RESULT_OK &&
+ resp == RPMB_RESP(RPMB_REQ_AUTH_DATA_READ)) {
+ curr_block = lduw_be_p(&sd->rpmb.result.address);
+ if (sd->rpmb.result.block_count == 0) {
+ stw_be_p(&sd->rpmb.result.block_count, sd->multi_blk_cnt);
+ } else {
+ curr_block += lduw_be_p(&sd->rpmb.result.block_count);
+ curr_block -= sd->multi_blk_cnt;
+ }
+ addr = curr_block * RPMB_DATA_LEN + sd_part_offset(sd);
+ if (blk_pread(sd->blk, addr, RPMB_DATA_LEN,
+ sd->rpmb.result.data, 0) < 0) {
+ error_report("sd_blk_read: read error on host side");
+ memset(sd->rpmb.result.data, 0, sizeof(sd->rpmb.result.data));
+ stw_be_p(&sd->rpmb.result.result,
+ RPMB_RESULT_READ_FAILURE
+ | (result & RPMB_RESULT_COUTER_EXPIRED));
+ }
+ if (sd->multi_blk_cnt == 1 &&
+ !rpmb_calc_hmac(sd, &sd->rpmb.result,
+ lduw_be_p(&sd->rpmb.result.block_count),
+ sd->rpmb.result.key_mac)) {
+ memset(sd->rpmb.result.data, 0, sizeof(sd->rpmb.result.data));
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_AUTH_FAILURE);
+ }
+ } else if (!rpmb_calc_hmac(sd, &sd->rpmb.result, 1,
+ sd->rpmb.result.key_mac)) {
+ memset(sd->rpmb.result.data, 0, sizeof(sd->rpmb.result.data));
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_AUTH_FAILURE);
}
+ memcpy(sd->data, &sd->rpmb.result, sizeof(sd->rpmb.result));
+
+ trace_sdcard_rpmb_read_block(resp, curr_block,
+ lduw_be_p(&sd->rpmb.result.result));
}
-static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
+static void emmc_rpmb_blk_write(SDState *sd, uint64_t addr, uint32_t len)
{
- trace_sdcard_write_block(addr, len);
- addr += sd_bootpart_offset(sd);
- if (!sd->blk || blk_pwrite(sd->blk, addr, len, sd->data, 0) < 0) {
- fprintf(stderr, "sd_blk_write: write error on host side\n");
+ RPMBDataFrame *frame = (RPMBDataFrame *)sd->data;
+ uint16_t req = lduw_be_p(&frame->req_resp);
+ uint8_t mac[RPMB_KEY_MAC_LEN];
+
+ if (req == RPMB_REQ_READ_RESULT) {
+ /* just return the current result register */
+ goto exit;
+ }
+ memset(&sd->rpmb.result, 0, sizeof(sd->rpmb.result));
+ memcpy(sd->rpmb.result.nonce, frame->nonce, sizeof(sd->rpmb.result.nonce));
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_OK);
+ stw_be_p(&sd->rpmb.result.req_resp, RPMB_RESP(req));
+
+ if (!sd->rpmb.key_set && req != RPMB_REQ_PROGRAM_AUTH_KEY) {
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_NO_AUTH_KEY);
+ goto exit;
}
+
+ switch (req) {
+ case RPMB_REQ_PROGRAM_AUTH_KEY:
+ if (sd->rpmb.key_set) {
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_WRITE_FAILURE);
+ break;
+ }
+ memcpy(sd->rpmb.key, frame->key_mac, sizeof(sd->rpmb.key));
+ sd->rpmb.key_set = 1;
+ break;
+ case RPMB_REQ_READ_WRITE_COUNTER:
+ stl_be_p(&sd->rpmb.result.write_counter, sd->rpmb.write_counter);
+ break;
+ case RPMB_REQ_AUTH_DATA_WRITE:
+ /* We only support single-block writes so far */
+ if (sd->multi_blk_cnt != 1) {
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_GENERAL_FAILURE);
+ break;
+ }
+ if (sd->rpmb.write_counter == 0xffffffff) {
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_WRITE_FAILURE);
+ break;
+ }
+ if (!rpmb_calc_hmac(sd, frame, 1, mac) ||
+ memcmp(frame->key_mac, mac, RPMB_KEY_MAC_LEN) != 0) {
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_AUTH_FAILURE);
+ break;
+ }
+ if (ldl_be_p(&frame->write_counter) != sd->rpmb.write_counter) {
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_COUNTER_FAILURE);
+ break;
+ }
+ sd->rpmb.result.address = frame->address;
+ addr = lduw_be_p(&frame->address) * RPMB_DATA_LEN + sd_part_offset(sd);
+ if (blk_pwrite(sd->blk, addr, RPMB_DATA_LEN, frame->data, 0) < 0) {
+ error_report("sd_blk_write: write error on host side");
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_WRITE_FAILURE);
+ } else {
+ sd->rpmb.write_counter++;
+ }
+ stl_be_p(&sd->rpmb.result.write_counter, sd->rpmb.write_counter);
+ break;
+ case RPMB_REQ_AUTH_DATA_READ:
+ sd->rpmb.result.address = frame->address;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "RPMB request %d not implemented\n", req);
+ stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_GENERAL_FAILURE);
+ break;
+ }
+exit:
+ if (sd->rpmb.write_counter == 0xffffffff) {
+ stw_be_p(&sd->rpmb.result.result,
+ lduw_be_p(&sd->rpmb.result.result) | RPMB_RESULT_COUTER_EXPIRED);
+ }
+ trace_sdcard_rpmb_write_block(req, lduw_be_p(&sd->rpmb.result.result));
}
static void sd_erase(SDState *sd)
@@ -1170,6 +1427,19 @@ static void emmc_function_switch(SDState *sd, uint32_t arg)
break;
}
+ if (index == EXT_CSD_PART_CONFIG) {
+ uint8_t part = b & EXT_CSD_PART_CONFIG_ACC_MASK;
+
+ if (((part == EXT_CSD_PART_CONFIG_ACC_BOOT1 ||
+ part == EXT_CSD_PART_CONFIG_ACC_BOOT2) && !sd->boot_part_size) ||
+ (part == EXT_CSD_PART_CONFIG_ACC_RPMB && !sd->rpmb_part_size)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "MMC switching to illegal partition\n");
+ sd->card_status |= R_CSR_SWITCH_ERROR_MASK;
+ return;
+ }
+ }
+
trace_sdcard_ext_csd_update(index, sd->ext_csd[index], b);
sd->ext_csd[index] = b;
}
@@ -1306,7 +1576,7 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
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->name, req.cmd, sd_mode_name(sd->mode),
+ sd->proto->name, req.cmd, sd_mode_name(sd_mode(sd)),
sd_version_str(sd->spec_version));
return sd_illegal;
@@ -1359,7 +1629,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
const void *data, size_t size)
{
if (sd->state != sd_transfer_state) {
- sd_invalid_state_for_cmd(sd, req);
+ return sd_invalid_state_for_cmd(sd, req);
}
sd->state = sd_sendingdata_state;
@@ -1395,14 +1665,6 @@ 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;
-
- return sd_r1;
-}
-
/* CMD2 */
static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
{
@@ -1474,11 +1736,17 @@ static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req)
/* CMD6 */
static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
{
- if (sd->mode != sd_data_transfer_mode) {
+ if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
- if (sd->state != sd_transfer_state) {
- return sd_invalid_state_for_cmd(sd, req);
+ if (sd_is_spi(sd)) {
+ if (sd->state == sd_idle_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
+ } else {
+ if (sd->state != sd_transfer_state) {
+ return sd_invalid_state_for_cmd(sd, req);
+ }
}
sd_function_switch(sd, req.arg);
@@ -1542,9 +1810,6 @@ static sd_rsp_type_t sd_cmd_DE_SELECT_CARD(SDState *sd, SDRequest req)
/* CMD8 */
static sd_rsp_type_t sd_cmd_SEND_IF_COND(SDState *sd, SDRequest req)
{
- if (sd->spec_version < SD_PHY_SPECv2_00_VERS) {
- return sd_cmd_illegal(sd, req);
- }
if (sd->state != sd_idle_state) {
return sd_invalid_state_for_cmd(sd, req);
}
@@ -1571,14 +1836,30 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
sd->ext_csd, sizeof(sd->ext_csd));
}
-/* CMD9 */
-static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
+static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
+ const void *data, size_t size)
{
+ /*
+ * XXX as of v10.1.0-rc1 command is reached in sd_idle_state,
+ * so disable this check.
if (sd->state != sd_standby_state) {
return sd_invalid_state_for_cmd(sd, req);
}
- return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
- sd->csd, 16);
+ */
+
+ /*
+ * Since SPI returns CSD and CID on the DAT lines,
+ * switch to sd_transfer_state.
+ */
+ sd->state = sd_transfer_state;
+
+ return sd_cmd_to_sendingdata(sd, req, 0, data, size);
+}
+
+/* CMD9 */
+static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
+{
+ return spi_cmd_SEND_CxD(sd, req, sd->csd, sizeof(sd->csd));
}
static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
@@ -1593,11 +1874,7 @@ static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
/* CMD10 */
static sd_rsp_type_t spi_cmd_SEND_CID(SDState *sd, SDRequest req)
{
- if (sd->state != sd_standby_state) {
- return sd_invalid_state_for_cmd(sd, req);
- }
- return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
- sd->cid, 16);
+ return spi_cmd_SEND_CxD(sd, req, sd->cid, sizeof(sd->cid));
}
static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req)
@@ -1629,7 +1906,7 @@ static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req)
/* CMD13 */
static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
{
- if (sd->mode != sd_data_transfer_mode) {
+ if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
@@ -1646,7 +1923,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
}
if (sd_is_spi(sd)) {
- return sd_r2_s;
+ return spi_r2;
}
return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0;
@@ -1655,7 +1932,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
/* CMD15 */
static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req)
{
- if (sd->mode != sd_data_transfer_mode) {
+ if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
switch (sd->state) {
@@ -1960,8 +2237,14 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req)
/* ACMD13 */
static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req)
{
- return sd_cmd_to_sendingdata(sd, req, 0,
- sd->sd_status, sizeof(sd->sd_status));
+ sd_rsp_type_t rsp;
+
+ rsp = sd_cmd_to_sendingdata(sd, req, 0,
+ sd->sd_status, sizeof(sd->sd_status));
+ if (sd_is_spi(sd) && rsp != sd_illegal) {
+ return spi_r2;
+ }
+ return rsp;
}
/* ACMD22 */
@@ -2011,17 +2294,21 @@ static sd_rsp_type_t sd_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
}
}
- if (FIELD_EX32(sd->ocr & req.arg, OCR, VDD_VOLTAGE_WINDOW)) {
- /*
- * We accept any voltage. 10000 V is nothing.
- *
- * Once we're powered up, we advance straight to ready state
- * unless it's an enquiry ACMD41 (bits 23:0 == 0).
- */
+ if (sd_is_spi(sd)) {
sd->state = sd_ready_state;
+ return sd_r1;
+ } else {
+ if (FIELD_EX32(sd->ocr & req.arg, OCR, VDD_VOLTAGE_WINDOW)) {
+ /*
+ * We accept any voltage. 10000 V is nothing.
+ *
+ * Once we're powered up, we advance straight to ready state
+ * unless it's an enquiry ACMD41 (bits 23:0 == 0).
+ */
+ sd->state = sd_ready_state;
+ }
+ return sd_r3;
}
-
- return sd_r3;
}
/* ACMD42 */
@@ -2052,7 +2339,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
if (req.cmd != 55 || sd->expecting_acmd) {
trace_sdcard_normal_command(sd->proto->name,
sd->last_cmd_name, req.cmd,
- req.arg, sd_state_name(sd->state));
+ req.arg,
+ sd_mode_name(sd_mode(sd)),
+ sd_state_name(sd->state));
}
/* Not interpreting this as an app command */
@@ -2138,7 +2427,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
{
sd->last_cmd_name = sd_acmd_name(sd, req.cmd);
trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name,
- req.cmd, req.arg, sd_state_name(sd->state));
+ req.cmd, req.arg,
+ sd_mode_name(sd_mode(sd)),
+ sd_state_name(sd->state));
sd->card_status |= APP_CMD;
if (sd->proto->acmd[req.cmd].handler) {
@@ -2193,13 +2484,14 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
return cmd_class == 0 || cmd_class == 7;
}
-int sd_do_command(SDState *sd, SDRequest *req,
- uint8_t *response) {
+static size_t sd_do_command(SDState *sd, SDRequest *req,
+ uint8_t *response, size_t respsz)
+{
int last_state;
sd_rsp_type_t rtype;
int rsplen;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) {
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return 0;
}
@@ -2237,7 +2529,6 @@ int sd_do_command(SDState *sd, SDRequest *req,
}
last_state = sd->state;
- sd_set_mode(sd);
if (sd->expecting_acmd) {
sd->expecting_acmd = false;
@@ -2257,36 +2548,37 @@ int sd_do_command(SDState *sd, SDRequest *req,
}
send_response:
+ rsplen = sd_response_size(sd, rtype);
+ assert(rsplen <= respsz);
+
switch (rtype) {
case sd_r1:
case sd_r1b:
sd_response_r1_make(sd, response);
- rsplen = 4;
+ break;
+
+ case spi_r2:
+ spi_response_r2_make(sd, response);
break;
case sd_r2_i:
memcpy(response, sd->cid, sizeof(sd->cid));
- rsplen = 16;
break;
case sd_r2_s:
memcpy(response, sd->csd, sizeof(sd->csd));
- rsplen = 16;
break;
case sd_r3:
sd_response_r3_make(sd, response);
- rsplen = 4;
break;
case sd_r6:
sd_response_r6_make(sd, response);
- rsplen = 4;
break;
case sd_r7:
sd_response_r7_make(sd, response);
- rsplen = 4;
break;
case sd_r0:
@@ -2298,7 +2590,6 @@ send_response:
sd->data_offset = 0;
/* fall-through */
case sd_illegal:
- rsplen = 0;
break;
default:
g_assert_not_reached();
@@ -2346,12 +2637,14 @@ static bool sd_generic_read_byte(SDState *sd, uint8_t *value)
return false;
}
-void sd_write_byte(SDState *sd, uint8_t value)
+static void sd_write_byte(SDState *sd, uint8_t value)
{
+ unsigned int partition_access;
int i;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return;
+ }
if (sd->state != sd_receivingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -2396,7 +2689,13 @@ 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;
- sd_blk_write(sd, sd->data_start, sd->data_offset);
+ 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_write(sd, sd->data_start, sd->data_offset);
+ } else {
+ sd_blk_write(sd, sd->data_start, sd->data_offset);
+ }
sd->blk_written++;
sd->data_start += sd->blk_len;
sd->data_offset = 0;
@@ -2475,15 +2774,17 @@ void sd_write_byte(SDState *sd, uint8_t value)
}
}
-uint8_t sd_read_byte(SDState *sd)
+static uint8_t sd_read_byte(SDState *sd)
{
/* TODO: Append CRCs */
const uint8_t dummy_byte = 0x00;
+ unsigned int partition_access;
uint8_t ret;
uint32_t io_len;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return dummy_byte;
+ }
if (sd->state != sd_sendingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -2521,7 +2822,13 @@ uint8_t sd_read_byte(SDState *sd)
sd->data_start, io_len)) {
return dummy_byte;
}
- sd_blk_read(sd, sd->data_start, io_len);
+ 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);
+ } else {
+ sd_blk_read(sd, sd->data_start, io_len);
+ }
}
ret = sd->data[sd->data_offset ++];
@@ -2558,16 +2865,11 @@ static bool sd_data_ready(SDState *sd)
return sd->state == sd_sendingdata_state;
}
-void sd_enable(SDState *sd, bool enable)
-{
- sd->enable = enable;
-}
-
static const SDProto sd_proto_spi = {
.name = "SPI",
.cmd = {
[0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE},
- [1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
+ [1] = {0, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
[5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional},
[6] = {10, sd_spi, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION},
[8] = {0, sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND},
@@ -2603,7 +2905,7 @@ static const SDProto sd_proto_spi = {
[13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS},
[22] = {8, sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS},
[23] = {8, sd_spi, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT},
- [41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
+ [41] = {8, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
[42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT},
[51] = {8, sd_spi, "SEND_SCR", sd_acmd_SEND_SCR},
},
@@ -2722,7 +3024,6 @@ static void sd_instance_init(Object *obj)
sd->proto = sc->proto;
sd->last_cmd_name = "UNSET";
- sd->enable = true;
sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd);
}
@@ -2733,13 +3034,36 @@ static void sd_instance_finalize(Object *obj)
timer_free(sd->ocr_power_timer);
}
+static void sd_blk_size_error(SDState *sd, int64_t blk_size,
+ int64_t blk_size_aligned, const char *rule,
+ Error **errp)
+{
+ const char *dev_type = sd_is_emmc(sd) ? "eMMC" : "SD card";
+ char *blk_size_str;
+
+ blk_size_str = size_to_str(blk_size);
+ error_setg(errp, "Invalid %s size: %s", dev_type, blk_size_str);
+ g_free(blk_size_str);
+
+ blk_size_str = size_to_str(blk_size_aligned);
+ error_append_hint(errp,
+ "%s size has to be %s, e.g. %s.\n"
+ "You can resize disk images with"
+ " 'qemu-img resize <imagefile> <new-size>'\n"
+ "(note that this will lose data if you make the"
+ " image smaller than it currently is).\n",
+ dev_type, rule, blk_size_str);
+ g_free(blk_size_str);
+}
+
static void sd_realize(DeviceState *dev, Error **errp)
{
SDState *sd = SDMMC_COMMON(dev);
+ int64_t blk_size = -ENOMEDIUM;
int ret;
switch (sd->spec_version) {
- case SD_PHY_SPECv1_10_VERS
+ case SD_PHY_SPECv2_00_VERS
... SD_PHY_SPECv3_01_VERS:
break;
default:
@@ -2748,32 +3072,36 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
if (sd->blk) {
- int64_t blk_size;
-
if (!blk_supports_write_perm(sd->blk)) {
error_setg(errp, "Cannot use read-only drive as SD card");
return;
}
blk_size = blk_getlength(sd->blk);
- if (blk_size > 0 && !is_power_of_2(blk_size)) {
- int64_t blk_size_aligned = pow2ceil(blk_size);
- char *blk_size_str;
-
- blk_size_str = size_to_str(blk_size);
- error_setg(errp, "Invalid SD card size: %s", blk_size_str);
- g_free(blk_size_str);
-
- blk_size_str = size_to_str(blk_size_aligned);
- error_append_hint(errp,
- "SD card size has to be a power of 2, e.g. %s.\n"
- "You can resize disk images with"
- " 'qemu-img resize <imagefile> <new-size>'\n"
- "(note that this will lose data if you make the"
- " image smaller than it currently is).\n",
- blk_size_str);
- g_free(blk_size_str);
-
+ }
+ if (blk_size >= 0) {
+ blk_size -= sd->boot_part_size * 2 + sd->rpmb_part_size;
+ if (blk_size > SDSC_MAX_CAPACITY) {
+ if (sd_is_emmc(sd) &&
+ !QEMU_IS_ALIGNED(blk_size, 1 << HWBLOCK_SHIFT)) {
+ int64_t blk_size_aligned =
+ ((blk_size >> HWBLOCK_SHIFT) + 1) << HWBLOCK_SHIFT;
+ sd_blk_size_error(sd, blk_size, blk_size_aligned,
+ "multiples of 512", errp);
+ return;
+ } else if (!sd_is_emmc(sd) &&
+ !QEMU_IS_ALIGNED(blk_size, 512 * KiB)) {
+ int64_t blk_size_aligned = ((blk_size >> 19) + 1) << 19;
+ sd_blk_size_error(sd, blk_size, blk_size_aligned,
+ "multiples of 512K", errp);
+ return;
+ }
+ } else if (blk_size > 0 && !is_power_of_2(blk_size)) {
+ sd_blk_size_error(sd, blk_size, pow2ceil(blk_size), "a power of 2",
+ errp);
+ return;
+ } else if (blk_size < 0) {
+ error_setg(errp, "eMMC image smaller than boot partitions");
return;
}
@@ -2784,42 +3112,59 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
}
+ if (!QEMU_IS_ALIGNED(sd->boot_part_size, 128 * KiB) ||
+ sd->boot_part_size > 255 * 128 * KiB) {
+ g_autofree char *size_str = size_to_str(sd->boot_part_size);
+
+ error_setg(errp, "Invalid boot partition size: %s", size_str);
+ error_append_hint(errp,
+ "The boot partition size must be multiples of 128K"
+ "and not larger than 32640K.\n");
+ }
+ if (!QEMU_IS_ALIGNED(sd->rpmb_part_size, 128 * KiB) ||
+ sd->rpmb_part_size > 128 * 128 * KiB) {
+ char *size_str = size_to_str(sd->boot_part_size);
+
+ error_setg(errp, "Invalid RPMB partition size: %s", size_str);
+ g_free(size_str);
+ error_append_hint(errp,
+ "The RPMB partition size must be multiples of 128K"
+ "and not larger than 16384K.\n");
+ }
}
static void emmc_realize(DeviceState *dev, Error **errp)
{
SDState *sd = SDMMC_COMMON(dev);
- sd->spec_version = SD_PHY_SPECv3_01_VERS; /* Actually v4.3 */
+ sd->spec_version = SD_PHY_SPECv3_01_VERS; /* Actually v4.5 */
sd_realize(dev, errp);
}
-static Property sdmmc_common_properties[] = {
+static const Property sdmmc_common_properties[] = {
DEFINE_PROP_DRIVE("drive", SDState, blk),
- DEFINE_PROP_END_OF_LIST()
};
-static Property sd_properties[] = {
+static const Property sd_properties[] = {
DEFINE_PROP_UINT8("spec_version", SDState,
spec_version, SD_PHY_SPECv3_01_VERS),
- DEFINE_PROP_END_OF_LIST()
};
-static Property emmc_properties[] = {
+static const Property emmc_properties[] = {
DEFINE_PROP_UINT64("boot-partition-size", SDState, boot_part_size, 0),
DEFINE_PROP_UINT8("boot-config", SDState, boot_config, 0x0),
- DEFINE_PROP_END_OF_LIST()
+ DEFINE_PROP_UINT64("rpmb-partition-size", SDState, rpmb_part_size, 0),
};
-static void sdmmc_common_class_init(ObjectClass *klass, void *data)
+static void sdmmc_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
device_class_set_props(dc, sdmmc_common_properties);
dc->vmsd = &sd_vmstate;
- dc->reset = sd_reset;
+ device_class_set_legacy_reset(dc, sd_reset);
dc->bus_type = TYPE_SD_BUS;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
@@ -2831,12 +3176,11 @@ static void sdmmc_common_class_init(ObjectClass *klass, void *data)
sc->read_byte = sd_read_byte;
sc->receive_ready = sd_receive_ready;
sc->data_ready = sd_data_ready;
- sc->enable = sd_enable;
sc->get_inserted = sd_get_inserted;
sc->get_readonly = sd_get_readonly;
}
-static void sd_class_init(ObjectClass *klass, void *data)
+static void sd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
@@ -2855,7 +3199,7 @@ static void sd_class_init(ObjectClass *klass, void *data)
* board to ensure that ssi transfers only occur when the chip select
* is asserted.
*/
-static void sd_spi_class_init(ObjectClass *klass, void *data)
+static void sd_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
@@ -2864,16 +3208,16 @@ static void sd_spi_class_init(ObjectClass *klass, void *data)
sc->proto = &sd_proto_spi;
}
-static void emmc_class_init(ObjectClass *klass, void *data)
+static void emmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
+ assert(qcrypto_hmac_supports(QCRYPTO_HASH_ALGO_SHA256));
+
dc->desc = "eMMC";
dc->realize = emmc_realize;
device_class_set_props(dc, emmc_properties);
- /* Reason: Soldered on board */
- dc->user_creatable = false;
sc->proto = &sd_proto_emmc;