* [PULL 0/8] Misc HW patches for 2025-11-04
@ 2025-11-04 17:48 Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 1/8] hw/sd/sdcard: Fix size check for backing block image Philippe Mathieu-Daudé
` (8 more replies)
0 siblings, 9 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
The following changes since commit e9c692eabbbb7f395347605a6ef33a32d398ea25:
Merge tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu into staging (2025-11-04 15:17:31 +0100)
are available in the Git repository at:
https://github.com/philmd/qemu.git tags/hw-misc-20251104
for you to fetch changes up to f79fec0275ee7a5151ced9b893c4af676c7f5db6:
hw/audio: Remove dead code from ac97_realize (2025-11-04 18:19:16 +0100)
----------------------------------------------------------------
Misc HW patches
- Add RPMB emulation to eMMC model :)
- Use generic MachineState::fdt field in microvm machine
- Remove dead code in ac97_realize()
----------------------------------------------------------------
Jan Kiszka (5):
hw/sd/sdcard: Fix size check for backing block image
hw/sd/sdcard: Add basic support for RPMB partition
hw/sd/sdcard: Handle RPMB MAC field
scripts: Add helper script to generate eMMC block device images
docs: Add eMMC device model description
Jan Luebbe (1):
hw/sd/sdcard: Allow user creation of eMMCs
Luigi Leonardi (1):
hw/i386/microvm: Use fdt field from MachineState
Osama Abdelkader (1):
hw/audio: Remove dead code from ac97_realize
docs/system/device-emulation.rst | 1 +
docs/system/devices/emmc.rst | 55 +++++
hw/sd/sdmmc-internal.h | 22 ++
include/hw/i386/microvm.h | 2 -
hw/audio/ac97.c | 19 --
hw/i386/microvm-dt.c | 96 ++++----
hw/sd/sd.c | 368 ++++++++++++++++++++++++++++---
hw/sd/trace-events | 2 +
scripts/mkemmc.sh | 216 ++++++++++++++++++
9 files changed, 686 insertions(+), 95 deletions(-)
create mode 100644 docs/system/devices/emmc.rst
create mode 100755 scripts/mkemmc.sh
--
2.51.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PULL 1/8] hw/sd/sdcard: Fix size check for backing block image
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 2/8] hw/sd/sdcard: Allow user creation of eMMCs Philippe Mathieu-Daudé
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Jan Kiszka <jan.kiszka@siemens.com>
Alignment rules apply the the individual partitions (user, boot, later
on also RPMB) and depend both on the size of the image and the type of
the device. Up to and including 2GB, the power-of-2 rule applies to the
user data area. For larger images, multiples of 512 sectors must be used
for eMMC and multiples of 512K for SD-cards. Fix the check accordingly
and also detect if the image is too small to even hold the boot
partitions.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Warner Losh <imp@bsdimp.com>
Message-ID: <591f6d8a9dc86428723cb6876df6e717cc41a70e.1762261430.git.jan.kiszka@siemens.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
hw/sd/sd.c | 69 +++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 48 insertions(+), 21 deletions(-)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index d7a496d77c9..76e915e1900 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -2759,9 +2759,32 @@ 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) {
@@ -2774,32 +2797,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;
+ 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;
}
@@ -2810,7 +2837,7 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
}
- if (sd->boot_part_size % (128 * KiB) ||
+ 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);
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 2/8] hw/sd/sdcard: Allow user creation of eMMCs
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 1/8] hw/sd/sdcard: Fix size check for backing block image Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 3/8] hw/sd/sdcard: Add basic support for RPMB partition Philippe Mathieu-Daudé
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Jan Luebbe <jlu@pengutronix.de>
For testing eMMC-specific functionality (such as handling boot
partitions), it would be very useful to attach them to generic VMs such
as x86_64 via the sdhci-pci device:
...
-drive if=none,id=emmc-drive,file=emmc.img,format=raw \
-device sdhci-pci \
-device emmc,id=emmc0,drive=emmc-drive,boot-partition-size=1048576 \
...
While most eMMCs are soldered to boards, they can also be connected to
SD controllers with just a passive adapter, such as:
https://docs.radxa.com/en/accessories/emmc-to-usd
https://github.com/voltlog/emmc-wfbga153-microsd
The only change necessary to make the options above work is to avoid
disabling user_creatable, so do that. The SDHCI-PCI driver in the Linux
kernel already supports this just fine.
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Acked-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20241015135649.4189256-1-jlu@pengutronix.de>
Enable user-instantiation so that eMMCs can be created for PCI-attached
SD/MMC host controllers (such as sdhci-pci) on virt machines, for QA
purposes for the eMMC model itself and for complex firmware/OS
integrations using the upcoming RPMB partition support.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Message-ID: <e515cc80de261ff03b3141724298f20313259a85.1762261430.git.jan.kiszka@siemens.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
hw/sd/sd.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 76e915e1900..e43e1a10ebb 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -2930,8 +2930,6 @@ static void emmc_class_init(ObjectClass *klass, const void *data)
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;
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 3/8] hw/sd/sdcard: Add basic support for RPMB partition
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 1/8] hw/sd/sdcard: Fix size check for backing block image Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 2/8] hw/sd/sdcard: Allow user creation of eMMCs Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 4/8] hw/sd/sdcard: Handle RPMB MAC field Philippe Mathieu-Daudé
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
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>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <d57388b599e47f5c95f30be7571b77f9016289eb.1762261430.git.jan.kiszka@siemens.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
hw/sd/sdmmc-internal.h | 22 +++++
hw/sd/sd.c | 217 +++++++++++++++++++++++++++++++++++++++--
hw/sd/trace-events | 2 +
3 files changed, 233 insertions(+), 8 deletions(-)
diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h
index ce6bc4e6ec4..c115f472efe 100644
--- a/hw/sd/sdmmc-internal.h
+++ b/hw/sd/sdmmc-internal.h
@@ -118,9 +118,31 @@ 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
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index e43e1a10ebb..aa57c858cbb 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -117,6 +117,26 @@ 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
+
+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;
@@ -140,6 +160,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 +193,12 @@ struct SDState {
uint32_t data_offset;
size_t data_size;
uint8_t data[512];
+ 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 +533,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 +863,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 +878,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 +923,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 +1011,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;
@@ -1045,6 +1105,7 @@ static const VMStateDescription sd_vmstate = {
.subsections = (const VMStateDescription * const []) {
&sd_ocr_vmstate,
&emmc_extcsd_vmstate,
+ &emmc_rpmb_vmstate,
NULL
},
};
@@ -1067,6 +1128,108 @@ 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 = 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));
+ }
+ }
+ 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 emmc_rpmb_blk_write(SDState *sd, uint64_t addr, uint32_t len)
+{
+ RPMBDataFrame *frame = (RPMBDataFrame *)sd->data;
+ uint16_t req = lduw_be_p(&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));
+ 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 (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)
{
uint64_t erase_start = sd->erase_start;
@@ -1180,6 +1343,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 +2554,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 +2604,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 +2693,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 +2737,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 +2995,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) &&
!QEMU_IS_ALIGNED(blk_size, 1 << HWBLOCK_SHIFT)) {
@@ -2846,13 +3036,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 (!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);
}
@@ -2869,6 +3069,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/trace-events b/hw/sd/trace-events
index 8d49840917e..d30daa21431 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -59,6 +59,8 @@ sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t
sdcard_set_voltage(uint16_t millivolts) "%u mV"
sdcard_ext_csd_update(unsigned index, uint8_t oval, uint8_t nval) "index %u: 0x%02x -> 0x%02x"
sdcard_switch(unsigned access, unsigned index, unsigned value, unsigned set) "SWITCH acc:%u idx:%u val:%u set:%u"
+sdcard_rpmb_read_block(uint16_t resp, uint16_t read_addr, uint16_t result) "resp 0x%x read_addr 0x%x result 0x%x"
+sdcard_rpmb_write_block(uint16_t req, uint16_t result) "req 0x%x result 0x%x"
# pl181.c
pl181_command_send(uint8_t cmd, uint32_t arg) "sending CMD%02d arg 0x%08" PRIx32
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 4/8] hw/sd/sdcard: Handle RPMB MAC field
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
` (2 preceding siblings ...)
2025-11-04 17:48 ` [PULL 3/8] hw/sd/sdcard: Add basic support for RPMB partition Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 5/8] scripts: Add helper script to generate eMMC block device images Philippe Mathieu-Daudé
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Jan Kiszka <jan.kiszka@siemens.com>
Implement correct setting of the MAC field when passing RPMB frames back
to the guest. Also check the MAC on authenticated write requests.
This depends on HMAC support for QCRYPTO_HASH_ALGO_SHA256 which is
always available via glib - assert this, just to be safe.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <b6f5698c0ca017871d54834f0c7bd4b4b6316bbd.1762261430.git.jan.kiszka@siemens.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
hw/sd/sd.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index aa57c858cbb..9c86c016cc9 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -51,6 +51,7 @@
#include "qemu/module.h"
#include "sdmmc-internal.h"
#include "trace.h"
+#include "crypto/hmac.h"
//#define DEBUG_SD 1
@@ -121,6 +122,7 @@ typedef struct SDProto {
#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];
@@ -1128,6 +1130,67 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
}
}
+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;
+
+ hmac = qcrypto_hmac_new(QCRYPTO_HASH_ALGO_SHA256, sd->rpmb.key,
+ RPMB_KEY_MAC_LEN, &err);
+ if (!hmac) {
+ error_report_err(err);
+ return false;
+ }
+
+ /*
+ * This implies a read request because we only support single-block write
+ * requests so far.
+ */
+ 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));
+
+ memcpy((uint8_t *)buf + RPMB_DATA_LEN, &frame->data[RPMB_DATA_LEN],
+ 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);
+ }
+
+ 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);
+
+ return success;
+}
+
static void emmc_rpmb_blk_read(SDState *sd, uint64_t addr, uint32_t len)
{
uint16_t resp = lduw_be_p(&sd->rpmb.result.req_resp);
@@ -1152,6 +1215,17 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t addr, uint32_t len)
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));
@@ -1163,6 +1237,7 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t addr, uint32_t len)
{
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 */
@@ -1200,6 +1275,11 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t addr, uint32_t len)
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;
@@ -3128,6 +3208,8 @@ 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);
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 5/8] scripts: Add helper script to generate eMMC block device images
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
` (3 preceding siblings ...)
2025-11-04 17:48 ` [PULL 4/8] hw/sd/sdcard: Handle RPMB MAC field Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 6/8] docs: Add eMMC device model description Philippe Mathieu-Daudé
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Jan Kiszka <jan.kiszka@siemens.com>
As an eMMC block device image may consist of more than just the user
data partition, provide a helper script that can compose the image from
boot partitions, an RPMB partition and the user data image. The script
also does the required size validation and/or rounding.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <eecefa8e-44ae-45ff-85d0-3f9b786948e0@siemens.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
scripts/mkemmc.sh | 216 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 216 insertions(+)
create mode 100755 scripts/mkemmc.sh
diff --git a/scripts/mkemmc.sh b/scripts/mkemmc.sh
new file mode 100755
index 00000000000..429388213c6
--- /dev/null
+++ b/scripts/mkemmc.sh
@@ -0,0 +1,216 @@
+#!/bin/sh -e
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Create eMMC block device image from boot, RPMB and user data images
+#
+# Copyright (c) Siemens, 2025
+#
+# Authors:
+# Jan Kiszka <jan.kiszka@siemens.com>
+#
+
+usage() {
+ echo "$0 [OPTIONS] USER_IMG[:SIZE] OUTPUT_IMG"
+ echo ""
+ echo "SIZE must be a power of 2 up to 2G and multiples of 512 byte from there on."
+ echo "If no SIZE is specified, the size of USER_ING will be used (rounded up)."
+ echo ""
+ echo "Supported options:"
+ echo " -b BOOT1_IMG[:SIZE] Add boot partitions. SIZE must be multiples of 128K. If"
+ echo " no SIZE is specified, the size of BOOT1_IMG will be"
+ echo " used (rounded up). BOOT1_IMG will be stored in boot"
+ echo " partition 1, and a boot partition 2 of the same size"
+ echo " will be created as empty (all zeros) unless -B is"
+ echo " specified as well."
+ echo " -B BOOT2_IMG Fill boot partition 2 with BOOT2_IMG. Must be combined"
+ echo " with -b which is also defining the partition size."
+ echo " -r RPMB_IMG[:SIZE] Add RPMB partition. SIZE must be multiples of 128K. If"
+ echo " no SIZE is specified, the size of RPMB_IMG will be"
+ echo " used (rounded up)."
+ echo " -h, --help This help"
+ echo ""
+ echo "All SIZE parameters support the units K, M, G. If SIZE is smaller than the"
+ echo "associated image, it will be truncated in the output image."
+ exit "$1"
+}
+
+process_size() {
+ name=$1
+ image_file=$2
+ alignment=$3
+ image_arg=$4
+ if [ "${image_arg#*:}" = "$image_arg" ]; then
+ if ! size=$(wc -c < "$image_file" 2>/dev/null); then
+ echo "Missing $name image '$image_file'." >&2
+ exit 1
+ fi
+ if [ "$alignment" = 128 ]; then
+ size=$(( (size + 128 * 1024 - 1) & ~(128 * 1024 - 1) ))
+ elif [ $size -gt $((2 * 1024 * 1024 * 1024)) ]; then
+ size=$(( (size + 511) & ~511 ))
+ elif [ $(( size & (size - 1) )) -gt 0 ]; then
+ n=0
+ while [ "$size" -gt 0 ]; do
+ size=$((size >> 1))
+ n=$((n + 1))
+ done
+ size=$((1 << n))
+ fi
+ else
+ value="${image_arg#*:}"
+ if [ "${value%K}" != "$value" ]; then
+ size=${value%K}
+ multiplier=1024
+ elif [ "${value%M}" != "$value" ]; then
+ size=${value%M}
+ multiplier=$((1024 * 1024))
+ elif [ "${value%G}" != "$value" ]; then
+ size=${value%G}
+ multiplier=$((1024 * 1024 * 1024))
+ else
+ size=$value
+ multiplier=1
+ fi
+ # check if "$size" is a valid integer by doing a self-comparison
+ if [ "$size" -eq "$size" ] 2>/dev/null; then
+ size=$((size * multiplier))
+ else
+ echo "Invalid value '$value' specified for $image_file image size." >&2
+ exit 1
+ fi
+ if [ "$alignment" = 128 ]; then
+ if [ $(( size & (128 * 1024 - 1) )) -ne 0 ]; then
+ echo "The $name image size must be multiples of 128K." >&2
+ exit 1
+ fi
+ elif [ $size -gt $((2 * 1024 * 1024 * 1024)) ]; then
+ if [ $(( size & 511)) -ne 0 ]; then
+ echo "The $name image size must be multiples of 512 (if >2G)." >&2
+ exit 1
+ fi
+ elif [ $(( size & (size - 1) )) -gt 0 ]; then
+ echo "The $name image size must be power of 2 (up to 2G)." >&2
+ exit 1
+ fi
+ fi
+ echo $size
+}
+
+check_truncation() {
+ image_file=$1
+ output_size=$2
+ if [ "$image_file" = "/dev/zero" ]; then
+ return
+ fi
+ if ! actual_size=$(wc -c < "$image_file" 2>/dev/null); then
+ echo "Missing image '$image_file'." >&2
+ exit 1
+ fi
+ if [ "$actual_size" -gt "$output_size" ]; then
+ echo "Warning: image '$image_file' will be truncated on output."
+ fi
+}
+
+userimg=
+outimg=
+bootimg1=
+bootimg2=/dev/zero
+bootsz=0
+rpmbimg=
+rpmbsz=0
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -b)
+ shift
+ [ $# -ge 1 ] || usage 1
+ bootimg1=${1%%:*}
+ bootsz=$(process_size boot "$bootimg1" 128 "$1")
+ shift
+ ;;
+ -B)
+ shift
+ [ $# -ge 1 ] || usage 1
+ bootimg2=$1
+ shift
+ ;;
+ -r)
+ shift
+ [ $# -ge 1 ] || usage 1
+ rpmbimg=${1%%:*}
+ rpmbsz=$(process_size RPMB "$rpmbimg" 128 "$1")
+ shift
+ ;;
+ -h|--help)
+ usage 0
+ ;;
+ *)
+ if [ -z "$userimg" ]; then
+ userimg=${1%%:*}
+ usersz=$(process_size user "$userimg" U "$1")
+ elif [ -z "$outimg" ]; then
+ outimg=$1
+ else
+ usage 1
+ fi
+ shift
+ ;;
+ esac
+done
+
+[ -n "$outimg" ] || usage 1
+
+if [ "$bootsz" -gt $((32640 * 1024)) ]; then
+ echo "Boot image size is larger than 32640K." >&2
+ exit 1
+fi
+if [ "$rpmbsz" -gt $((16384 * 1024)) ]; then
+ echo "RPMB image size is larger than 16384K." >&2
+ exit 1
+fi
+
+echo "Creating eMMC image"
+
+truncate -s 0 "$outimg"
+pos=0
+
+if [ "$bootsz" -gt 0 ]; then
+ echo " Boot partition 1 and 2: $((bootsz / 1024))K each"
+ blocks=$(( bootsz / (128 * 1024) ))
+ check_truncation "$bootimg1" "$bootsz"
+ dd if="$bootimg1" of="$outimg" conv=sparse bs=128K count=$blocks \
+ status=none
+ check_truncation "$bootimg2" "$bootsz"
+ dd if="$bootimg2" of="$outimg" conv=sparse bs=128K count=$blocks \
+ seek=$blocks status=none
+ pos=$((2 * bootsz))
+fi
+
+if [ "$rpmbsz" -gt 0 ]; then
+ echo " RPMB partition: $((rpmbsz / 1024))K"
+ blocks=$(( rpmbsz / (128 * 1024) ))
+ check_truncation "$rpmbimg" "$rpmbsz"
+ dd if="$rpmbimg" of="$outimg" conv=sparse bs=128K count=$blocks \
+ seek=$(( pos / (128 * 1024) )) status=none
+ pos=$((pos + rpmbsz))
+fi
+
+if [ "$usersz" -lt 1024 ]; then
+ echo " User data: $usersz bytes"
+elif [ "$usersz" -lt $((1024 * 1024)) ]; then
+ echo " User data: $(( (usersz + 1023) / 1024 ))K ($usersz)"
+elif [ "$usersz" -lt $((1024 * 1024 * 1024)) ]; then
+ echo " User data: $(( (usersz + 1048575) / 1048576))M ($usersz)"
+else
+ echo " User data: $(( (usersz + 1073741823) / 1073741824))G ($usersz)"
+fi
+check_truncation "$userimg" "$usersz"
+dd if="$userimg" of="$outimg" conv=sparse bs=128K seek=$(( pos / (128 * 1024) )) \
+ count=$(( (usersz + 128 * 1024 - 1) / (128 * 1024) )) status=none
+pos=$((pos + usersz))
+truncate -s $pos "$outimg"
+
+echo ""
+echo "Instantiate by appending to the qemu command line:"
+echo " -drive file=$outimg,if=none,format=raw,id=emmc-img"
+echo " -device emmc,boot-partition-size=$bootsz,rpmb-partition-size=$rpmbsz,drive=emmc-img"
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 6/8] docs: Add eMMC device model description
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
` (4 preceding siblings ...)
2025-11-04 17:48 ` [PULL 5/8] scripts: Add helper script to generate eMMC block device images Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 7/8] hw/i386/microvm: Use fdt field from MachineState Philippe Mathieu-Daudé
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <b9c3ff21e7170fef5d0e7d08698a113d2a64e649.1762261430.git.jan.kiszka@siemens.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
docs/system/device-emulation.rst | 1 +
docs/system/devices/emmc.rst | 55 ++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 docs/system/devices/emmc.rst
diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst
index db714ad47aa..971325527a1 100644
--- a/docs/system/device-emulation.rst
+++ b/docs/system/device-emulation.rst
@@ -88,6 +88,7 @@ Emulated Devices
devices/canokey.rst
devices/ccid.rst
devices/cxl.rst
+ devices/emmc.rst
devices/igb.rst
devices/ivshmem-flat.rst
devices/ivshmem.rst
diff --git a/docs/system/devices/emmc.rst b/docs/system/devices/emmc.rst
new file mode 100644
index 00000000000..e62adfd68ed
--- /dev/null
+++ b/docs/system/devices/emmc.rst
@@ -0,0 +1,55 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+==============
+eMMC Emulation
+==============
+
+Besides SD card emulation, QEMU also offers an eMMC model as found on many
+embedded boards. An eMMC, just like an SD card, is connected to the machine
+via an SDHCI controller.
+
+Create eMMC Images
+==================
+
+A recent eMMC consists of 4 partitions: 2 boot partitions, 1 Replay protected
+Memory Block (RPMB), and the user data area. QEMU expects backing images for
+the eMMC to contain those partitions concatenated in exactly that order.
+However, the boot partitions as well as the RPMB might be absent if their sizes
+are configured to zero.
+
+The eMMC specification defines alignment constraints for the partitions. The
+two boot partitions must be of the same size. Furthermore, boot and RPMB
+partitions must be multiples of 128 KB with a maximum of 32640 KB for each
+boot partition and 16384K for the RPMB partition.
+
+The alignment constrain of the user data area depends on its size. Up to 2
+GByte, the size must be a power of 2. From 2 GByte onward, the size has to be
+multiples of 512 byte.
+
+QEMU is enforcing those alignment rules before instantiating the device.
+Therefore, the provided image has to strictly follow them as well. The helper
+script ``scripts/mkemmc.sh`` can be used to create compliant images, with or
+without pre-filled partitions. E.g., to create an eMMC image from a firmware
+image and an OS image with an empty 2 MByte RPMB, use the following command:
+
+.. code-block:: console
+
+ scripts/mkemmc.sh -b firmware.img -r /dev/zero:2M os.img emmc.img
+
+This will take care of rounding up the partition sizes to the next valid value
+and will leave the RPMB and the second boot partition empty (zeroed).
+
+Adding eMMC Devices
+===================
+
+An eMMC is either automatically created by a machine model (e.g. Aspeed boards)
+or can be user-created when using a PCI-attached SDHCI controller. To
+instantiate the eMMC image from the example above in a machine without other
+SDHCI controllers while assuming that the firmware needs a boot partitions of
+1 MB, use the following options:
+
+.. code-block:: console
+
+ -drive file=emmc.img,if=none,format=raw,id=emmc-img
+ -device sdhci-pci
+ -device emmc,drive=emmc-img,boot-partition-size=1048576,rpmb-partition-size=2097152
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 7/8] hw/i386/microvm: Use fdt field from MachineState
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
` (5 preceding siblings ...)
2025-11-04 17:48 ` [PULL 6/8] docs: Add eMMC device model description Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 8/8] hw/audio: Remove dead code from ac97_realize Philippe Mathieu-Daudé
2025-11-05 9:00 ` [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Luigi Leonardi <leonardi@redhat.com>
MachineState already provides an fdt field, remove it from
MicrovmMachineState and use that instead.
This is useful when using the `dumpdtb` option, as QEMU expects the
device tree to be stored in the MachineState struct, otherwise it
will return this error:
qemu-system-x86_64: This machine doesn't have an FDT
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20251030-fix_microvm-v1-1-f89544a04be3@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
include/hw/i386/microvm.h | 2 -
hw/i386/microvm-dt.c | 96 +++++++++++++++++++++------------------
2 files changed, 52 insertions(+), 46 deletions(-)
diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
index b9ac34a3ef1..e73d1e65de8 100644
--- a/include/hw/i386/microvm.h
+++ b/include/hw/i386/microvm.h
@@ -102,8 +102,6 @@ struct MicrovmMachineState {
Notifier powerdown_req;
struct GPEXConfig gpex;
- /* device tree */
- void *fdt;
uint32_t ioapic_phandle[2];
};
diff --git a/hw/i386/microvm-dt.c b/hw/i386/microvm-dt.c
index cb27dfd732e..81eaddafc8b 100644
--- a/hw/i386/microvm-dt.c
+++ b/hw/i386/microvm-dt.c
@@ -48,6 +48,7 @@ static bool debug;
static void dt_add_microvm_irq(MicrovmMachineState *mms,
const char *nodename, uint32_t irq)
{
+ MachineState *ms = MACHINE(mms);
int index = 0;
if (irq >= IO_APIC_SECONDARY_IRQBASE) {
@@ -55,13 +56,14 @@ static void dt_add_microvm_irq(MicrovmMachineState *mms,
index++;
}
- qemu_fdt_setprop_cell(mms->fdt, nodename, "interrupt-parent",
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
mms->ioapic_phandle[index]);
- qemu_fdt_setprop_cells(mms->fdt, nodename, "interrupts", irq, 0);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0);
}
static void dt_add_virtio(MicrovmMachineState *mms, VirtIOMMIOProxy *mmio)
{
+ MachineState *ms = MACHINE(mms);
SysBusDevice *dev = SYS_BUS_DEVICE(mmio);
VirtioBusState *mmio_virtio_bus = &mmio->bus;
BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
@@ -77,10 +79,10 @@ static void dt_add_virtio(MicrovmMachineState *mms, VirtIOMMIOProxy *mmio)
uint32_t irq = mms->virtio_irq_base + index;
nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
- qemu_fdt_add_subnode(mms->fdt, nodename);
- qemu_fdt_setprop_string(mms->fdt, nodename, "compatible", "virtio,mmio");
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "reg", 2, base, 2, size);
- qemu_fdt_setprop(mms->fdt, nodename, "dma-coherent", NULL, 0);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "virtio,mmio");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+ qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
dt_add_microvm_irq(mms, nodename, irq);
g_free(nodename);
}
@@ -88,40 +90,42 @@ static void dt_add_virtio(MicrovmMachineState *mms, VirtIOMMIOProxy *mmio)
static void dt_add_xhci(MicrovmMachineState *mms)
{
const char compat[] = "generic-xhci";
+ MachineState *ms = MACHINE(mms);
uint32_t irq = MICROVM_XHCI_IRQ;
hwaddr base = MICROVM_XHCI_BASE;
hwaddr size = XHCI_LEN_REGS;
char *nodename;
nodename = g_strdup_printf("/usb@%" PRIx64, base);
- qemu_fdt_add_subnode(mms->fdt, nodename);
- qemu_fdt_setprop(mms->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "reg", 2, base, 2, size);
- qemu_fdt_setprop(mms->fdt, nodename, "dma-coherent", NULL, 0);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+ qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
dt_add_microvm_irq(mms, nodename, irq);
g_free(nodename);
}
static void dt_add_pcie(MicrovmMachineState *mms)
{
+ MachineState *ms = MACHINE(mms);
hwaddr base = PCIE_MMIO_BASE;
int nr_pcie_buses;
char *nodename;
nodename = g_strdup_printf("/pcie@%" PRIx64, base);
- qemu_fdt_add_subnode(mms->fdt, nodename);
- qemu_fdt_setprop_string(mms->fdt, nodename,
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename,
"compatible", "pci-host-ecam-generic");
- qemu_fdt_setprop_string(mms->fdt, nodename, "device_type", "pci");
- qemu_fdt_setprop_cell(mms->fdt, nodename, "#address-cells", 3);
- qemu_fdt_setprop_cell(mms->fdt, nodename, "#size-cells", 2);
- qemu_fdt_setprop_cell(mms->fdt, nodename, "linux,pci-domain", 0);
- qemu_fdt_setprop(mms->fdt, nodename, "dma-coherent", NULL, 0);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
+ qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "reg",
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
2, PCIE_ECAM_BASE, 2, PCIE_ECAM_SIZE);
if (mms->gpex.mmio64.size) {
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "ranges",
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
1, FDT_PCI_RANGE_MMIO,
2, mms->gpex.mmio32.base,
@@ -133,7 +137,7 @@ static void dt_add_pcie(MicrovmMachineState *mms)
2, mms->gpex.mmio64.base,
2, mms->gpex.mmio64.size);
} else {
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "ranges",
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
1, FDT_PCI_RANGE_MMIO,
2, mms->gpex.mmio32.base,
@@ -142,7 +146,7 @@ static void dt_add_pcie(MicrovmMachineState *mms)
}
nr_pcie_buses = PCIE_ECAM_SIZE / PCIE_MMCFG_SIZE_MIN;
- qemu_fdt_setprop_cells(mms->fdt, nodename, "bus-range", 0,
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
nr_pcie_buses - 1);
g_free(nodename);
@@ -150,6 +154,7 @@ static void dt_add_pcie(MicrovmMachineState *mms)
static void dt_add_ioapic(MicrovmMachineState *mms, SysBusDevice *dev)
{
+ MachineState *ms = MACHINE(mms);
hwaddr base = dev->mmio[0].addr;
char *nodename;
uint32_t ph;
@@ -168,18 +173,18 @@ static void dt_add_ioapic(MicrovmMachineState *mms, SysBusDevice *dev)
}
nodename = g_strdup_printf("/ioapic%d@%" PRIx64, index + 1, base);
- qemu_fdt_add_subnode(mms->fdt, nodename);
- qemu_fdt_setprop_string(mms->fdt, nodename,
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename,
"compatible", "intel,ce4100-ioapic");
- qemu_fdt_setprop(mms->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(mms->fdt, nodename, "#interrupt-cells", 0x2);
- qemu_fdt_setprop_cell(mms->fdt, nodename, "#address-cells", 0x2);
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "reg",
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 0x2);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
2, base, 2, 0x1000);
- ph = qemu_fdt_alloc_phandle(mms->fdt);
- qemu_fdt_setprop_cell(mms->fdt, nodename, "phandle", ph);
- qemu_fdt_setprop_cell(mms->fdt, nodename, "linux,phandle", ph);
+ ph = qemu_fdt_alloc_phandle(ms->fdt);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", ph);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,phandle", ph);
mms->ioapic_phandle[index] = ph;
g_free(nodename);
@@ -190,17 +195,18 @@ static void dt_add_isa_serial(MicrovmMachineState *mms, ISADevice *dev)
const char compat[] = "ns16550";
uint32_t irq = object_property_get_int(OBJECT(dev), "irq", &error_fatal);
hwaddr base = object_property_get_int(OBJECT(dev), "iobase", &error_fatal);
+ MachineState *ms = MACHINE(mms);
hwaddr size = 8;
char *nodename;
nodename = g_strdup_printf("/serial@%" PRIx64, base);
- qemu_fdt_add_subnode(mms->fdt, nodename);
- qemu_fdt_setprop(mms->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "reg", 2, base, 2, size);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
dt_add_microvm_irq(mms, nodename, irq);
if (base == 0x3f8 /* com1 */) {
- qemu_fdt_setprop_string(mms->fdt, "/chosen", "stdout-path", nodename);
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
}
g_free(nodename);
@@ -211,13 +217,14 @@ static void dt_add_isa_rtc(MicrovmMachineState *mms, ISADevice *dev)
const char compat[] = "motorola,mc146818";
uint32_t irq = object_property_get_uint(OBJECT(dev), "irq", &error_fatal);
hwaddr base = object_property_get_uint(OBJECT(dev), "iobase", &error_fatal);
+ MachineState *ms = MACHINE(mms);
hwaddr size = 8;
char *nodename;
nodename = g_strdup_printf("/rtc@%" PRIx64, base);
- qemu_fdt_add_subnode(mms->fdt, nodename);
- qemu_fdt_setprop(mms->fdt, nodename, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_sized_cells(mms->fdt, nodename, "reg", 2, base, 2, size);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
dt_add_microvm_irq(mms, nodename, irq);
g_free(nodename);
}
@@ -317,27 +324,28 @@ static void dt_setup_sys_bus(MicrovmMachineState *mms)
void dt_setup_microvm(MicrovmMachineState *mms)
{
X86MachineState *x86ms = X86_MACHINE(mms);
+ MachineState *ms = MACHINE(mms);
int size = 0;
- mms->fdt = create_device_tree(&size);
+ ms->fdt = create_device_tree(&size);
/* root node */
- qemu_fdt_setprop_string(mms->fdt, "/", "compatible", "linux,microvm");
- qemu_fdt_setprop_cell(mms->fdt, "/", "#address-cells", 0x2);
- qemu_fdt_setprop_cell(mms->fdt, "/", "#size-cells", 0x2);
+ qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "linux,microvm");
+ qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
+ qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
- qemu_fdt_add_subnode(mms->fdt, "/chosen");
+ qemu_fdt_add_subnode(ms->fdt, "/chosen");
dt_setup_sys_bus(mms);
/* add to fw_cfg */
if (debug) {
fprintf(stderr, "%s: add etc/fdt to fw_cfg\n", __func__);
}
- fw_cfg_add_file(x86ms->fw_cfg, "etc/fdt", mms->fdt, size);
+ fw_cfg_add_file(x86ms->fw_cfg, "etc/fdt", ms->fdt, size);
if (debug) {
fprintf(stderr, "%s: writing microvm.fdt\n", __func__);
- if (!g_file_set_contents("microvm.fdt", mms->fdt, size, NULL)) {
+ if (!g_file_set_contents("microvm.fdt", ms->fdt, size, NULL)) {
fprintf(stderr, "%s: writing microvm.fdt failed\n", __func__);
return;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PULL 8/8] hw/audio: Remove dead code from ac97_realize
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
` (6 preceding siblings ...)
2025-11-04 17:48 ` [PULL 7/8] hw/i386/microvm: Use fdt field from MachineState Philippe Mathieu-Daudé
@ 2025-11-04 17:48 ` Philippe Mathieu-Daudé
2025-11-05 9:00 ` [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
8 siblings, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-04 17:48 UTC (permalink / raw)
To: qemu-devel
From: Osama Abdelkader <osama.abdelkader@gmail.com>
Remove unnecessary PCI configuration register initialization that was
marked with TODO comments indicating it's redundant:
- PCI_COMMAND register is already 0x00 by default, no need to override
- PCI_BASE_ADDRESS_0 registers are automatically set by pci_register_bar()
This aligns the code with the pattern used by other PCI audio devices
in QEMU (via-ac97, intel-hda, es1370) and removes 15 lines of dead code.
Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20251102231903.65409-1-osama.abdelkader@gmail.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
hw/audio/ac97.c | 19 -------------------
1 file changed, 19 deletions(-)
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index be7a39377f9..60daa62ea33 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -1279,30 +1279,11 @@ static void ac97_realize(PCIDevice *dev, Error **errp)
return;
}
- /* TODO: no need to override */
- c[PCI_COMMAND] = 0x00; /* pcicmd pci command rw, ro */
- c[PCI_COMMAND + 1] = 0x00;
-
- /* TODO: */
c[PCI_STATUS] = PCI_STATUS_FAST_BACK; /* pcists pci status rwc, ro */
c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
c[PCI_CLASS_PROG] = 0x00; /* pi programming interface ro */
- /* TODO set when bar is registered. no need to override. */
- /* nabmar native audio mixer base address rw */
- c[PCI_BASE_ADDRESS_0] = PCI_BASE_ADDRESS_SPACE_IO;
- c[PCI_BASE_ADDRESS_0 + 1] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 2] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 3] = 0x00;
-
- /* TODO set when bar is registered. no need to override. */
- /* nabmbar native audio bus mastering base address rw */
- c[PCI_BASE_ADDRESS_0 + 4] = PCI_BASE_ADDRESS_SPACE_IO;
- c[PCI_BASE_ADDRESS_0 + 5] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 6] = 0x00;
- c[PCI_BASE_ADDRESS_0 + 7] = 0x00;
-
c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */
c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */
--
2.51.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PULL 0/8] Misc HW patches for 2025-11-04
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
` (7 preceding siblings ...)
2025-11-04 17:48 ` [PULL 8/8] hw/audio: Remove dead code from ac97_realize Philippe Mathieu-Daudé
@ 2025-11-05 9:00 ` Philippe Mathieu-Daudé
2025-11-05 13:47 ` Richard Henderson
8 siblings, 1 reply; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-05 9:00 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
Hi,
On 4/11/25 18:48, Philippe Mathieu-Daudé wrote:
> The following changes since commit e9c692eabbbb7f395347605a6ef33a32d398ea25:
>
> Merge tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu into staging (2025-11-04 15:17:31 +0100)
>
> are available in the Git repository at:
>
> https://github.com/philmd/qemu.git tags/hw-misc-20251104
>
> for you to fetch changes up to f79fec0275ee7a5151ced9b893c4af676c7f5db6:
I missed Cédric Le Goater provided his Tested-by tag via IRC, so
amended to the relevant commits and regenerated the tag (no other
change). New tag hash is 1eb18789f8863e7ee89c1dc06b2de806442b4927.
Note I also ignore this checkpatch error:
ERROR: line over 90 characters
#242: FILE: scripts/mkemmc.sh:216:
+echo " -device
emmc,boot-partition-size=$bootsz,rpmb-partition-size=$rpmbsz,drive=emmc-img"
> ----------------------------------------------------------------
> Misc HW patches
>
> - Add RPMB emulation to eMMC model :)
> - Use generic MachineState::fdt field in microvm machine
> - Remove dead code in ac97_realize()
> ----------------------------------------------------------------
Regards,
Phil.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PULL 0/8] Misc HW patches for 2025-11-04
2025-11-05 9:00 ` [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
@ 2025-11-05 13:47 ` Richard Henderson
0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2025-11-05 13:47 UTC (permalink / raw)
To: Philippe Mathieu-Daudé; +Cc: qemu-devel
On 11/5/25 10:00, Philippe Mathieu-Daudé wrote:
> Hi,
>
> On 4/11/25 18:48, Philippe Mathieu-Daudé wrote:
>> The following changes since commit e9c692eabbbb7f395347605a6ef33a32d398ea25:
>>
>> Merge tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu into staging
>> (2025-11-04 15:17:31 +0100)
>>
>> are available in the Git repository at:
>>
>> https://github.com/philmd/qemu.git tags/hw-misc-20251104
>>
>> for you to fetch changes up to f79fec0275ee7a5151ced9b893c4af676c7f5db6:
>
> I missed Cédric Le Goater provided his Tested-by tag via IRC, so
> amended to the relevant commits and regenerated the tag (no other
> change). New tag hash is 1eb18789f8863e7ee89c1dc06b2de806442b4927.
>
> Note I also ignore this checkpatch error:
>
> ERROR: line over 90 characters
> #242: FILE: scripts/mkemmc.sh:216:
> +echo " -device emmc,boot-partition-size=$bootsz,rpmb-partition-size=$rpmbsz,drive=emmc-img"
>
>> ----------------------------------------------------------------
>> Misc HW patches
>>
>> - Add RPMB emulation to eMMC model :)
>> - Use generic MachineState::fdt field in microvm machine
>> - Remove dead code in ac97_realize()
>> ----------------------------------------------------------------
> Regards,
>
> Phil.
Applied, thanks. Please update https://wiki.qemu.org/ChangeLog/10.2 as appropriate.
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-11-05 13:47 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-04 17:48 [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 1/8] hw/sd/sdcard: Fix size check for backing block image Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 2/8] hw/sd/sdcard: Allow user creation of eMMCs Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 3/8] hw/sd/sdcard: Add basic support for RPMB partition Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 4/8] hw/sd/sdcard: Handle RPMB MAC field Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 5/8] scripts: Add helper script to generate eMMC block device images Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 6/8] docs: Add eMMC device model description Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 7/8] hw/i386/microvm: Use fdt field from MachineState Philippe Mathieu-Daudé
2025-11-04 17:48 ` [PULL 8/8] hw/audio: Remove dead code from ac97_realize Philippe Mathieu-Daudé
2025-11-05 9:00 ` [PULL 0/8] Misc HW patches for 2025-11-04 Philippe Mathieu-Daudé
2025-11-05 13:47 ` Richard Henderson
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).