qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v1 QEMU CXL modifications for openspdm 1/1] pcie/spdm: PCIe CMA i


From: Chris Browy
Subject: [PATCH v1 QEMU CXL modifications for openspdm 1/1] pcie/spdm: PCIe CMA implementation
Date: Fri, 25 Jun 2021 20:05:39 -0400

From: hchkuo <hchkuo@avery-design.com.tw>

The Data Object Exchange implementation of Component Measurement
and Authentication (CMA). This patch is basically based on Openspdm:
https://github.com/jyao1/openspdm.git.

Openspdm is an emulator composed of an SPDM requester and an SPDM
responder. The requester and responder communicate with each other via
a TCP socket. The Openspdm requester is merged to this patch as a DOE
capability in hw/mem/cxl_type3.c. The "-spdm=<bool>" is provided to turn
on/off the CMA capability. Once the option is turned on (-spdm=true) the 
CXL device can communicate with Openspdm's responder to get the data 
object of SPDM/secured SPDM.

Signed-off-by: hchkuo <hchkuo@avery-design.com.tw>
Signed-off-by: Chris Browy <cbrowy@avery-design.com>
---
 hw/mem/cxl_type3.c              |  31 +++-
 hw/pci/Kconfig                  |   4 +
 hw/pci/SpdmEmuCommand.c         | 319 ++++++++++++++++++++++++++++++++++++++++
 hw/pci/meson.build              |   1 +
 include/hw/cxl/cxl_device.h     |   2 +
 include/hw/pci/SpdmEmuCommand.h |  21 +++
 include/hw/pci/pcie_doe.h       |   2 +
 7 files changed, 377 insertions(+), 3 deletions(-)
 create mode 100644 hw/pci/SpdmEmuCommand.c
 create mode 100644 include/hw/pci/SpdmEmuCommand.h

diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 4b4097f..da38f3f 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -16,6 +16,8 @@
 #include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 
+#include "hw/pci/SpdmEmuCommand.h"
+
 #define DWORD_BYTE 4
 
 /* This function will be used when cdat file is not specified */
@@ -266,6 +268,9 @@ static uint32_t ct3d_config_read(PCIDevice *pci_dev, 
uint32_t addr, int size)
 
     if (pcie_doe_read_config(&ct3d->doe_comp, addr, size, &val)) {
         return val;
+    } else if (ct3d->use_spdm &&
+               pcie_doe_read_config(&ct3d->doe_spdm, addr, size, &val)) {
+        return val;
     } else if (pcie_doe_read_config(&ct3d->doe_cdat, addr, size, &val)) {
         return val;
     }
@@ -278,6 +283,9 @@ static void ct3d_config_write(PCIDevice *pci_dev, uint32_t 
addr, uint32_t val,
 {
     CXLType3Dev *ct3d = CT3(pci_dev);
 
+    if (ct3d->use_spdm) {
+        pcie_doe_write_config(&ct3d->doe_spdm, addr, val, size);
+    }
     pcie_doe_write_config(&ct3d->doe_comp, addr, val, size);
     pcie_doe_write_config(&ct3d->doe_cdat, addr, val, size);
     pci_default_write_config(pci_dev, addr, val, size);
@@ -472,6 +480,12 @@ static MemoryRegion 
*cxl_md_get_memory_region(MemoryDeviceState *md,
     return ct3d->cxl_dstate.pmem;
 }
 
+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 DOEProtocol doe_comp_prot[] = {
     {CXL_VENDOR_ID, CXL_DOE_COMPLIANCE, cxl_doe_compliance_rsp},
     {},
@@ -489,7 +503,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
     ComponentRegisters *regs = &cxl_cstate->crb;
     MemoryRegion *mr = &regs->component_registers;
     uint8_t *pci_conf = pci_dev->config;
-    unsigned short msix_num = 2;
+    unsigned short msix_num = 3;
     int i;
 
     if (!ct3d->cxl_dstate.pmem) {
@@ -528,13 +542,22 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
     }
 
     /* DOE Initailization */
-    pcie_doe_init(pci_dev, &ct3d->doe_comp, 0x160, doe_comp_prot, true, 0);
-    pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x190, doe_cdat_prot, true, 1);
+    if (ct3d->use_spdm) {
+        spdm_sock_init(errp);
+        pcie_doe_init(pci_dev, &ct3d->doe_spdm, 0x160, doe_spdm_prot, true, 2);
+    }
+    pcie_doe_init(pci_dev, &ct3d->doe_comp, 0x190, doe_comp_prot, true, 1);
+    pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x1b0, doe_cdat_prot, true, 0);
 
     cxl_cstate->cdat.build_cdat_table = build_default_cdat_table;
     cxl_doe_cdat_init(cxl_cstate, errp);
 }
 
+static void ct3_exit(PCIDevice *pci_dev)
+{
+    spdm_sock_fini();
+}
+
 static uint64_t cxl_md_get_addr(const MemoryDeviceState *md)
 {
     CXLType3Dev *ct3d = CT3(md);
@@ -570,6 +593,7 @@ static Property ct3_props[] = {
     DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND,
                      HostMemoryBackend *),
     DEFINE_PROP_STRING("cdat", CXLType3Dev, cxl_cstate.cdat.filename),
+    DEFINE_PROP_BOOL("spdm", CXLType3Dev, use_spdm, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -658,6 +682,7 @@ static void ct3_class_init(ObjectClass *oc, void *data)
     CXLType3Class *cvc = CXL_TYPE3_DEV_CLASS(oc);
 
     pc->realize = ct3_realize;
+    pc->exit = ct3_exit;
     pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
     pc->vendor_id = PCI_VENDOR_ID_INTEL;
     pc->device_id = 0xd93; /* LVF for now */
diff --git a/hw/pci/Kconfig b/hw/pci/Kconfig
index 77f8b00..181495e 100644
--- a/hw/pci/Kconfig
+++ b/hw/pci/Kconfig
@@ -13,3 +13,7 @@ config MSI_NONBROKEN
     # or support it and have a good implementation. See commit
     # 47d2b0f33c664533b8dbd5cb17faa8e6a01afe1f.
     bool
+
+config PCIE_SPDM
+    bool
+    default y
diff --git a/hw/pci/SpdmEmuCommand.c b/hw/pci/SpdmEmuCommand.c
new file mode 100644
index 0000000..b1944fa
--- /dev/null
+++ b/hw/pci/SpdmEmuCommand.c
@@ -0,0 +1,319 @@
+/**
+@file
+UEFI OS based application.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "hw/pci/SpdmEmuCommand.h"
+#include "qapi/error.h"
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#define DWORD_BYTE 4
+
+struct in_addr mIpAddress = {0x0100007F};
+int ClientSocket;
+uint32_t mUseTransportLayer = SOCKET_TRANSPORT_TYPE_PCI_DOE;
+
+/**
+  This function dump raw data.
+
+  @param  Data  raw data
+  @param  Size  raw data size
+**/
+static void DumpData(uint8_t *Data, uint64_t Size)
+{
+    uint64_t Index;
+
+    for (Index = 0; Index < Size; Index++) {
+        if (Index != 0) {
+            printf (" ");
+        }
+        printf ("%02x", Data[Index]);
+    }
+    printf("\n");
+}
+
+/**
+  Read number of bytes data in blocking mode.
+
+  If there is no enough data in socket, this function will wait.
+  This function will return if enough data is read, or socket error.
+**/
+static bool ReadBytes(int Socket, uint8_t *Buffer, uint32_t NumberOfBytes)
+{
+    int Result;
+    uint32_t NumberReceived;
+
+    NumberReceived = 0;
+    while (NumberReceived < NumberOfBytes) {
+        Result = recv(Socket, (char *)(Buffer + NumberReceived),
+                      NumberOfBytes - NumberReceived, 0);
+        if (Result == -1) {
+            printf("Receive error - 0x%x\n", errno);
+            return false;
+        }
+        if (Result == 0) {
+            return false;
+        }
+        NumberReceived += Result;
+    }
+    return true;
+}
+
+static bool ReadData32(int Socket, uint32_t *Data)
+{
+    bool Result;
+
+    Result = ReadBytes(Socket, (uint8_t *)Data, sizeof(uint32_t));
+    if (!Result) {
+        return Result;
+    }
+    *Data = ntohl(*Data);
+    return true;
+}
+
+/**
+  Read multiple bytes in blocking mode.
+
+  The length is presented as first 4 bytes in big endian.
+  The data follows the length.
+
+  If there is no enough data in socket, this function will wait.
+  This function will return if enough data is read, or socket error.
+**/
+static bool ReadMultipleBytes(int Socket, uint8_t *Buffer,
+                              uint32_t *BytesReceived, uint32_t 
MaxBufferLength)
+{
+    uint32_t Length;
+    bool Result;
+
+    Result = ReadData32(Socket, &Length);
+    if (!Result) {
+        return Result;
+    }
+    printf("Platform Port Receive Size: ");
+    Length = ntohl(Length);
+    DumpData((uint8_t *)&Length, sizeof(uint32_t));
+    Length = ntohl(Length);
+
+    *BytesReceived = Length;
+    if (*BytesReceived > MaxBufferLength) {
+        printf("Buffer too small (0x%x). Expected - 0x%x\n",
+               MaxBufferLength, *BytesReceived);
+        return false;
+    }
+    if (Length == 0) {
+        return true;
+    }
+    Result = ReadBytes (Socket, Buffer, Length);
+    if (!Result) {
+        return Result;
+    }
+    printf("Platform Port Receive Buffer:\n    ");
+    DumpData(Buffer, Length);
+    return true;
+}
+
+static bool ReceivePlatformData(int Socket, uint32_t *Command,
+                                uint8_t *ReceiveBuffer,
+                                uint32_t *BytesToReceive)
+{
+    bool Result;
+    uint32_t Response;
+    uint32_t TransportType;
+    uint32_t BytesReceived;
+
+    Result = ReadData32(Socket, &Response);
+    if (!Result) {
+        return Result;
+    }
+    *Command = Response;
+    printf("Platform Port Receive Command: ");
+    Response = ntohl(Response);
+    DumpData((uint8_t *)&Response, sizeof(uint32_t));
+
+    Result = ReadData32(Socket, &TransportType);
+    if (!Result) {
+        return Result;
+    }
+    printf("Platform Port Receive TransportType: ");
+    TransportType = ntohl(TransportType);
+    DumpData((uint8_t *)&TransportType, sizeof(uint32_t));
+    TransportType = ntohl(TransportType);
+    if (TransportType != mUseTransportLayer) {
+        printf("TransportType mismatch\n");
+        return false;
+    }
+
+    BytesReceived = 0;
+    Result = ReadMultipleBytes(Socket, ReceiveBuffer, &BytesReceived,
+                               (uint32_t)*BytesToReceive);
+    if (!Result) {
+        return Result;
+    }
+    *BytesToReceive = BytesReceived;
+
+    return Result;
+}
+
+/**
+  Write number of bytes data in blocking mode.
+
+  This function will return if data is written, or socket error.
+**/
+static bool WriteBytes(int Socket, uint8_t *Buffer, uint32_t NumberOfBytes)
+{
+    int Result;
+    uint32_t NumberSent;
+
+    NumberSent = 0;
+    while (NumberSent < NumberOfBytes) {
+        Result = send(Socket, (char *)(Buffer + NumberSent),
+                      NumberOfBytes - NumberSent, 0);
+        if (Result == -1) {
+            printf ("Send error - 0x%x\n", errno);
+            return false;
+        }
+        NumberSent += Result;
+    }
+    return true;
+}
+
+static bool WriteData32(int Socket, uint32_t Data)
+{
+    Data = htonl(Data);
+    return WriteBytes(Socket, (uint8_t *)&Data, sizeof(uint32_t));
+}
+
+/**
+  Write multiple bytes.
+
+  The length is presented as first 4 bytes in big endian.
+  The data follows the length.
+**/
+static bool WriteMultipleBytes(int Socket, uint8_t *Buffer,
+                               uint32_t BytesToSend)
+{
+    bool Result;
+
+    Result = WriteData32 (Socket, BytesToSend);
+    if (!Result) {
+        return Result;
+    }
+    printf("Platform Port Transmit Size: ");
+    BytesToSend = htonl(BytesToSend);
+    DumpData((uint8_t *)&BytesToSend, sizeof(uint32_t));
+    BytesToSend = htonl(BytesToSend);
+
+    Result = WriteBytes(Socket, Buffer, BytesToSend);
+    if (!Result) {
+        return Result;
+    }
+    printf("Platform Port Transmit Buffer:\n    ");
+    DumpData(Buffer, BytesToSend);
+
+    return true;
+}
+
+static bool SendPlatformData(int Socket, uint32_t Command, uint8_t *SendBuffer,
+                             uint32_t BytesToSend)
+{
+    bool Result;
+    uint32_t Request;
+    uint32_t TransportType;
+
+    Request = Command;
+    Result = WriteData32(Socket, Request);
+    if (!Result) {
+        return Result;
+    }
+    printf ("Platform Port Transmit Command: ");
+    Request = htonl(Request);
+    DumpData((uint8_t *)&Request, sizeof(uint32_t));
+
+    Result = WriteData32(Socket, mUseTransportLayer);
+    if (!Result) {
+        return Result;
+    }
+    printf("Platform Port Transmit TransportType: ");
+    TransportType = ntohl(mUseTransportLayer);
+    DumpData((uint8_t *)&TransportType, sizeof(uint32_t));
+
+    Result = WriteMultipleBytes(Socket, SendBuffer, BytesToSend);
+    if (!Result) {
+        return Result;
+    }
+
+    return true;
+}
+
+void spdm_sock_init(Error **errp)
+{
+    int result;
+    struct sockaddr_in ServerAddr;
+    uint16_t Port = 2323;
+
+    ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (ClientSocket == INVALID_SOCKET) {
+        error_setg(errp, "Openspdm: %s\n", strerror(errno));
+        return;
+    }
+
+    ServerAddr.sin_family = AF_INET;
+    memcpy(&ServerAddr.sin_addr.s_addr, &mIpAddress, sizeof(struct in_addr));
+    ServerAddr.sin_port = htons(Port);
+    memset(ServerAddr.sin_zero, 0, sizeof(ServerAddr.sin_zero));
+
+    result = connect(ClientSocket, (struct sockaddr *)&ServerAddr,
+                     sizeof(ServerAddr));
+    if (result == SOCKET_ERROR) {
+        error_setg(errp, "Openspdm: %s\n", strerror(errno));
+        closesocket(ClientSocket);
+        return;
+    }
+    printf("Openspdm: Connect success!\n");
+}
+
+bool pcie_doe_spdm_rsp(DOECap *doe_cap)
+{
+    void *req = pcie_doe_get_write_mbox_ptr(doe_cap);
+    uint32_t len = pcie_doe_get_obj_len(req);
+    uint32_t rsp_len = MAX_SPDM_MESSAGE_BUFFER_SIZE, Command;
+    bool result;
+
+    result = SendPlatformData(ClientSocket, SOCKET_SPDM_COMMAND_NORMAL,
+                              req, len * DWORD_BYTE);
+    if (!result) {
+        printf("SendPlatformData error\n");
+        return result;
+    }
+
+    result = ReceivePlatformData(ClientSocket, &Command,
+                                 (uint8_t *)doe_cap->read_mbox, &rsp_len);
+    if (!result) {
+        printf("ReceivePlatformData error\n");
+        return result;
+    }
+
+    assert(Command != 0);
+    doe_cap->read_mbox_len += DIV_ROUND_UP(rsp_len, DWORD_BYTE);
+
+    return true;
+}
+
+void spdm_sock_fini(void)
+{
+    bool result;
+
+    result = SendPlatformData(ClientSocket, SOCKET_SPDM_COMMAND_SHUTDOWN,
+                              NULL, 0);
+    if (!result) {
+        printf("SendPlatformData error\n");
+        return;
+    }
+    printf("Openspdm: Shutdown!\n");
+}
diff --git a/hw/pci/meson.build b/hw/pci/meson.build
index 115e502..e3be112 100644
--- a/hw/pci/meson.build
+++ b/hw/pci/meson.build
@@ -13,6 +13,7 @@ pci_ss.add(files(
 # CONFIG_PCI_EXPRESS=n.
 pci_ss.add(files('pcie.c', 'pcie_aer.c'))
 pci_ss.add(files('pcie_doe.c'))
+pci_ss.add(when: 'CONFIG_PCIE_SPDM', if_true: files('SpdmEmuCommand.c'))
 softmmu_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: files('pcie_port.c', 
'pcie_host.c'))
 softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss)
 
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index de006ff..a112620 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -240,6 +240,8 @@ typedef struct cxl_type3_dev {
     /* DOE */
     DOECap doe_comp;
     DOECap doe_cdat;
+    bool use_spdm;
+    DOECap doe_spdm;
 } CXLType3Dev;
 
 #ifndef TYPE_CXL_TYPE3_DEV
diff --git a/include/hw/pci/SpdmEmuCommand.h b/include/hw/pci/SpdmEmuCommand.h
new file mode 100644
index 0000000..39e7e9a
--- /dev/null
+++ b/include/hw/pci/SpdmEmuCommand.h
@@ -0,0 +1,21 @@
+#include "qemu/osdep.h"
+#include "hw/pci/pcie_doe.h"
+
+#define SOCKET_TRANSPORT_TYPE_MCTP     0x01
+#define SOCKET_TRANSPORT_TYPE_PCI_DOE  0x02
+
+#define SOCKET_SPDM_COMMAND_NORMAL                0x0001
+#define SOCKET_SPDM_COMMAND_OOB_ENCAP_KEY_UPDATE  0x8001
+#define SOCKET_SPDM_COMMAND_CONTINUE              0xFFFD
+#define SOCKET_SPDM_COMMAND_SHUTDOWN              0xFFFE
+#define SOCKET_SPDM_COMMAND_UNKOWN                0xFFFF
+#define SOCKET_SPDM_COMMAND_TEST                  0xDEAD
+
+#define INVALID_SOCKET (-1)
+#define SOCKET_ERROR (-1)
+
+#define MAX_SPDM_MESSAGE_BUFFER_SIZE      0x1200
+
+void spdm_sock_init(Error **errp);
+bool pcie_doe_spdm_rsp(DOECap *doe_cap);
+void spdm_sock_fini(void);
diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
index e551f49..af4be56 100644
--- a/include/hw/pci/pcie_doe.h
+++ b/include/hw/pci/pcie_doe.h
@@ -47,6 +47,8 @@ REG32(PCI_DOE_CAP_STATUS, 0)
 
 /* PCI-SIG defined Data Object Types - Table 7-x2 */
 #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
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]