qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <philmd@linaro.org>
To: Jan Kiszka <jan.kiszka@siemens.com>, qemu-devel <qemu-devel@nongnu.org>
Cc: "Bin Meng" <bmeng.cn@gmail.com>,
	qemu-block@nongnu.org,
	"Ilias Apalodimas" <ilias.apalodimas@linaro.org>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Jan Lübbe" <jlu@pengutronix.de>,
	"Jerome Forissier" <jerome.forissier@linaro.org>
Subject: Re: [PATCH v5 3/6] hw/sd/sdcard: Add basic support for RPMB partition
Date: Mon, 3 Nov 2025 16:08:53 +0100	[thread overview]
Message-ID: <66a62dd7-e4b7-407a-8402-8b9b5b08833e@linaro.org> (raw)
In-Reply-To: <091d69e0e15b951f6110938c8ebffc988204f52c.1760702638.git.jan.kiszka@siemens.com>

Hi Jan,

On 17/10/25 14:03, Jan Kiszka wrote:
> From: Jan Kiszka <jan.kiszka@siemens.com>
> 
> The Replay Protected Memory Block (RPMB) is available since eMMC 4.4
> which has been obsoleted by 4.41. Therefore lift the provided
> EXT_CSD_REV to 5 (4.41) and provide the basic logic to implement basic
> support for it. This allows to set the authentication key, read the
> write counter and authenticated perform data read and write requests.
> Those aren't actually authenticated yet, support for that will be added
> later.
> 
> The RPMB image needs to be added to backing block images after potential
> boot partitions and before the user data. It's size is controlled by
> the rpmb-partition-size property.
> 
> Also missing in this version (and actually not only for RPMB bits) is
> persistence of registers that are supposed to survive power cycles. Most
> prominent are the write counters or the authentication key. This feature
> can be added later, e.g. by append a state structure to the backing
> block image.
> 
> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> ---
>   hw/sd/sd.c             | 206 +++++++++++++++++++++++++++++++++++++++--
>   hw/sd/sdmmc-internal.h |  21 +++++
>   hw/sd/trace-events     |   2 +
>   3 files changed, 221 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index 305ea251cb..918fe9f79f 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -117,6 +117,20 @@ typedef struct SDProto {
>       } cmd[SDMMC_CMD_MAX], acmd[SDMMC_CMD_MAX];
>   } SDProto;
>   

   #define RPMB_STUFF_LEN      196

> +#define RPMB_KEY_MAC_LEN    32
> +
> +typedef 

QEMU_PACKED (better safe than sorry).

> struct {
> +    uint8_t stuff_bytes[196];
> +    uint8_t key_mac[RPMB_KEY_MAC_LEN];
> +    uint8_t data[256];
> +    uint8_t nonce[16];
> +    uint32_t write_counter;
> +    uint16_t address;
> +    uint16_t block_count;
> +    uint16_t result;
> +    uint16_t req_resp;
> +} RPMBDataFrame;
> +
>   struct SDState {
>       DeviceState parent_obj;
>   
> @@ -140,6 +154,7 @@ struct SDState {
>   
>       uint8_t spec_version;
>       uint64_t boot_part_size;
> +    uint64_t rpmb_part_size;
>       BlockBackend *blk;
>       uint8_t boot_config;
>   
> @@ -172,6 +187,10 @@ struct SDState {
>       uint32_t data_offset;
>       size_t data_size;
>       uint8_t data[512];
> +    RPMBDataFrame rpmb_result;
> +    uint32_t rpmb_write_counter;
> +    uint8_t rpmb_key[32];
> +    uint8_t rpmb_key_set;

Matter of style:

        struct {
            uint32_t write_counter;
            uint8_t key[RPMB_KEY_MAC_LEN];
            uint8_t key_set;
            RPMBDataFrame result;
        } rpmb;

>       QEMUTimer *ocr_power_timer;
>       uint8_t dat_lines;
>       bool cmd_line;
> @@ -506,7 +525,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;
> @@ -834,7 +855,8 @@ static uint32_t sd_blk_len(SDState *sd)
>   /*
>    * This requires a disk image that has two boot partitions inserted at the
>    * beginning of it, followed by an RPMB partition. The size of the boot
> - * partitions is the "boot-partition-size" property.
> + * partitions is the "boot-partition-size" property, the one of the RPMB
> + * partition is 'rpmb-partition-size'.
>    */
>   static uint32_t sd_part_offset(SDState *sd)
>   {
> @@ -848,11 +870,13 @@ static uint32_t sd_part_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;
> +        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_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();
>       }
> @@ -891,7 +915,7 @@ static void sd_reset(DeviceState *dev)
>       }
>       size = sect << HWBLOCK_SHIFT;
>       if (sd_is_emmc(sd)) {
> -        size -= sd->boot_part_size * 2;
> +        size -= sd->boot_part_size * 2 + sd->rpmb_part_size;
>       }
>   
>       sect = sd_addr_to_wpnum(size) + 1;
> @@ -979,6 +1003,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, 256),
> +        VMSTATE_UINT8_ARRAY(rpmb_result.nonce, SDState, 16),
> +        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;
> @@ -1045,6 +1097,7 @@ static const VMStateDescription sd_vmstate = {
>       .subsections = (const VMStateDescription * const []) {
>           &sd_ocr_vmstate,
>           &emmc_extcsd_vmstate,
> +        &emmc_rpmb_vmstate,
>           NULL
>       },
>   };
> @@ -1067,6 +1120,105 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
>       }
>   }
>   
> +static void emmc_rpmb_blk_read(SDState *sd, uint64_t addr, uint32_t len)
> +{
> +    uint16_t resp = be16_to_cpu(sd->rpmb_result.req_resp);
> +    uint16_t result = be16_to_cpu(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 = be16_to_cpu(sd->rpmb_result.address);
> +        if (sd->rpmb_result.block_count == 0) {
> +            sd->rpmb_result.block_count = cpu_to_be16(sd->multi_blk_cnt);
> +        } else {
> +            curr_block += be16_to_cpu(sd->rpmb_result.block_count) -
> +                sd->multi_blk_cnt;
> +        }
> +        addr = curr_block * 256 + sd_part_offset(sd);
> +        if (blk_pread(sd->blk, addr, 256, sd->rpmb_result.data, 0) < 0) {

Would be nice to re-use sd_blk_read(), but I notice we want to read the
frame data to then copy the whole message into sd->data.

> +            fprintf(stderr, "sd_blk_read: read error on host side\n");

Although a pre-existing pattern in this file, no new fprintf(stderr)
please. Better use the Error* API, otherwise error_report().

               error_report("sd_blk_read: read error on host side");

> +            memset(sd->rpmb_result.data, 0, sizeof(sd->rpmb_result.data));
> +            sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_READ_FAILURE |
> +                (result & RPMB_RESULT_COUTER_EXPIRED));
> +        }
> +    }
> +    memcpy(sd->data, &sd->rpmb_result, sizeof(sd->rpmb_result));
> +
> +    trace_sdcard_rpmb_read_block(resp, curr_block,
> +                                 be16_to_cpu(sd->rpmb_result.result));
> +}
> +
> +static void emmc_rpmb_blk_write(SDState *sd, uint64_t addr, uint32_t len)
> +{
> +    RPMBDataFrame *frame = (RPMBDataFrame *)sd->data;
> +    uint16_t req = be16_to_cpu(frame->req_resp);
> +
> +    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));
> +    sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_OK);
> +    sd->rpmb_result.req_resp = cpu_to_be16(RPMB_RESP(req));
> +
> +    if (!sd->rpmb_key_set && req != RPMB_REQ_PROGRAM_AUTH_KEY) {
> +        sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_NO_AUTH_KEY);
> +        goto exit;
> +    }
> +
> +    switch (req) {
> +    case RPMB_REQ_PROGRAM_AUTH_KEY:
> +        if (sd->rpmb_key_set) {
> +            sd->rpmb_result.result = cpu_to_be16(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:
> +        sd->rpmb_result.write_counter = cpu_to_be32(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) {
> +            sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_GENERAL_FAILURE);
> +            break;
> +        }
> +        if (sd->rpmb_write_counter == 0xffffffff) {
> +            sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
> +            break;
> +        }
> +        if (be32_to_cpu(frame->write_counter) != sd->rpmb_write_counter) {
> +            sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_COUNTER_FAILURE);
> +            break;
> +        }
> +        sd->rpmb_result.address = frame->address;
> +        addr = be16_to_cpu(frame->address) * 256 + sd_part_offset(sd);
> +        if (blk_pwrite(sd->blk, addr, 256, frame->data, 0) < 0) {
> +            fprintf(stderr, "sd_blk_write: write error on host side\n");

                error_report("sd_blk_write: write error on host side");

> +            sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
> +        } else {
> +            sd->rpmb_write_counter++;
> +        }
> +        sd->rpmb_result.write_counter = cpu_to_be32(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);
> +        sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_GENERAL_FAILURE);
> +        break;
> +    }
> +exit:
> +    if (sd->rpmb_write_counter == 0xffffffff) {
> +        sd->rpmb_result.result |= cpu_to_be16(RPMB_RESULT_COUTER_EXPIRED);
> +    }
> +    trace_sdcard_rpmb_write_block(req, be16_to_cpu(sd->rpmb_result.result));
> +}
> +
>   static void sd_erase(SDState *sd)
>   {
>       uint64_t erase_start = sd->erase_start;
> @@ -1180,6 +1332,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;
>   }
> @@ -2378,6 +2543,7 @@ static bool sd_generic_read_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)) {
> @@ -2427,7 +2593,13 @@ static 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;
> @@ -2510,6 +2682,7 @@ 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;
>   
> @@ -2553,7 +2726,13 @@ static 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 ++];
>   
> @@ -2805,7 +2984,7 @@ static void sd_realize(DeviceState *dev, Error **errp)
>           blk_size = blk_getlength(sd->blk);
>       }
>       if (blk_size >= 0) {
> -        blk_size -= sd->boot_part_size * 2;
> +        blk_size -= sd->boot_part_size * 2 + sd->rpmb_part_size;
>           if (blk_size > SDSC_MAX_CAPACITY) {
>               if (sd_is_emmc(sd) && blk_size % (1 << HWBLOCK_SHIFT) != 0) {
>                   int64_t blk_size_aligned =
> @@ -2844,13 +3023,23 @@ static void sd_realize(DeviceState *dev, Error **errp)
>                             "The boot partition size must be multiples of 128K"
>                             "and not larger than 32640K.\n");
>       }
> +    if (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);
>   }
> @@ -2867,6 +3056,7 @@ static const Property sd_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_UINT64("rpmb-partition-size", SDState, rpmb_part_size, 0),
>   };
>   
>   static void sdmmc_common_class_init(ObjectClass *klass, const void *data)
> diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h
> index ce6bc4e6ec..c4a9aa8edf 100644
> --- a/hw/sd/sdmmc-internal.h
> +++ b/hw/sd/sdmmc-internal.h
> @@ -118,9 +118,30 @@ DECLARE_OBJ_CHECKERS(SDState, SDCardClass, SDMMC_COMMON, TYPE_SDMMC_COMMON)
>   #define EXT_CSD_PART_CONFIG_ACC_DEFAULT         (0x0)
>   #define EXT_CSD_PART_CONFIG_ACC_BOOT1           (0x1)
>   #define EXT_CSD_PART_CONFIG_ACC_BOOT2           (0x2)
> +#define EXT_CSD_PART_CONFIG_ACC_RPMB            (0x3)
>   
>   #define EXT_CSD_PART_CONFIG_EN_MASK             (0x7 << 3)
>   #define EXT_CSD_PART_CONFIG_EN_BOOT0            (0x1 << 3)
>   #define EXT_CSD_PART_CONFIG_EN_USER             (0x7 << 3)
>   
> +#define RPMB_REQ_PROGRAM_AUTH_KEY       (1)
> +#define RPMB_REQ_READ_WRITE_COUNTER     (2)
> +#define RPMB_REQ_AUTH_DATA_WRITE        (3)
> +#define RPMB_REQ_AUTH_DATA_READ         (4)
> +#define RPMB_REQ_READ_RESULT            (5)
> +#define RPMB_REQ_AUTH_CONFIG_WRITE      (6)
> +#define RPMB_REQ_AUTH_CONFIG_READ       (7)
> +
> +#define RPMB_RESP(__req__)              ((__req__) << 8)
> +
> +#define RPMB_RESULT_OK                  (0)
> +#define RPMB_RESULT_GENERAL_FAILURE     (1)
> +#define RPMB_RESULT_AUTH_FAILURE        (2)
> +#define RPMB_RESULT_COUNTER_FAILURE     (3)
> +#define RPMB_RESULT_ADDRESS_FAILURE     (4)
> +#define RPMB_RESULT_WRITE_FAILURE       (5)
> +#define RPMB_RESULT_READ_FAILURE        (6)
> +#define RPMB_RESULT_NO_AUTH_KEY         (7)

> +#define RPMB_RESULT_COUTER_EXPIRED      (0x80)
> +
>   #endif

If you are OK, I'd like to squash:

-- >8 --diff --git a/hw/sd/sd.c b/hw/sd/sd.c
diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h
index c4a9aa8edf6..c115f472efe 100644
--- a/hw/sd/sdmmc-internal.h
+++ b/hw/sd/sdmmc-internal.h
@@ -144,2 +144,3 @@ DECLARE_OBJ_CHECKERS(SDState, SDCardClass, 
SDMMC_COMMON, TYPE_SDMMC_COMMON)
  #define RPMB_RESULT_NO_AUTH_KEY         (7)
+
  #define RPMB_RESULT_COUTER_EXPIRED      (0x80)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index f8883860fb1..ac8f6b94746 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -119,8 +119,10 @@ typedef struct SDProto {

+#define RPMB_STUFF_LEN      196
  #define RPMB_KEY_MAC_LEN    32
+#define RPMB_DATA_LEN       256     /* one RPMB block is half a sector */

-typedef struct {
-    uint8_t stuff_bytes[196];
+typedef struct QEMU_PACKED {
+    uint8_t stuff_bytes[RPMB_STUFF_LEN];
      uint8_t key_mac[RPMB_KEY_MAC_LEN];
-    uint8_t data[256];
+    uint8_t data[RPMB_DATA_LEN];
      uint8_t nonce[16];
@@ -133,2 +135,5 @@ typedef struct {

+QEMU_BUILD_BUG_MSG(sizeof(RPMBDataFrame) != 512,
+                   "invalid RPMBDataFrame size");
+
  struct SDState {
@@ -191,3 +196,3 @@ struct SDState {
      uint32_t rpmb_write_counter;
-    uint8_t rpmb_key[32];
+    uint8_t rpmb_key[RPMB_KEY_MAC_LEN];
      uint8_t rpmb_key_set;
@@ -1019,3 +1024,3 @@ static const VMStateDescription emmc_rpmb_vmstate = {
          VMSTATE_UINT8_ARRAY(rpmb_result.key_mac, SDState, 
RPMB_KEY_MAC_LEN),
-        VMSTATE_UINT8_ARRAY(rpmb_result.data, SDState, 256),
+        VMSTATE_UINT8_ARRAY(rpmb_result.data, SDState, RPMB_DATA_LEN),
          VMSTATE_UINT8_ARRAY(rpmb_result.nonce, SDState, 16),
@@ -1137,5 +1142,6 @@ static void emmc_rpmb_blk_read(SDState *sd, 
uint64_t addr, uint32_t len)
          }
-        addr = curr_block * 256 + sd_part_offset(sd);
-        if (blk_pread(sd->blk, addr, 256, sd->rpmb_result.data, 0) < 0) {
-            fprintf(stderr, "sd_blk_read: read error on host side\n");
+        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));
@@ -1197,5 +1203,5 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
          sd->rpmb_result.address = frame->address;
-        addr = be16_to_cpu(frame->address) * 256 + sd_part_offset(sd);
-        if (blk_pwrite(sd->blk, addr, 256, frame->data, 0) < 0) {
-            fprintf(stderr, "sd_blk_write: write error on host side\n");
+        addr = be16_to_cpu(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");
              sd->rpmb_result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
@@ -3027,3 +3033,3 @@ static void sd_realize(DeviceState *dev, Error **errp)
      }
-    if (sd->rpmb_part_size % (128 * KiB) ||
+    if (!QEMU_IS_ALIGNED(sd->rpmb_part_size, 128 * KiB) ||
          sd->rpmb_part_size > 128 * 128 * KiB) {
---

And on top, if you don't mind (but can do that later):

-- >8 --
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index ac8f6b94746..71f396cb4d6 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -195,4 +195,6 @@ struct SDState {
-    RPMBDataFrame rpmb_result;
-    uint32_t rpmb_write_counter;
-    uint8_t rpmb_key[RPMB_KEY_MAC_LEN];
-    uint8_t rpmb_key_set;
+    struct {
+        uint32_t write_counter;
+        uint8_t key[RPMB_KEY_MAC_LEN];
+        uint8_t key_set;
+        RPMBDataFrame result;
+    } rpmb;
@@ -1024,11 +1026,11 @@ static const VMStateDescription 
emmc_rpmb_vmstate = {
-        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, 16),
-        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_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, 16),
+        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),
@@ -1130,2 +1132,2 @@ static void emmc_rpmb_blk_read(SDState *sd, 
uint64_t addr, uint32_t len)
-    uint16_t resp = be16_to_cpu(sd->rpmb_result.req_resp);
-    uint16_t result = be16_to_cpu(sd->rpmb_result.result);
+    uint16_t resp = be16_to_cpu(sd->rpmb.result.req_resp);
+    uint16_t result = be16_to_cpu(sd->rpmb.result.result);
@@ -1136,3 +1138,3 @@ static void emmc_rpmb_blk_read(SDState *sd, 
uint64_t addr, uint32_t len)
-        curr_block = be16_to_cpu(sd->rpmb_result.address);
-        if (sd->rpmb_result.block_count == 0) {
-            sd->rpmb_result.block_count = cpu_to_be16(sd->multi_blk_cnt);
+        curr_block = be16_to_cpu(sd->rpmb.result.address);
+        if (sd->rpmb.result.block_count == 0) {
+            sd->rpmb.result.block_count = cpu_to_be16(sd->multi_blk_cnt);
@@ -1140 +1142 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t 
addr, uint32_t len)
-            curr_block += be16_to_cpu(sd->rpmb_result.block_count) -
+            curr_block += be16_to_cpu(sd->rpmb.result.block_count) -
@@ -1144,2 +1146 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t 
addr, uint32_t len)
-        if (blk_pread(sd->blk, addr, RPMB_DATA_LEN,
-                      sd->rpmb_result.data, 0) < 0) {
+        if (blk_pread(sd->blk, addr, RPMB_DATA_LEN, 
sd->rpmb.result.data, 0) < 0) {
@@ -1147,2 +1148,2 @@ static void emmc_rpmb_blk_read(SDState *sd, 
uint64_t addr, uint32_t len)
-            memset(sd->rpmb_result.data, 0, sizeof(sd->rpmb_result.data));
-            sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_READ_FAILURE |
+            memset(sd->rpmb.result.data, 0, sizeof(sd->rpmb.result.data));
+            sd->rpmb.result.result = cpu_to_be16(RPMB_RESULT_READ_FAILURE |
@@ -1152 +1153 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t 
addr, uint32_t len)
-    memcpy(sd->data, &sd->rpmb_result, sizeof(sd->rpmb_result));
+    memcpy(sd->data, &sd->rpmb.result, sizeof(sd->rpmb.result));
@@ -1155 +1156 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t 
addr, uint32_t len)
-                                 be16_to_cpu(sd->rpmb_result.result));
+                                 be16_to_cpu(sd->rpmb.result.result));
@@ -1167,4 +1168,4 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-    memset(&sd->rpmb_result, 0, sizeof(sd->rpmb_result));
-    memcpy(sd->rpmb_result.nonce, frame->nonce, 
sizeof(sd->rpmb_result.nonce));
-    sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_OK);
-    sd->rpmb_result.req_resp = cpu_to_be16(RPMB_RESP(req));
+    memset(&sd->rpmb.result, 0, sizeof(sd->rpmb.result));
+    memcpy(sd->rpmb.result.nonce, frame->nonce, 
sizeof(sd->rpmb.result.nonce));
+    sd->rpmb.result.result = cpu_to_be16(RPMB_RESULT_OK);
+    sd->rpmb.result.req_resp = cpu_to_be16(RPMB_RESP(req));
@@ -1172,2 +1173,2 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-    if (!sd->rpmb_key_set && req != RPMB_REQ_PROGRAM_AUTH_KEY) {
-        sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_NO_AUTH_KEY);
+    if (!sd->rpmb.key_set && req != RPMB_REQ_PROGRAM_AUTH_KEY) {
+        sd->rpmb.result.result = cpu_to_be16(RPMB_RESULT_NO_AUTH_KEY);
@@ -1179,2 +1180,2 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-        if (sd->rpmb_key_set) {
-            sd->rpmb_result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
+        if (sd->rpmb.key_set) {
+            sd->rpmb.result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
@@ -1183,2 +1184,2 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-        memcpy(sd->rpmb_key, frame->key_mac, sizeof(sd->rpmb_key));
-        sd->rpmb_key_set = 1;
+        memcpy(sd->rpmb.key, frame->key_mac, sizeof(sd->rpmb.key));
+        sd->rpmb.key_set = 1;
@@ -1187 +1188 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-        sd->rpmb_result.write_counter = 
cpu_to_be32(sd->rpmb_write_counter);
+        sd->rpmb.result.write_counter = 
cpu_to_be32(sd->rpmb.write_counter);
@@ -1192 +1193 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-            sd->rpmb_result.result = 
cpu_to_be16(RPMB_RESULT_GENERAL_FAILURE);
+            sd->rpmb.result.result = 
cpu_to_be16(RPMB_RESULT_GENERAL_FAILURE);
@@ -1195,2 +1196,2 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-        if (sd->rpmb_write_counter == 0xffffffff) {
-            sd->rpmb_result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
+        if (sd->rpmb.write_counter == 0xffffffff) {
+            sd->rpmb.result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
@@ -1199,2 +1200,2 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-        if (be32_to_cpu(frame->write_counter) != sd->rpmb_write_counter) {
-            sd->rpmb_result.result = 
cpu_to_be16(RPMB_RESULT_COUNTER_FAILURE);
+        if (be32_to_cpu(frame->write_counter) != sd->rpmb.write_counter) {
+            sd->rpmb.result.result = 
cpu_to_be16(RPMB_RESULT_COUNTER_FAILURE);
@@ -1203,3 +1204,3 @@ static void emmc_rpmb_blk_write(SDState *sd, 
uint64_t addr, uint32_t len)
-        sd->rpmb_result.address = frame->address;
-        addr = be16_to_cpu(frame->address) * RPMB_DATA_LEN + 
sd_part_offset(sd);
-        if (blk_pwrite(sd->blk, addr, RPMB_DATA_LEN, frame->data, 0) < 0) {
+        sd->rpmb.result.address = frame->address;
+        addr = be16_to_cpu(frame->address) * 256 + sd_part_offset(sd);
+        if (blk_pwrite(sd->blk, addr, 256, frame->data, 0) < 0) {
@@ -1207 +1208 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-            sd->rpmb_result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
+            sd->rpmb.result.result = 
cpu_to_be16(RPMB_RESULT_WRITE_FAILURE);
@@ -1209 +1210 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-            sd->rpmb_write_counter++;
+            sd->rpmb.write_counter++;
@@ -1211 +1212 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-        sd->rpmb_result.write_counter = 
cpu_to_be32(sd->rpmb_write_counter);
+        sd->rpmb.result.write_counter = 
cpu_to_be32(sd->rpmb.write_counter);
@@ -1214 +1215 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-        sd->rpmb_result.address = frame->address;
+        sd->rpmb.result.address = frame->address;
@@ -1218 +1219 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t 
addr, uint32_t len)
-        sd->rpmb_result.result = cpu_to_be16(RPMB_RESULT_GENERAL_FAILURE);
+        sd->rpmb.result.result = cpu_to_be16(RPMB_RESULT_GENERAL_FAILURE);
@@ -1222,2 +1223,2 @@ exit:
-    if (sd->rpmb_write_counter == 0xffffffff) {
-        sd->rpmb_result.result |= cpu_to_be16(RPMB_RESULT_COUTER_EXPIRED);
+    if (sd->rpmb.write_counter == 0xffffffff) {
+        sd->rpmb.result.result |= cpu_to_be16(RPMB_RESULT_COUTER_EXPIRED);
@@ -1225 +1226 @@ exit:
-    trace_sdcard_rpmb_write_block(req, 
be16_to_cpu(sd->rpmb_result.result));
+    trace_sdcard_rpmb_write_block(req, 
be16_to_cpu(sd->rpmb.result.result));
---

Regards,

Phil.


  reply	other threads:[~2025-11-03 15:09 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-17 12:03 [PATCH v5 0/6] sd: Add RPMB emulation to eMMC model Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 1/6] hw/sd/sdcard: Fix size check for backing block image Jan Kiszka
2025-10-20  7:29   ` Cédric Le Goater
2025-10-30 22:10   ` Philippe Mathieu-Daudé
2025-10-17 12:03 ` [PATCH v5 2/6] hw/sd/sdcard: Allow user-instantiated eMMC Jan Kiszka
2025-10-27 11:55   ` Daniel P. Berrangé
2025-10-27 12:23     ` Philippe Mathieu-Daudé
2025-10-27 12:35       ` Daniel P. Berrangé
2025-10-27 12:44         ` Philippe Mathieu-Daudé
2025-10-30 14:17           ` Jan Lübbe
2025-10-27 12:45       ` Jan Lübbe
2025-10-30 16:50   ` Jan Lübbe
2025-10-30 18:10     ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 3/6] hw/sd/sdcard: Add basic support for RPMB partition Jan Kiszka
2025-11-03 15:08   ` Philippe Mathieu-Daudé [this message]
2025-11-04  6:34     ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 4/6] hw/sd/sdcard: Handle RPMB MAC field Jan Kiszka
2025-11-03 15:18   ` Philippe Mathieu-Daudé
2025-11-04  6:43     ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 5/6] scripts: Add helper script to generate eMMC block device images Jan Kiszka
2025-11-03 13:12   ` Philippe Mathieu-Daudé
2025-11-04  6:30     ` Jan Kiszka
2025-11-04  9:26       ` Jan Kiszka
2025-11-04 12:33         ` Philippe Mathieu-Daudé
2025-11-04 12:40           ` Jan Kiszka
2025-11-04 14:14             ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 6/6] docs: Add eMMC device model description Jan Kiszka
2025-11-03 13:15   ` Philippe Mathieu-Daudé
2025-10-20  7:28 ` [PATCH v5 0/6] sd: Add RPMB emulation to eMMC model Cédric Le Goater
2025-10-27 11:15 ` Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=66a62dd7-e4b7-407a-8402-8b9b5b08833e@linaro.org \
    --to=philmd@linaro.org \
    --cc=alex.bennee@linaro.org \
    --cc=bmeng.cn@gmail.com \
    --cc=ilias.apalodimas@linaro.org \
    --cc=jan.kiszka@siemens.com \
    --cc=jerome.forissier@linaro.org \
    --cc=jlu@pengutronix.de \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).