From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
This patch extends the existing support we have for NVMe with only DoE
to also add support to SPDM over the NVMe Security Send/Recv commands.
With the new definition of the `spdm-trans` argument, users can specify
`spdm_trans=nvme` or `spdm_trans=doe`. This allows us to select the SPDM
transport respectively. SPDM over the NVMe Security Send/Recv commands
are defined in the DMTF DSP0286.
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
docs/specs/spdm.rst | 10 ++++++--
hw/nvme/ctrl.c | 46 ++++++++++++++++++++++++++++---------
include/hw/pci/pci_device.h | 2 ++
3 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
index f7de080ff0..dd6cfbbd68 100644
--- a/docs/specs/spdm.rst
+++ b/docs/specs/spdm.rst
@@ -98,7 +98,7 @@ Then you can add this to your QEMU command line:
.. code-block:: shell
-drive file=blknvme,if=none,id=mynvme,format=raw \
- -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
+ -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe
At which point QEMU will try to connect to the SPDM server.
@@ -113,7 +113,13 @@ of the default. So the entire QEMU command might look like this
-append "root=/dev/vda console=ttyS0" \
-net none -nographic \
-drive file=blknvme,if=none,id=mynvme,format=raw \
- -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
+ -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe
+
+The `spdm_trans` argument defines the underlying transport type that is emulated
+by QEMU. For an PCIe NVMe controller, both "doe" and "nvme" are supported. Where,
+"doe" does SPDM transport over the PCIe extended capability Data Object Exchange
+(DOE), and "nvme" uses the NVMe Admin Security Send/Receive commands to
+implement the SPDM transport.
.. _DMTF:
https://www.dmtf.org/standards/SPDM
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index ad52e8f569..8a610f57f2 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -8947,19 +8947,31 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
pcie_cap_deverr_init(pci_dev);
- /* DOE Initialisation */
+ /* SPDM Initialisation */
if (pci_dev->spdm_port) {
- uint16_t doe_offset = n->params.sriov_max_vfs ?
- PCI_CONFIG_SPACE_SIZE + PCI_ARI_SIZEOF
- : PCI_CONFIG_SPACE_SIZE;
+ switch (pci_dev->spdm_trans) {
+ case SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE:
+ uint16_t doe_offset = n->params.sriov_max_vfs ?
+ PCI_CONFIG_SPACE_SIZE + PCI_ARI_SIZEOF
+ : PCI_CONFIG_SPACE_SIZE;
- pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
- doe_spdm_prot, true, 0);
+ pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
+ doe_spdm_prot, true, 0);
- pci_dev->doe_spdm.spdm_socket = spdm_socket_connect(pci_dev->spdm_port,
- errp);
+ pci_dev->doe_spdm.spdm_socket =
+ spdm_socket_connect(pci_dev->spdm_port, errp);
- if (pci_dev->doe_spdm.spdm_socket < 0) {
+ if (pci_dev->doe_spdm.spdm_socket < 0) {
+ return false;
+ }
+ break;
+ case SPDM_SOCKET_TRANSPORT_TYPE_NVME:
+ n->spdm_socket = spdm_socket_connect(pci_dev->spdm_port, errp);
+ if (n->spdm_socket < 0) {
+ return false;
+ }
+ break;
+ default:
return false;
}
}
@@ -9250,11 +9262,17 @@ static void nvme_exit(PCIDevice *pci_dev)
g_free(n->cmb.buf);
}
+ /* Only one of the `spdm_socket` below would have been setup */
if (pci_dev->doe_spdm.spdm_socket > 0) {
spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE);
}
+ if (n->spdm_socket >= 0) {
+ spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
+ SPDM_SOCKET_TRANSPORT_TYPE_NVME);
+ }
+
if (n->pmr.dev) {
host_memory_backend_set_mapped(n->pmr.dev, false);
}
@@ -9307,6 +9325,8 @@ static const Property nvme_props[] = {
false),
DEFINE_PROP_UINT16("mqes", NvmeCtrl, params.mqes, 0x7ff),
DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
+ DEFINE_PROP_SPDM_TRANS("spdm_trans", PCIDevice, spdm_trans,
+ SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE),
DEFINE_PROP_BOOL("ctratt.mem", NvmeCtrl, params.ctratt.mem, false),
DEFINE_PROP_BOOL("atomic.dn", NvmeCtrl, params.atomic_dn, 0),
DEFINE_PROP_UINT16("atomic.awun", NvmeCtrl, params.atomic_awun, 0),
@@ -9382,7 +9402,9 @@ static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
{
uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
- if (pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE)) {
+ /* DOE is only initialised if SPDM over DOE is used */
+ if (pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE) &&
+ dev->spdm_trans == SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE) {
pcie_doe_write_config(&dev->doe_spdm, address, val, len);
}
pci_default_write_config(dev, address, val, len);
@@ -9393,7 +9415,9 @@ static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
static uint32_t nvme_pci_read_config(PCIDevice *dev, uint32_t address, int len)
{
uint32_t val;
- if (dev->spdm_port && pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE)) {
+
+ if (dev->spdm_port && pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE) &&
+ (dev->spdm_trans == SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE)) {
if (pcie_doe_read_config(&dev->doe_spdm, address, len, &val)) {
return val;
}
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index eee0338568..88ccea5011 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -4,6 +4,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_doe.h"
+#include "system/spdm-socket.h"
#define TYPE_PCI_DEVICE "pci-device"
typedef struct PCIDeviceClass PCIDeviceClass;
@@ -166,6 +167,7 @@ struct PCIDevice {
/* SPDM */
uint16_t spdm_port;
+ SpdmTransportType spdm_trans;
/* DOE */
DOECap doe_spdm;
--
2.51.0
On Sep 11 16:00, Wilfred Mallawa wrote:
> From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
>
> This patch extends the existing support we have for NVMe with only DoE
> to also add support to SPDM over the NVMe Security Send/Recv commands.
>
> With the new definition of the `spdm-trans` argument, users can specify
> `spdm_trans=nvme` or `spdm_trans=doe`. This allows us to select the SPDM
> transport respectively. SPDM over the NVMe Security Send/Recv commands
> are defined in the DMTF DSP0286.
>
> Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
LGTM. One small nit below that I can fix when merging if another
revision is not rolled.
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
> ---
> docs/specs/spdm.rst | 10 ++++++--
> hw/nvme/ctrl.c | 46 ++++++++++++++++++++++++++++---------
> include/hw/pci/pci_device.h | 2 ++
> 3 files changed, 45 insertions(+), 13 deletions(-)
>
> diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
> index f7de080ff0..dd6cfbbd68 100644
> --- a/docs/specs/spdm.rst
> +++ b/docs/specs/spdm.rst
> @@ -98,7 +98,7 @@ Then you can add this to your QEMU command line:
> .. code-block:: shell
>
> -drive file=blknvme,if=none,id=mynvme,format=raw \
> - -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
> + -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe
>
> At which point QEMU will try to connect to the SPDM server.
>
> @@ -113,7 +113,13 @@ of the default. So the entire QEMU command might look like this
> -append "root=/dev/vda console=ttyS0" \
> -net none -nographic \
> -drive file=blknvme,if=none,id=mynvme,format=raw \
> - -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
> + -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe
> +
> +The `spdm_trans` argument defines the underlying transport type that is emulated
> +by QEMU. For an PCIe NVMe controller, both "doe" and "nvme" are supported. Where,
> +"doe" does SPDM transport over the PCIe extended capability Data Object Exchange
> +(DOE), and "nvme" uses the NVMe Admin Security Send/Receive commands to
> +implement the SPDM transport.
>
> .. _DMTF:
> https://www.dmtf.org/standards/SPDM
> diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
> index ad52e8f569..8a610f57f2 100644
> --- a/hw/nvme/ctrl.c
> +++ b/hw/nvme/ctrl.c
> @@ -8947,19 +8947,31 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
>
> pcie_cap_deverr_init(pci_dev);
>
> - /* DOE Initialisation */
> + /* SPDM Initialisation */
> if (pci_dev->spdm_port) {
> - uint16_t doe_offset = n->params.sriov_max_vfs ?
> - PCI_CONFIG_SPACE_SIZE + PCI_ARI_SIZEOF
> - : PCI_CONFIG_SPACE_SIZE;
> + switch (pci_dev->spdm_trans) {
> + case SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE:
> + uint16_t doe_offset = n->params.sriov_max_vfs ?
> + PCI_CONFIG_SPACE_SIZE + PCI_ARI_SIZEOF
> + : PCI_CONFIG_SPACE_SIZE;
>
> - pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
> - doe_spdm_prot, true, 0);
> + pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
> + doe_spdm_prot, true, 0);
>
> - pci_dev->doe_spdm.spdm_socket = spdm_socket_connect(pci_dev->spdm_port,
> - errp);
> + pci_dev->doe_spdm.spdm_socket =
> + spdm_socket_connect(pci_dev->spdm_port, errp);
>
> - if (pci_dev->doe_spdm.spdm_socket < 0) {
> + if (pci_dev->doe_spdm.spdm_socket < 0) {
> + return false;
> + }
> + break;
> + case SPDM_SOCKET_TRANSPORT_TYPE_NVME:
> + n->spdm_socket = spdm_socket_connect(pci_dev->spdm_port, errp);
> + if (n->spdm_socket < 0) {
> + return false;
> + }
> + break;
> + default:
> return false;
> }
> }
> @@ -9250,11 +9262,17 @@ static void nvme_exit(PCIDevice *pci_dev)
> g_free(n->cmb.buf);
> }
>
> + /* Only one of the `spdm_socket` below would have been setup */
> if (pci_dev->doe_spdm.spdm_socket > 0) {
> spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
> SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE);
> }
>
> + if (n->spdm_socket >= 0) {
> + spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
> + SPDM_SOCKET_TRANSPORT_TYPE_NVME);
> + }
> +
Might as well assert the above condition or at least use an else if
here.
On Thu, 2025-09-11 at 08:30 +0200, Klaus Jensen wrote: > On Sep 11 16:00, Wilfred Mallawa wrote: > > From: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > > > This patch extends the existing support we have for NVMe with only > > DoE > > to also add support to SPDM over the NVMe Security Send/Recv > > commands. > > > > With the new definition of the `spdm-trans` argument, users can > > specify > > `spdm_trans=nvme` or `spdm_trans=doe`. This allows us to select the > > SPDM > > transport respectively. SPDM over the NVMe Security Send/Recv > > commands > > are defined in the DMTF DSP0286. > > > > Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> > > LGTM. One small nit below that I can fix when merging if another > revision is not rolled. Hey Klaus, I've sent a V7 with this addressed. Thanks for the feedback! Regards, Wilfred [...]
© 2016 - 2026 Red Hat, Inc.