* [PATCH v7 0/3] Initial support for SPDM Responders
@ 2024-06-14 1:28 Alistair Francis
2024-06-14 1:28 ` [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0 Alistair Francis
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Alistair Francis @ 2024-06-14 1:28 UTC (permalink / raw)
To: wilfred.mallawa, marcel.apfelbaum, lukas, qemu-devel, mst,
Jonathan.Cameron, kbusch, hchkuo, cbrowy, its, jiewen.yao
Cc: Alistair Francis, qemu-block, Paolo Bonzini, alistair23,
Jesper Devantier
The Security Protocol and Data Model (SPDM) Specification defines
messages, data objects, and sequences for performing message exchanges
over a variety of transport and physical media.
- https://www.dmtf.org/sites/default/files/standards/documents/DSP0274_1.3.0.pdf
SPDM currently supports PCIe DOE and MCTP transports, but it can be
extended to support others in the future. This series adds
support to QEMU to connect to an external SPDM instance.
SPDM support can be added to any QEMU device by exposing a
TCP socket to a SPDM server. The server can then implement the SPDM
decoding/encoding support, generally using libspdm [1].
This is similar to how the current TPM implementation works and means
that the heavy lifting of setting up certificate chains, capabilities,
measurements and complex crypto can be done outside QEMU by a well
supported and tested library.
This series implements socket support and exposes SPDM for a NVMe device.
1: https://github.com/DMTF/libspdm
v7:
- Fixup checkpatch failures
- Fixup test failures
- Rename port name to be clearer
v6:
- Add documentation to public functions
- Rename socket variable to spdm_socket
- Don't override errp
- Correctly return false from nvme_init_pci() on error
v5:
- Update MAINTAINERS
v4:
- Rebase
v3:
- Spelling fixes
- Support for SPDM-Utils
v2:
- Add cover letter
- A few code fixes based on comments
- Document SPDM-Utils
- A few tweaks and clarifications to the documentation
Alistair Francis (1):
hw/pci: Add all Data Object Types defined in PCIe r6.0
Huai-Cheng Kuo (1):
backends: Initial support for SPDM socket support
Wilfred Mallawa (1):
hw/nvme: Add SPDM over DOE support
MAINTAINERS | 6 +
docs/specs/index.rst | 1 +
docs/specs/spdm.rst | 134 ++++++++++++++++++++++
include/hw/pci/pci_device.h | 7 ++
include/hw/pci/pcie_doe.h | 5 +
include/sysemu/spdm-socket.h | 74 ++++++++++++
backends/spdm-socket.c | 216 +++++++++++++++++++++++++++++++++++
hw/nvme/ctrl.c | 60 ++++++++++
backends/Kconfig | 4 +
backends/meson.build | 2 +
10 files changed, 509 insertions(+)
create mode 100644 docs/specs/spdm.rst
create mode 100644 include/sysemu/spdm-socket.h
create mode 100644 backends/spdm-socket.c
--
2.45.2
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0
2024-06-14 1:28 [PATCH v7 0/3] Initial support for SPDM Responders Alistair Francis
@ 2024-06-14 1:28 ` Alistair Francis
2024-06-14 1:52 ` Wilfred Mallawa
2024-06-14 1:28 ` [PATCH v7 2/3] backends: Initial support for SPDM socket support Alistair Francis
2024-06-14 1:28 ` [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support Alistair Francis
2 siblings, 1 reply; 7+ messages in thread
From: Alistair Francis @ 2024-06-14 1:28 UTC (permalink / raw)
To: wilfred.mallawa, marcel.apfelbaum, lukas, qemu-devel, mst,
Jonathan.Cameron, kbusch, hchkuo, cbrowy, its, jiewen.yao
Cc: Alistair Francis, qemu-block, Paolo Bonzini, alistair23,
Jesper Devantier, Jonathan Cameron
Add all of the defined protocols/features from the PCIe-SIG r6.0
"Table 6-32 PCI-SIG defined Data Object Types (Vendor ID = 0001h)"
table.
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
include/hw/pci/pcie_doe.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
index 87dc17dcef..15d94661f9 100644
--- a/include/hw/pci/pcie_doe.h
+++ b/include/hw/pci/pcie_doe.h
@@ -46,6 +46,8 @@ REG32(PCI_DOE_CAP_STATUS, 0)
/* PCI-SIG defined Data Object Types - r6.0 Table 6-32 */
#define PCI_SIG_DOE_DISCOVERY 0x00
+#define PCI_SIG_DOE_CMA 0x01
+#define PCI_SIG_DOE_SECURED_CMA 0x02
#define PCI_DOE_DW_SIZE_MAX (1 << 18)
#define PCI_DOE_PROTOCOL_NUM_MAX 256
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v7 2/3] backends: Initial support for SPDM socket support
2024-06-14 1:28 [PATCH v7 0/3] Initial support for SPDM Responders Alistair Francis
2024-06-14 1:28 ` [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0 Alistair Francis
@ 2024-06-14 1:28 ` Alistair Francis
2024-06-14 1:28 ` [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support Alistair Francis
2 siblings, 0 replies; 7+ messages in thread
From: Alistair Francis @ 2024-06-14 1:28 UTC (permalink / raw)
To: wilfred.mallawa, marcel.apfelbaum, lukas, qemu-devel, mst,
Jonathan.Cameron, kbusch, hchkuo, cbrowy, its, jiewen.yao
Cc: Alistair Francis, qemu-block, Paolo Bonzini, alistair23,
Jesper Devantier, Jonathan Cameron, Jonathan Cameron
From: Huai-Cheng Kuo <hchkuo@avery-design.com.tw>
SPDM enables authentication, attestation and key exchange to assist in
providing infrastructure security enablement. It's a standard published
by the DMTF [1].
SPDM supports multiple transports, including PCIe DOE and MCTP.
This patch adds support to QEMU to connect to an external SPDM
instance.
SPDM support can be added to any QEMU device by exposing a
TCP socket to a SPDM server. The server can then implement the SPDM
decoding/encoding support, generally using libspdm [2].
This is similar to how the current TPM implementation works and means
that the heavy lifting of setting up certificate chains, capabilities,
measurements and complex crypto can be done outside QEMU by a well
supported and tested library.
1: https://www.dmtf.org/standards/SPDM
2: https://github.com/DMTF/libspdm
Signed-off-by: Huai-Cheng Kuo <hchkuo@avery-design.com.tw>
Signed-off-by: Chris Browy <cbrowy@avery-design.com>
Co-developed-by: Jonathan Cameron <Jonathan.cameron@huawei.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
[ Changes by WM
- Bug fixes from testing
]
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
[ Changes by AF:
- Convert to be more QEMU-ified
- Move to backends as it isn't PCIe specific
]
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
MAINTAINERS | 6 +
include/sysemu/spdm-socket.h | 74 ++++++++++++
backends/spdm-socket.c | 216 +++++++++++++++++++++++++++++++++++
backends/Kconfig | 4 +
backends/meson.build | 2 +
5 files changed, 302 insertions(+)
create mode 100644 include/sysemu/spdm-socket.h
create mode 100644 backends/spdm-socket.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 951556224a..aeac108586 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3394,6 +3394,12 @@ F: tests/qtest/*tpm*
F: docs/specs/tpm.rst
T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
+SPDM
+M: Alistair Francis <alistair.francis@wdc.com>
+S: Maintained
+F: backends/spdm-socket.c
+F: include/sysemu/spdm-socket.h
+
Checkpatch
S: Odd Fixes
F: scripts/checkpatch.pl
diff --git a/include/sysemu/spdm-socket.h b/include/sysemu/spdm-socket.h
new file mode 100644
index 0000000000..5d8bd9aa4e
--- /dev/null
+++ b/include/sysemu/spdm-socket.h
@@ -0,0 +1,74 @@
+/*
+ * QEMU SPDM socket support
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SPDM_REQUESTER_H
+#define SPDM_REQUESTER_H
+
+/**
+ * spdm_socket_connect: connect to an external SPDM socket
+ * @port: port to connect to
+ * @errp: error object handle
+ *
+ * This will connect to an external SPDM socket server. On error
+ * it will return -1 and errp will be set. On success this function
+ * will return the socket number.
+ */
+int spdm_socket_connect(uint16_t port, Error **errp);
+
+/**
+ * spdm_socket_rsp: send and receive a message to a SPDM server
+ * @socket: socket returned from spdm_socket_connect()
+ * @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
+ * @req: request buffer
+ * @req_len: request buffer length
+ * @rsp: response buffer
+ * @rsp_len: response buffer length
+ *
+ * Send platform data to a SPDM server on socket and then receive
+ * a response.
+ */
+uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
+ void *req, uint32_t req_len,
+ void *rsp, uint32_t rsp_len);
+
+/**
+ * spdm_socket_close: send a shutdown command to the server
+ * @socket: socket returned from spdm_socket_connect()
+ * @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
+ *
+ * This will issue a shutdown command to the server.
+ */
+void spdm_socket_close(const int socket, uint32_t transport_type);
+
+#define SPDM_SOCKET_COMMAND_NORMAL 0x0001
+#define SPDM_SOCKET_COMMAND_OOB_ENCAP_KEY_UPDATE 0x8001
+#define SPDM_SOCKET_COMMAND_CONTINUE 0xFFFD
+#define SPDM_SOCKET_COMMAND_SHUTDOWN 0xFFFE
+#define SPDM_SOCKET_COMMAND_UNKOWN 0xFFFF
+#define SPDM_SOCKET_COMMAND_TEST 0xDEAD
+
+#define SPDM_SOCKET_TRANSPORT_TYPE_MCTP 0x01
+#define SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE 0x02
+
+#define SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE 0x1200
+
+#endif
diff --git a/backends/spdm-socket.c b/backends/spdm-socket.c
new file mode 100644
index 0000000000..d0663d696c
--- /dev/null
+++ b/backends/spdm-socket.c
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * QEMU SPDM socket support
+ *
+ * This is based on:
+ * https://github.com/DMTF/spdm-emu/blob/07c0a838bcc1c6207c656ac75885c0603e344b6f/spdm_emu/spdm_emu_common/command.c
+ * but has been re-written to match QEMU style
+ *
+ * Copyright (c) 2021, DMTF. All rights reserved.
+ * Copyright (c) 2023. Western Digital Corporation or its affiliates.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/spdm-socket.h"
+#include "qapi/error.h"
+
+static bool read_bytes(const int socket, uint8_t *buffer,
+ size_t number_of_bytes)
+{
+ ssize_t number_received = 0;
+ ssize_t result;
+
+ while (number_received < number_of_bytes) {
+ result = recv(socket, buffer + number_received,
+ number_of_bytes - number_received, 0);
+ if (result <= 0) {
+ return false;
+ }
+ number_received += result;
+ }
+ return true;
+}
+
+static bool read_data32(const int socket, uint32_t *data)
+{
+ bool result;
+
+ result = read_bytes(socket, (uint8_t *)data, sizeof(uint32_t));
+ if (!result) {
+ return result;
+ }
+ *data = ntohl(*data);
+ return true;
+}
+
+static bool read_multiple_bytes(const int socket, uint8_t *buffer,
+ uint32_t *bytes_received,
+ uint32_t max_buffer_length)
+{
+ uint32_t length;
+ bool result;
+
+ result = read_data32(socket, &length);
+ if (!result) {
+ return result;
+ }
+
+ if (length > max_buffer_length) {
+ return false;
+ }
+
+ if (bytes_received) {
+ *bytes_received = length;
+ }
+
+ if (length == 0) {
+ return true;
+ }
+
+ return read_bytes(socket, buffer, length);
+}
+
+static bool receive_platform_data(const int socket,
+ uint32_t transport_type,
+ uint32_t *command,
+ uint8_t *receive_buffer,
+ uint32_t *bytes_to_receive)
+{
+ bool result;
+ uint32_t response;
+ uint32_t bytes_received;
+
+ result = read_data32(socket, &response);
+ if (!result) {
+ return result;
+ }
+ *command = response;
+
+ result = read_data32(socket, &transport_type);
+ if (!result) {
+ return result;
+ }
+
+ bytes_received = 0;
+ result = read_multiple_bytes(socket, receive_buffer, &bytes_received,
+ *bytes_to_receive);
+ if (!result) {
+ return result;
+ }
+ *bytes_to_receive = bytes_received;
+
+ return result;
+}
+
+static bool write_bytes(const int socket, const uint8_t *buffer,
+ uint32_t number_of_bytes)
+{
+ ssize_t number_sent = 0;
+ ssize_t result;
+
+ while (number_sent < number_of_bytes) {
+ result = send(socket, buffer + number_sent,
+ number_of_bytes - number_sent, 0);
+ if (result == -1) {
+ return false;
+ }
+ number_sent += result;
+ }
+ return true;
+}
+
+static bool write_data32(const int socket, uint32_t data)
+{
+ data = htonl(data);
+ return write_bytes(socket, (uint8_t *)&data, sizeof(uint32_t));
+}
+
+static bool write_multiple_bytes(const int socket, const uint8_t *buffer,
+ uint32_t bytes_to_send)
+{
+ bool result;
+
+ result = write_data32(socket, bytes_to_send);
+ if (!result) {
+ return result;
+ }
+
+ return write_bytes(socket, buffer, bytes_to_send);
+}
+
+static bool send_platform_data(const int socket,
+ uint32_t transport_type, uint32_t command,
+ const uint8_t *send_buffer, size_t bytes_to_send)
+{
+ bool result;
+
+ result = write_data32(socket, command);
+ if (!result) {
+ return result;
+ }
+
+ result = write_data32(socket, transport_type);
+ if (!result) {
+ return result;
+ }
+
+ return write_multiple_bytes(socket, send_buffer, bytes_to_send);
+}
+
+int spdm_socket_connect(uint16_t port, Error **errp)
+{
+ int client_socket;
+ struct sockaddr_in server_addr;
+
+ client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (client_socket < 0) {
+ error_setg(errp, "cannot create socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset((char *)&server_addr, 0, sizeof(server_addr));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ server_addr.sin_port = htons(port);
+
+
+ if (connect(client_socket, (struct sockaddr *)&server_addr,
+ sizeof(server_addr)) < 0) {
+ error_setg(errp, "cannot connect: %s", strerror(errno));
+ close(client_socket);
+ return -1;
+ }
+
+ return client_socket;
+}
+
+uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
+ void *req, uint32_t req_len,
+ void *rsp, uint32_t rsp_len)
+{
+ uint32_t command;
+ bool result;
+
+ result = send_platform_data(socket, transport_type,
+ SPDM_SOCKET_COMMAND_NORMAL,
+ req, req_len);
+ if (!result) {
+ return 0;
+ }
+
+ result = receive_platform_data(socket, transport_type, &command,
+ (uint8_t *)rsp, &rsp_len);
+ if (!result) {
+ return 0;
+ }
+
+ assert(command != 0);
+
+ return rsp_len;
+}
+
+void spdm_socket_close(const int socket, uint32_t transport_type)
+{
+ send_platform_data(socket, transport_type,
+ SPDM_SOCKET_COMMAND_SHUTDOWN, NULL, 0);
+}
diff --git a/backends/Kconfig b/backends/Kconfig
index 2cb23f62fa..d3dbe19868 100644
--- a/backends/Kconfig
+++ b/backends/Kconfig
@@ -3,3 +3,7 @@ source tpm/Kconfig
config IOMMUFD
bool
depends on VFIO
+
+config SPDM_SOCKET
+ bool
+ default y
diff --git a/backends/meson.build b/backends/meson.build
index 8b2b111497..e5d4db7971 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -31,4 +31,6 @@ endif
system_ss.add(when: gio, if_true: files('dbus-vmstate.c'))
system_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
+system_ss.add(when: 'CONFIG_SPDM_SOCKET', if_true: files('spdm-socket.c'))
+
subdir('tpm')
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support
2024-06-14 1:28 [PATCH v7 0/3] Initial support for SPDM Responders Alistair Francis
2024-06-14 1:28 ` [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0 Alistair Francis
2024-06-14 1:28 ` [PATCH v7 2/3] backends: Initial support for SPDM socket support Alistair Francis
@ 2024-06-14 1:28 ` Alistair Francis
2024-06-14 1:56 ` Wilfred Mallawa
2024-07-02 13:27 ` Michael S. Tsirkin
2 siblings, 2 replies; 7+ messages in thread
From: Alistair Francis @ 2024-06-14 1:28 UTC (permalink / raw)
To: wilfred.mallawa, marcel.apfelbaum, lukas, qemu-devel, mst,
Jonathan.Cameron, kbusch, hchkuo, cbrowy, its, jiewen.yao
Cc: Alistair Francis, qemu-block, Paolo Bonzini, alistair23,
Jesper Devantier, Jonathan Cameron, Klaus Jensen
From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Setup Data Object Exchance (DOE) as an extended capability for the NVME
controller and connect SPDM to it (CMA) to it.
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Klaus Jensen <k.jensen@samsung.com>
---
docs/specs/index.rst | 1 +
docs/specs/spdm.rst | 134 ++++++++++++++++++++++++++++++++++++
include/hw/pci/pci_device.h | 7 ++
include/hw/pci/pcie_doe.h | 3 +
hw/nvme/ctrl.c | 60 ++++++++++++++++
5 files changed, 205 insertions(+)
create mode 100644 docs/specs/spdm.rst
diff --git a/docs/specs/index.rst b/docs/specs/index.rst
index 1484e3e760..e2d907959a 100644
--- a/docs/specs/index.rst
+++ b/docs/specs/index.rst
@@ -29,6 +29,7 @@ guest hardware that is specific to QEMU.
edu
ivshmem-spec
pvpanic
+ spdm
standard-vga
virt-ctlr
vmcoreinfo
diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
new file mode 100644
index 0000000000..f7de080ff0
--- /dev/null
+++ b/docs/specs/spdm.rst
@@ -0,0 +1,134 @@
+======================================================
+QEMU Security Protocols and Data Models (SPDM) Support
+======================================================
+
+SPDM enables authentication, attestation and key exchange to assist in
+providing infrastructure security enablement. It's a standard published
+by the `DMTF`_.
+
+QEMU supports connecting to a SPDM responder implementation. This allows an
+external application to emulate the SPDM responder logic for an SPDM device.
+
+Setting up a SPDM server
+========================
+
+When using QEMU with SPDM devices QEMU will connect to a server which
+implements the SPDM functionality.
+
+SPDM-Utils
+----------
+
+You can use `SPDM Utils`_ to emulate a responder. This is the simplest method.
+
+SPDM-Utils is a Linux applications to manage, test and develop devices
+supporting DMTF Security Protocol and Data Model (SPDM). It is written in Rust
+and utilises libspdm.
+
+To use SPDM-Utils you will need to do the following steps. Details are included
+in the SPDM-Utils README.
+
+ 1. `Build libspdm`_
+ 2. `Build SPDM Utils`_
+ 3. `Run it as a server`_
+
+spdm-emu
+--------
+
+You can use `spdm emu`_ to model the
+SPDM responder.
+
+.. code-block:: shell
+
+ $ cd spdm-emu
+ $ git submodule init; git submodule update --recursive
+ $ mkdir build; cd build
+ $ cmake -DARCH=x64 -DTOOLCHAIN=GCC -DTARGET=Debug -DCRYPTO=openssl ..
+ $ make -j32
+ $ make copy_sample_key # Build certificates, required for SPDM authentication.
+
+It is worth noting that the certificates should be in compliance with
+PCIe r6.1 sec 6.31.3. This means you will need to add the following to
+openssl.cnf
+
+.. code-block::
+
+ subjectAltName = otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100
+ 2.23.147 = ASN1:OID:2.23.147
+
+and then manually regenerate some certificates with:
+
+.. code-block:: shell
+
+ $ openssl req -nodes -newkey ec:param.pem -keyout end_responder.key \
+ -out end_responder.req -sha384 -batch \
+ -subj "/CN=DMTF libspdm ECP384 responder cert"
+
+ $ openssl x509 -req -in end_responder.req -out end_responder.cert \
+ -CA inter.cert -CAkey inter.key -sha384 -days 3650 -set_serial 3 \
+ -extensions v3_end -extfile ../openssl.cnf
+
+ $ openssl asn1parse -in end_responder.cert -out end_responder.cert.der
+
+ $ cat ca.cert.der inter.cert.der end_responder.cert.der > bundle_responder.certchain.der
+
+You can use SPDM-Utils instead as it will generate the correct certificates
+automatically.
+
+The responder can then be launched with
+
+.. code-block:: shell
+
+ $ cd bin
+ $ ./spdm_responder_emu --trans PCI_DOE
+
+Connecting an SPDM NVMe device
+==============================
+
+Once a SPDM server is running we can start QEMU and connect to the server.
+
+For an NVMe device first let's setup a block we can use
+
+.. code-block:: shell
+
+ $ cd qemu-spdm/linux/image
+ $ dd if=/dev/zero of=blknvme bs=1M count=2096 # 2GB NNMe Drive
+
+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
+
+At which point QEMU will try to connect to the SPDM server.
+
+Note that if using x64-64 you will want to use the q35 machine instead
+of the default. So the entire QEMU command might look like this
+
+.. code-block:: shell
+
+ qemu-system-x86_64 -M q35 \
+ --kernel bzImage \
+ -drive file=rootfs.ext2,if=virtio,format=raw \
+ -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
+
+.. _DMTF:
+ https://www.dmtf.org/standards/SPDM
+
+.. _SPDM Utils:
+ https://github.com/westerndigitalcorporation/spdm-utils
+
+.. _spdm emu:
+ https://github.com/dmtf/spdm-emu
+
+.. _Build libspdm:
+ https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-libspdm
+
+.. _Build SPDM Utils:
+ https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-the-binary
+
+.. _Run it as a server:
+ https://github.com/westerndigitalcorporation/spdm-utils#qemu-spdm-device-emulation
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index d3dd0f64b2..15694f2489 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -3,6 +3,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
+#include "hw/pci/pcie_doe.h"
#define TYPE_PCI_DEVICE "pci-device"
typedef struct PCIDeviceClass PCIDeviceClass;
@@ -157,6 +158,12 @@ struct PCIDevice {
MSIVectorReleaseNotifier msix_vector_release_notifier;
MSIVectorPollNotifier msix_vector_poll_notifier;
+ /* SPDM */
+ uint16_t spdm_port;
+
+ /* DOE */
+ DOECap doe_spdm;
+
/* ID of standby device in net_failover pair */
char *failover_pair_id;
uint32_t acpi_index;
diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
index 15d94661f9..9e1275db8a 100644
--- a/include/hw/pci/pcie_doe.h
+++ b/include/hw/pci/pcie_doe.h
@@ -108,6 +108,9 @@ struct DOECap {
/* Protocols and its callback response */
DOEProtocol *protocols;
uint16_t protocol_num;
+
+ /* Used for spdm-socket */
+ int spdm_socket;
};
void pcie_doe_init(PCIDevice *pdev, DOECap *doe_cap, uint16_t offset,
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 127c3d2383..db41f7c8d0 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -203,6 +203,7 @@
#include "sysemu/hostmem.h"
#include "hw/pci/msix.h"
#include "hw/pci/pcie_sriov.h"
+#include "sysemu/spdm-socket.h"
#include "migration/vmstate.h"
#include "nvme.h"
@@ -8087,6 +8088,27 @@ static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
return 0;
}
+static bool pcie_doe_spdm_rsp(DOECap *doe_cap)
+{
+ void *req = pcie_doe_get_write_mbox_ptr(doe_cap);
+ uint32_t req_len = pcie_doe_get_obj_len(req) * 4;
+ void *rsp = doe_cap->read_mbox;
+ uint32_t rsp_len = SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE;
+
+ uint32_t recvd = spdm_socket_rsp(doe_cap->spdm_socket,
+ SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE,
+ req, req_len, rsp, rsp_len);
+ doe_cap->read_mbox_len += DIV_ROUND_UP(recvd, 4);
+
+ return recvd != 0;
+}
+
+static DOEProtocol doe_spdm_prot[] = {
+ { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_CMA, pcie_doe_spdm_rsp },
+ { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_SECURED_CMA, pcie_doe_spdm_rsp },
+ { }
+};
+
static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
{
ERRP_GUARD();
@@ -8157,6 +8179,25 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
+ pcie_cap_deverr_init(pci_dev);
+
+ /* DOE 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;
+
+ 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);
+
+ if (pci_dev->doe_spdm.spdm_socket < 0) {
+ return false;
+ }
+ }
+
if (n->params.cmb_size_mb) {
nvme_init_cmb(n, pci_dev);
}
@@ -8407,6 +8448,11 @@ static void nvme_exit(PCIDevice *pci_dev)
g_free(n->cmb.buf);
}
+ 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->pmr.dev) {
host_memory_backend_set_mapped(n->pmr.dev, false);
}
@@ -8451,6 +8497,7 @@ static Property nvme_props[] = {
params.sriov_max_vq_per_vf, 0),
DEFINE_PROP_BOOL("msix-exclusive-bar", NvmeCtrl, params.msix_exclusive_bar,
false),
+ DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -8522,11 +8569,23 @@ static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
{
uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
+ pcie_doe_write_config(&dev->doe_spdm, address, val, len);
pci_default_write_config(dev, address, val, len);
pcie_cap_flr_write_config(dev, address, val, len);
nvme_sriov_post_write_config(dev, old_num_vfs);
}
+static uint32_t nvme_pci_read_config(PCIDevice *dev, uint32_t address, int len)
+{
+ uint32_t val;
+ if (dev->spdm_port) {
+ if (pcie_doe_read_config(&dev->doe_spdm, address, len, &val)) {
+ return val;
+ }
+ }
+ return pci_default_read_config(dev, address, len);
+}
+
static const VMStateDescription nvme_vmstate = {
.name = "nvme",
.unmigratable = 1,
@@ -8539,6 +8598,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
pc->realize = nvme_realize;
pc->config_write = nvme_pci_write_config;
+ pc->config_read = nvme_pci_read_config;
pc->exit = nvme_exit;
pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
pc->revision = 2;
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0
2024-06-14 1:28 ` [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0 Alistair Francis
@ 2024-06-14 1:52 ` Wilfred Mallawa
0 siblings, 0 replies; 7+ messages in thread
From: Wilfred Mallawa @ 2024-06-14 1:52 UTC (permalink / raw)
To: Alistair Francis, wilfred.mallawa, marcel.apfelbaum, lukas,
qemu-devel, mst, Jonathan.Cameron, kbusch, hchkuo, cbrowy, its,
jiewen.yao
Cc: Alistair Francis, qemu-block, Paolo Bonzini, Jesper Devantier
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
On Fri, 2024-06-14 at 11:28 +1000, Alistair Francis wrote:
> Add all of the defined protocols/features from the PCIe-SIG r6.0
> "Table 6-32 PCI-SIG defined Data Object Types (Vendor ID = 0001h)"
> table.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---
> include/hw/pci/pcie_doe.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
> index 87dc17dcef..15d94661f9 100644
> --- a/include/hw/pci/pcie_doe.h
> +++ b/include/hw/pci/pcie_doe.h
> @@ -46,6 +46,8 @@ REG32(PCI_DOE_CAP_STATUS, 0)
>
> /* PCI-SIG defined Data Object Types - r6.0 Table 6-32 */
> #define PCI_SIG_DOE_DISCOVERY 0x00
> +#define PCI_SIG_DOE_CMA 0x01
> +#define PCI_SIG_DOE_SECURED_CMA 0x02
>
> #define PCI_DOE_DW_SIZE_MAX (1 << 18)
> #define PCI_DOE_PROTOCOL_NUM_MAX 256
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support
2024-06-14 1:28 ` [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support Alistair Francis
@ 2024-06-14 1:56 ` Wilfred Mallawa
2024-07-02 13:27 ` Michael S. Tsirkin
1 sibling, 0 replies; 7+ messages in thread
From: Wilfred Mallawa @ 2024-06-14 1:56 UTC (permalink / raw)
To: Alistair Francis, wilfred.mallawa, marcel.apfelbaum, lukas,
qemu-devel, mst, Jonathan.Cameron, kbusch, hchkuo, cbrowy, its,
jiewen.yao
Cc: Alistair Francis, qemu-block, Paolo Bonzini, Jesper Devantier,
Klaus Jensen
On Fri, 2024-06-14 at 11:28 +1000, Alistair Francis wrote:
> From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
>
> Setup Data Object Exchance (DOE) as an extended capability for the
> NVME
small typo here 🤓️ [s/Setup Data Object Exchance/Setup Data Object
Exchange]
Wilfred
> controller and connect SPDM to it (CMA) to it.
>
> Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Acked-by: Klaus Jensen <k.jensen@samsung.com>
> ---
> docs/specs/index.rst | 1 +
> docs/specs/spdm.rst | 134
> ++++++++++++++++++++++++++++++++++++
> include/hw/pci/pci_device.h | 7 ++
> include/hw/pci/pcie_doe.h | 3 +
> hw/nvme/ctrl.c | 60 ++++++++++++++++
> 5 files changed, 205 insertions(+)
> create mode 100644 docs/specs/spdm.rst
>
> diff --git a/docs/specs/index.rst b/docs/specs/index.rst
> index 1484e3e760..e2d907959a 100644
> --- a/docs/specs/index.rst
> +++ b/docs/specs/index.rst
> @@ -29,6 +29,7 @@ guest hardware that is specific to QEMU.
> edu
> ivshmem-spec
> pvpanic
> + spdm
> standard-vga
> virt-ctlr
> vmcoreinfo
> diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
> new file mode 100644
> index 0000000000..f7de080ff0
> --- /dev/null
> +++ b/docs/specs/spdm.rst
> @@ -0,0 +1,134 @@
> +======================================================
> +QEMU Security Protocols and Data Models (SPDM) Support
> +======================================================
> +
> +SPDM enables authentication, attestation and key exchange to assist
> in
> +providing infrastructure security enablement. It's a standard
> published
> +by the `DMTF`_.
> +
> +QEMU supports connecting to a SPDM responder implementation. This
> allows an
> +external application to emulate the SPDM responder logic for an SPDM
> device.
> +
> +Setting up a SPDM server
> +========================
> +
> +When using QEMU with SPDM devices QEMU will connect to a server
> which
> +implements the SPDM functionality.
> +
> +SPDM-Utils
> +----------
> +
> +You can use `SPDM Utils`_ to emulate a responder. This is the
> simplest method.
> +
> +SPDM-Utils is a Linux applications to manage, test and develop
> devices
> +supporting DMTF Security Protocol and Data Model (SPDM). It is
> written in Rust
> +and utilises libspdm.
> +
> +To use SPDM-Utils you will need to do the following steps. Details
> are included
> +in the SPDM-Utils README.
> +
> + 1. `Build libspdm`_
> + 2. `Build SPDM Utils`_
> + 3. `Run it as a server`_
> +
> +spdm-emu
> +--------
> +
> +You can use `spdm emu`_ to model the
> +SPDM responder.
> +
> +.. code-block:: shell
> +
> + $ cd spdm-emu
> + $ git submodule init; git submodule update --recursive
> + $ mkdir build; cd build
> + $ cmake -DARCH=x64 -DTOOLCHAIN=GCC -DTARGET=Debug -
> DCRYPTO=openssl ..
> + $ make -j32
> + $ make copy_sample_key # Build certificates, required for SPDM
> authentication.
> +
> +It is worth noting that the certificates should be in compliance
> with
> +PCIe r6.1 sec 6.31.3. This means you will need to add the following
> to
> +openssl.cnf
> +
> +.. code-block::
> +
> + subjectAltName =
> otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVI
> D=1af4:SSID=1100
> + 2.23.147 = ASN1:OID:2.23.147
> +
> +and then manually regenerate some certificates with:
> +
> +.. code-block:: shell
> +
> + $ openssl req -nodes -newkey ec:param.pem -keyout
> end_responder.key \
> + -out end_responder.req -sha384 -batch \
> + -subj "/CN=DMTF libspdm ECP384 responder cert"
> +
> + $ openssl x509 -req -in end_responder.req -out
> end_responder.cert \
> + -CA inter.cert -CAkey inter.key -sha384 -days 3650 -
> set_serial 3 \
> + -extensions v3_end -extfile ../openssl.cnf
> +
> + $ openssl asn1parse -in end_responder.cert -out
> end_responder.cert.der
> +
> + $ cat ca.cert.der inter.cert.der end_responder.cert.der >
> bundle_responder.certchain.der
> +
> +You can use SPDM-Utils instead as it will generate the correct
> certificates
> +automatically.
> +
> +The responder can then be launched with
> +
> +.. code-block:: shell
> +
> + $ cd bin
> + $ ./spdm_responder_emu --trans PCI_DOE
> +
> +Connecting an SPDM NVMe device
> +==============================
> +
> +Once a SPDM server is running we can start QEMU and connect to the
> server.
> +
> +For an NVMe device first let's setup a block we can use
> +
> +.. code-block:: shell
> +
> + $ cd qemu-spdm/linux/image
> + $ dd if=/dev/zero of=blknvme bs=1M count=2096 # 2GB NNMe Drive
> +
> +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
> +
> +At which point QEMU will try to connect to the SPDM server.
> +
> +Note that if using x64-64 you will want to use the q35 machine
> instead
> +of the default. So the entire QEMU command might look like this
> +
> +.. code-block:: shell
> +
> + qemu-system-x86_64 -M q35 \
> + --kernel bzImage \
> + -drive file=rootfs.ext2,if=virtio,format=raw \
> + -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
> +
> +.. _DMTF:
> + https://www.dmtf.org/standards/SPDM
> +
> +.. _SPDM Utils:
> + https://github.com/westerndigitalcorporation/spdm-utils
> +
> +.. _spdm emu:
> + https://github.com/dmtf/spdm-emu
> +
> +.. _Build libspdm:
> +
> https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-libspdm
> +
> +.. _Build SPDM Utils:
> +
> https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-the-binary
> +
> +.. _Run it as a server:
> +
> https://github.com/westerndigitalcorporation/spdm-utils#qemu-spdm-device-emulation
> diff --git a/include/hw/pci/pci_device.h
> b/include/hw/pci/pci_device.h
> index d3dd0f64b2..15694f2489 100644
> --- a/include/hw/pci/pci_device.h
> +++ b/include/hw/pci/pci_device.h
> @@ -3,6 +3,7 @@
>
> #include "hw/pci/pci.h"
> #include "hw/pci/pcie.h"
> +#include "hw/pci/pcie_doe.h"
>
> #define TYPE_PCI_DEVICE "pci-device"
> typedef struct PCIDeviceClass PCIDeviceClass;
> @@ -157,6 +158,12 @@ struct PCIDevice {
> MSIVectorReleaseNotifier msix_vector_release_notifier;
> MSIVectorPollNotifier msix_vector_poll_notifier;
>
> + /* SPDM */
> + uint16_t spdm_port;
> +
> + /* DOE */
> + DOECap doe_spdm;
> +
> /* ID of standby device in net_failover pair */
> char *failover_pair_id;
> uint32_t acpi_index;
> diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
> index 15d94661f9..9e1275db8a 100644
> --- a/include/hw/pci/pcie_doe.h
> +++ b/include/hw/pci/pcie_doe.h
> @@ -108,6 +108,9 @@ struct DOECap {
> /* Protocols and its callback response */
> DOEProtocol *protocols;
> uint16_t protocol_num;
> +
> + /* Used for spdm-socket */
> + int spdm_socket;
> };
>
> void pcie_doe_init(PCIDevice *pdev, DOECap *doe_cap, uint16_t
> offset,
> diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
> index 127c3d2383..db41f7c8d0 100644
> --- a/hw/nvme/ctrl.c
> +++ b/hw/nvme/ctrl.c
> @@ -203,6 +203,7 @@
> #include "sysemu/hostmem.h"
> #include "hw/pci/msix.h"
> #include "hw/pci/pcie_sriov.h"
> +#include "sysemu/spdm-socket.h"
> #include "migration/vmstate.h"
>
> #include "nvme.h"
> @@ -8087,6 +8088,27 @@ static int nvme_add_pm_capability(PCIDevice
> *pci_dev, uint8_t offset)
> return 0;
> }
>
> +static bool pcie_doe_spdm_rsp(DOECap *doe_cap)
> +{
> + void *req = pcie_doe_get_write_mbox_ptr(doe_cap);
> + uint32_t req_len = pcie_doe_get_obj_len(req) * 4;
> + void *rsp = doe_cap->read_mbox;
> + uint32_t rsp_len = SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE;
> +
> + uint32_t recvd = spdm_socket_rsp(doe_cap->spdm_socket,
> + SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE,
> + req, req_len, rsp, rsp_len);
> + doe_cap->read_mbox_len += DIV_ROUND_UP(recvd, 4);
> +
> + return recvd != 0;
> +}
> +
> +static DOEProtocol doe_spdm_prot[] = {
> + { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_CMA, pcie_doe_spdm_rsp },
> + { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_SECURED_CMA,
> pcie_doe_spdm_rsp },
> + { }
> +};
> +
> static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error
> **errp)
> {
> ERRP_GUARD();
> @@ -8157,6 +8179,25 @@ static bool nvme_init_pci(NvmeCtrl *n,
> PCIDevice *pci_dev, Error **errp)
>
> nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
>
> + pcie_cap_deverr_init(pci_dev);
> +
> + /* DOE 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;
> +
> + 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);
> +
> + if (pci_dev->doe_spdm.spdm_socket < 0) {
> + return false;
> + }
> + }
> +
> if (n->params.cmb_size_mb) {
> nvme_init_cmb(n, pci_dev);
> }
> @@ -8407,6 +8448,11 @@ static void nvme_exit(PCIDevice *pci_dev)
> g_free(n->cmb.buf);
> }
>
> + 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->pmr.dev) {
> host_memory_backend_set_mapped(n->pmr.dev, false);
> }
> @@ -8451,6 +8497,7 @@ static Property nvme_props[] = {
> params.sriov_max_vq_per_vf, 0),
> DEFINE_PROP_BOOL("msix-exclusive-bar", NvmeCtrl,
> params.msix_exclusive_bar,
> false),
> + DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
> DEFINE_PROP_END_OF_LIST(),
> };
>
> @@ -8522,11 +8569,23 @@ static void nvme_pci_write_config(PCIDevice
> *dev, uint32_t address,
> {
> uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
>
> + pcie_doe_write_config(&dev->doe_spdm, address, val, len);
> pci_default_write_config(dev, address, val, len);
> pcie_cap_flr_write_config(dev, address, val, len);
> nvme_sriov_post_write_config(dev, old_num_vfs);
> }
>
> +static uint32_t nvme_pci_read_config(PCIDevice *dev, uint32_t
> address, int len)
> +{
> + uint32_t val;
> + if (dev->spdm_port) {
> + if (pcie_doe_read_config(&dev->doe_spdm, address, len,
> &val)) {
> + return val;
> + }
> + }
> + return pci_default_read_config(dev, address, len);
> +}
> +
> static const VMStateDescription nvme_vmstate = {
> .name = "nvme",
> .unmigratable = 1,
> @@ -8539,6 +8598,7 @@ static void nvme_class_init(ObjectClass *oc,
> void *data)
>
> pc->realize = nvme_realize;
> pc->config_write = nvme_pci_write_config;
> + pc->config_read = nvme_pci_read_config;
> pc->exit = nvme_exit;
> pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
> pc->revision = 2;
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support
2024-06-14 1:28 ` [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support Alistair Francis
2024-06-14 1:56 ` Wilfred Mallawa
@ 2024-07-02 13:27 ` Michael S. Tsirkin
1 sibling, 0 replies; 7+ messages in thread
From: Michael S. Tsirkin @ 2024-07-02 13:27 UTC (permalink / raw)
To: Alistair Francis
Cc: wilfred.mallawa, marcel.apfelbaum, lukas, qemu-devel,
Jonathan.Cameron, kbusch, hchkuo, cbrowy, its, jiewen.yao,
Alistair Francis, qemu-block, Paolo Bonzini, Jesper Devantier,
Klaus Jensen
On Fri, Jun 14, 2024 at 11:28:46AM +1000, Alistair Francis wrote:
> From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
>
> Setup Data Object Exchance (DOE) as an extended capability for the NVME
> controller and connect SPDM to it (CMA) to it.
>
> Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Acked-by: Klaus Jensen <k.jensen@samsung.com>
With this, qos-test fails:
# Start of nvme-tests tests
# starting QEMU: exec ./build/qemu-system-x86_64 -qtest unix:/tmp/qtest-72968.sock -qtest-log /dev/null -chardev socket,path=/tmp/qtest-72968.qmp,id=char0 -mon chardev=char0,mode=control -display none -audio none -M pc -drive id=drv0,if=none,file=null-co://,file.read-zeroes=on,format=raw -object memory-backend-ram,id=pmr0,share=on,size=8 -device nvme,addr=04.0,drive=drv0,serial=foo,cmb_size_mb=2 -accel qtest
ok 27 /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/nvme/nvme-tests/oob-cmb-access
# starting QEMU: exec ./build/qemu-system-x86_64 -qtest unix:/tmp/qtest-72968.sock -qtest-log /dev/null -chardev socket,path=/tmp/qtest-72968.qmp,id=char0 -mon chardev=char0,mode=control -display none -audio none -M pc -drive id=drv0,if=none,file=null-co://,file.read-zeroes=on,format=raw -object memory-backend-ram,id=pmr0,share=on,size=8 -device nvme,addr=04.0,drive=drv0,serial=foo,pmrdev=pmr0 -accel qtest
Broken pipe
../tests/qtest/libqtest.c:205: kill_qemu() detected QEMU death from signal 11 (Segmentation fault) (core dumped)
./run4bisect.sh: line 30: 72968 Aborted (core dumped) QTEST_QEMU_STORAGE_DAEMON_BINARY=./build/storage-daemon/qemu-storage-daemon QTEST_QEMU_BINARY=./build/qemu-system-x86_64 ./build/tests/qtest/qos-test
TEST DONE 1
Also here:
https://gitlab.com/mstredhat/qemu/-/jobs/7245683487
I dropped the patchset for now, pls resolve and resubmit.
> ---
> docs/specs/index.rst | 1 +
> docs/specs/spdm.rst | 134 ++++++++++++++++++++++++++++++++++++
> include/hw/pci/pci_device.h | 7 ++
> include/hw/pci/pcie_doe.h | 3 +
> hw/nvme/ctrl.c | 60 ++++++++++++++++
> 5 files changed, 205 insertions(+)
> create mode 100644 docs/specs/spdm.rst
>
> diff --git a/docs/specs/index.rst b/docs/specs/index.rst
> index 1484e3e760..e2d907959a 100644
> --- a/docs/specs/index.rst
> +++ b/docs/specs/index.rst
> @@ -29,6 +29,7 @@ guest hardware that is specific to QEMU.
> edu
> ivshmem-spec
> pvpanic
> + spdm
> standard-vga
> virt-ctlr
> vmcoreinfo
> diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
> new file mode 100644
> index 0000000000..f7de080ff0
> --- /dev/null
> +++ b/docs/specs/spdm.rst
> @@ -0,0 +1,134 @@
> +======================================================
> +QEMU Security Protocols and Data Models (SPDM) Support
> +======================================================
> +
> +SPDM enables authentication, attestation and key exchange to assist in
> +providing infrastructure security enablement. It's a standard published
> +by the `DMTF`_.
> +
> +QEMU supports connecting to a SPDM responder implementation. This allows an
> +external application to emulate the SPDM responder logic for an SPDM device.
> +
> +Setting up a SPDM server
> +========================
> +
> +When using QEMU with SPDM devices QEMU will connect to a server which
> +implements the SPDM functionality.
> +
> +SPDM-Utils
> +----------
> +
> +You can use `SPDM Utils`_ to emulate a responder. This is the simplest method.
> +
> +SPDM-Utils is a Linux applications to manage, test and develop devices
> +supporting DMTF Security Protocol and Data Model (SPDM). It is written in Rust
> +and utilises libspdm.
> +
> +To use SPDM-Utils you will need to do the following steps. Details are included
> +in the SPDM-Utils README.
> +
> + 1. `Build libspdm`_
> + 2. `Build SPDM Utils`_
> + 3. `Run it as a server`_
> +
> +spdm-emu
> +--------
> +
> +You can use `spdm emu`_ to model the
> +SPDM responder.
> +
> +.. code-block:: shell
> +
> + $ cd spdm-emu
> + $ git submodule init; git submodule update --recursive
> + $ mkdir build; cd build
> + $ cmake -DARCH=x64 -DTOOLCHAIN=GCC -DTARGET=Debug -DCRYPTO=openssl ..
> + $ make -j32
> + $ make copy_sample_key # Build certificates, required for SPDM authentication.
> +
> +It is worth noting that the certificates should be in compliance with
> +PCIe r6.1 sec 6.31.3. This means you will need to add the following to
> +openssl.cnf
> +
> +.. code-block::
> +
> + subjectAltName = otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100
> + 2.23.147 = ASN1:OID:2.23.147
> +
> +and then manually regenerate some certificates with:
> +
> +.. code-block:: shell
> +
> + $ openssl req -nodes -newkey ec:param.pem -keyout end_responder.key \
> + -out end_responder.req -sha384 -batch \
> + -subj "/CN=DMTF libspdm ECP384 responder cert"
> +
> + $ openssl x509 -req -in end_responder.req -out end_responder.cert \
> + -CA inter.cert -CAkey inter.key -sha384 -days 3650 -set_serial 3 \
> + -extensions v3_end -extfile ../openssl.cnf
> +
> + $ openssl asn1parse -in end_responder.cert -out end_responder.cert.der
> +
> + $ cat ca.cert.der inter.cert.der end_responder.cert.der > bundle_responder.certchain.der
> +
> +You can use SPDM-Utils instead as it will generate the correct certificates
> +automatically.
> +
> +The responder can then be launched with
> +
> +.. code-block:: shell
> +
> + $ cd bin
> + $ ./spdm_responder_emu --trans PCI_DOE
> +
> +Connecting an SPDM NVMe device
> +==============================
> +
> +Once a SPDM server is running we can start QEMU and connect to the server.
> +
> +For an NVMe device first let's setup a block we can use
> +
> +.. code-block:: shell
> +
> + $ cd qemu-spdm/linux/image
> + $ dd if=/dev/zero of=blknvme bs=1M count=2096 # 2GB NNMe Drive
> +
> +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
> +
> +At which point QEMU will try to connect to the SPDM server.
> +
> +Note that if using x64-64 you will want to use the q35 machine instead
> +of the default. So the entire QEMU command might look like this
> +
> +.. code-block:: shell
> +
> + qemu-system-x86_64 -M q35 \
> + --kernel bzImage \
> + -drive file=rootfs.ext2,if=virtio,format=raw \
> + -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
> +
> +.. _DMTF:
> + https://www.dmtf.org/standards/SPDM
> +
> +.. _SPDM Utils:
> + https://github.com/westerndigitalcorporation/spdm-utils
> +
> +.. _spdm emu:
> + https://github.com/dmtf/spdm-emu
> +
> +.. _Build libspdm:
> + https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-libspdm
> +
> +.. _Build SPDM Utils:
> + https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-the-binary
> +
> +.. _Run it as a server:
> + https://github.com/westerndigitalcorporation/spdm-utils#qemu-spdm-device-emulation
> diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
> index d3dd0f64b2..15694f2489 100644
> --- a/include/hw/pci/pci_device.h
> +++ b/include/hw/pci/pci_device.h
> @@ -3,6 +3,7 @@
>
> #include "hw/pci/pci.h"
> #include "hw/pci/pcie.h"
> +#include "hw/pci/pcie_doe.h"
>
> #define TYPE_PCI_DEVICE "pci-device"
> typedef struct PCIDeviceClass PCIDeviceClass;
> @@ -157,6 +158,12 @@ struct PCIDevice {
> MSIVectorReleaseNotifier msix_vector_release_notifier;
> MSIVectorPollNotifier msix_vector_poll_notifier;
>
> + /* SPDM */
> + uint16_t spdm_port;
> +
> + /* DOE */
> + DOECap doe_spdm;
> +
> /* ID of standby device in net_failover pair */
> char *failover_pair_id;
> uint32_t acpi_index;
> diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
> index 15d94661f9..9e1275db8a 100644
> --- a/include/hw/pci/pcie_doe.h
> +++ b/include/hw/pci/pcie_doe.h
> @@ -108,6 +108,9 @@ struct DOECap {
> /* Protocols and its callback response */
> DOEProtocol *protocols;
> uint16_t protocol_num;
> +
> + /* Used for spdm-socket */
> + int spdm_socket;
> };
>
> void pcie_doe_init(PCIDevice *pdev, DOECap *doe_cap, uint16_t offset,
> diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
> index 127c3d2383..db41f7c8d0 100644
> --- a/hw/nvme/ctrl.c
> +++ b/hw/nvme/ctrl.c
> @@ -203,6 +203,7 @@
> #include "sysemu/hostmem.h"
> #include "hw/pci/msix.h"
> #include "hw/pci/pcie_sriov.h"
> +#include "sysemu/spdm-socket.h"
> #include "migration/vmstate.h"
>
> #include "nvme.h"
> @@ -8087,6 +8088,27 @@ static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
> return 0;
> }
>
> +static bool pcie_doe_spdm_rsp(DOECap *doe_cap)
> +{
> + void *req = pcie_doe_get_write_mbox_ptr(doe_cap);
> + uint32_t req_len = pcie_doe_get_obj_len(req) * 4;
> + void *rsp = doe_cap->read_mbox;
> + uint32_t rsp_len = SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE;
> +
> + uint32_t recvd = spdm_socket_rsp(doe_cap->spdm_socket,
> + SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE,
> + req, req_len, rsp, rsp_len);
> + doe_cap->read_mbox_len += DIV_ROUND_UP(recvd, 4);
> +
> + return recvd != 0;
> +}
> +
> +static DOEProtocol doe_spdm_prot[] = {
> + { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_CMA, pcie_doe_spdm_rsp },
> + { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_SECURED_CMA, pcie_doe_spdm_rsp },
> + { }
> +};
> +
> static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
> {
> ERRP_GUARD();
> @@ -8157,6 +8179,25 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
>
> nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
>
> + pcie_cap_deverr_init(pci_dev);
> +
> + /* DOE 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;
> +
> + 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);
> +
> + if (pci_dev->doe_spdm.spdm_socket < 0) {
> + return false;
> + }
> + }
> +
> if (n->params.cmb_size_mb) {
> nvme_init_cmb(n, pci_dev);
> }
> @@ -8407,6 +8448,11 @@ static void nvme_exit(PCIDevice *pci_dev)
> g_free(n->cmb.buf);
> }
>
> + 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->pmr.dev) {
> host_memory_backend_set_mapped(n->pmr.dev, false);
> }
> @@ -8451,6 +8497,7 @@ static Property nvme_props[] = {
> params.sriov_max_vq_per_vf, 0),
> DEFINE_PROP_BOOL("msix-exclusive-bar", NvmeCtrl, params.msix_exclusive_bar,
> false),
> + DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
> DEFINE_PROP_END_OF_LIST(),
> };
>
> @@ -8522,11 +8569,23 @@ static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
> {
> uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
>
> + pcie_doe_write_config(&dev->doe_spdm, address, val, len);
> pci_default_write_config(dev, address, val, len);
> pcie_cap_flr_write_config(dev, address, val, len);
> nvme_sriov_post_write_config(dev, old_num_vfs);
> }
>
> +static uint32_t nvme_pci_read_config(PCIDevice *dev, uint32_t address, int len)
> +{
> + uint32_t val;
> + if (dev->spdm_port) {
> + if (pcie_doe_read_config(&dev->doe_spdm, address, len, &val)) {
> + return val;
> + }
> + }
> + return pci_default_read_config(dev, address, len);
> +}
> +
> static const VMStateDescription nvme_vmstate = {
> .name = "nvme",
> .unmigratable = 1,
> @@ -8539,6 +8598,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
>
> pc->realize = nvme_realize;
> pc->config_write = nvme_pci_write_config;
> + pc->config_read = nvme_pci_read_config;
> pc->exit = nvme_exit;
> pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
> pc->revision = 2;
> --
> 2.45.2
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-07-02 13:28 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-14 1:28 [PATCH v7 0/3] Initial support for SPDM Responders Alistair Francis
2024-06-14 1:28 ` [PATCH v7 1/3] hw/pci: Add all Data Object Types defined in PCIe r6.0 Alistair Francis
2024-06-14 1:52 ` Wilfred Mallawa
2024-06-14 1:28 ` [PATCH v7 2/3] backends: Initial support for SPDM socket support Alistair Francis
2024-06-14 1:28 ` [PATCH v7 3/3] hw/nvme: Add SPDM over DOE support Alistair Francis
2024-06-14 1:56 ` Wilfred Mallawa
2024-07-02 13:27 ` Michael S. Tsirkin
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).