mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2024-09-10 15:56:45 +03:00
virtio,pci,pc: features,fixes
pci: Initial support for SPDM Responders cxl: Add support for scan media, feature commands, device patrol scrub control, DDR5 ECS control, firmware updates virtio: in-order support virtio-net: support for SR-IOV emulation (note: known issues on s390, might get reverted if not fixed) smbios: memory device size is now configurable per Machine cpu: architecture agnostic code to support vCPU Hotplug Fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmae9l8PHG1zdEByZWRo YXQuY29tAAoJECgfDbjSjVRp8fYH/impBH9nViO/WK48io4mLSkl0EUL8Y/xrMvH zKFCKaXq8D96VTt1Z4EGKYgwG0voBKZaCEKYU/0ARGnSlSwxINQ8ROCnBWMfn2sx yQt08EXVMznNLtXjc6U5zCoCi6SaV85GH40No3MUFXBQt29ZSlFqO/fuHGZHYBwS wuVKvTjjNF4EsGt3rS4Qsv6BwZWMM+dE6yXpKWk68kR8IGp+6QGxkMbWt9uEX2Md VuemKVnFYw0XGCGy5K+ZkvoA2DGpEw0QxVSOMs8CI55Oc9SkTKz5fUSzXXGo1if+ M1CTjOPJu6pMym6gy6XpFa8/QioDA/jE2vBQvfJ64TwhJDV159s= =k8e9 -----END PGP SIGNATURE----- Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging virtio,pci,pc: features,fixes pci: Initial support for SPDM Responders cxl: Add support for scan media, feature commands, device patrol scrub control, DDR5 ECS control, firmware updates virtio: in-order support virtio-net: support for SR-IOV emulation (note: known issues on s390, might get reverted if not fixed) smbios: memory device size is now configurable per Machine cpu: architecture agnostic code to support vCPU Hotplug Fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmae9l8PHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRp8fYH/impBH9nViO/WK48io4mLSkl0EUL8Y/xrMvH # zKFCKaXq8D96VTt1Z4EGKYgwG0voBKZaCEKYU/0ARGnSlSwxINQ8ROCnBWMfn2sx # yQt08EXVMznNLtXjc6U5zCoCi6SaV85GH40No3MUFXBQt29ZSlFqO/fuHGZHYBwS # wuVKvTjjNF4EsGt3rS4Qsv6BwZWMM+dE6yXpKWk68kR8IGp+6QGxkMbWt9uEX2Md # VuemKVnFYw0XGCGy5K+ZkvoA2DGpEw0QxVSOMs8CI55Oc9SkTKz5fUSzXXGo1if+ # M1CTjOPJu6pMym6gy6XpFa8/QioDA/jE2vBQvfJ64TwhJDV159s= # =k8e9 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 23 Jul 2024 10:16:31 AM AEST # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [undefined] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [undefined] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (61 commits) hw/nvme: Add SPDM over DOE support backends: Initial support for SPDM socket support hw/pci: Add all Data Object Types defined in PCIe r6.0 tests/acpi: Add expected ACPI AML files for RISC-V tests/qtest/bios-tables-test.c: Enable basic testing for RISC-V tests/acpi: Add empty ACPI data files for RISC-V tests/qtest/bios-tables-test.c: Remove the fall back path tests/acpi: update expected DSDT blob for aarch64 and microvm acpi/gpex: Create PCI link devices outside PCI root bridge tests/acpi: Allow DSDT acpi table changes for aarch64 hw/riscv/virt-acpi-build.c: Update the HID of RISC-V UART hw/riscv/virt-acpi-build.c: Add namespace devices for PLIC and APLIC virtio-iommu: Add trace point on virtio_iommu_detach_endpoint_from_domain hw/vfio/common: Add vfio_listener_region_del_iommu trace event virtio-iommu: Remove the end point on detach virtio-iommu: Free [host_]resv_ranges on unset_iommu_devices virtio-iommu: Remove probe_done Revert "virtio-iommu: Clear IOMMUDevice when VFIO device is unplugged" gdbstub: Add helper function to unregister GDB register space physmem: Add helper function to destroy CPU AddressSpace ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
5885bcef3d
|
@ -2009,6 +2009,7 @@ F: hw/pci-bridge/*
|
|||
F: qapi/pci.json
|
||||
F: docs/pci*
|
||||
F: docs/specs/*pci*
|
||||
F: docs/system/sriov.rst
|
||||
|
||||
PCIE DOE
|
||||
M: Huai-Cheng Kuo <hchkuo@avery-design.com.tw>
|
||||
|
@ -2208,6 +2209,7 @@ F: docs/devel/vfio-iommufd.rst
|
|||
|
||||
vhost
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
R: Stefano Garzarella <sgarzare@redhat.com>
|
||||
S: Supported
|
||||
F: hw/*/*vhost*
|
||||
F: docs/interop/vhost-user.json
|
||||
|
@ -3398,6 +3400,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
|
||||
|
@ -3657,6 +3665,7 @@ F: tests/uefi-test-tools/
|
|||
VT-d Emulation
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
R: Jason Wang <jasowang@redhat.com>
|
||||
R: Yi Liu <yi.l.liu@intel.com>
|
||||
S: Supported
|
||||
F: hw/i386/intel_iommu.c
|
||||
F: hw/i386/intel_iommu_internal.h
|
||||
|
|
|
@ -340,14 +340,71 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void kvm_park_vcpu(CPUState *cpu)
|
||||
{
|
||||
struct KVMParkedVcpu *vcpu;
|
||||
|
||||
trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||
|
||||
vcpu = g_malloc0(sizeof(*vcpu));
|
||||
vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
|
||||
vcpu->kvm_fd = cpu->kvm_fd;
|
||||
QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
|
||||
}
|
||||
|
||||
int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
|
||||
{
|
||||
struct KVMParkedVcpu *cpu;
|
||||
int kvm_fd = -ENOENT;
|
||||
|
||||
QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
|
||||
if (cpu->vcpu_id == vcpu_id) {
|
||||
QLIST_REMOVE(cpu, node);
|
||||
kvm_fd = cpu->kvm_fd;
|
||||
g_free(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
trace_kvm_unpark_vcpu(vcpu_id, kvm_fd > 0 ? "unparked" : "!found parked");
|
||||
|
||||
return kvm_fd;
|
||||
}
|
||||
|
||||
int kvm_create_vcpu(CPUState *cpu)
|
||||
{
|
||||
unsigned long vcpu_id = kvm_arch_vcpu_id(cpu);
|
||||
KVMState *s = kvm_state;
|
||||
int kvm_fd;
|
||||
|
||||
/* check if the KVM vCPU already exist but is parked */
|
||||
kvm_fd = kvm_unpark_vcpu(s, vcpu_id);
|
||||
if (kvm_fd < 0) {
|
||||
/* vCPU not parked: create a new KVM vCPU */
|
||||
kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id);
|
||||
if (kvm_fd < 0) {
|
||||
error_report("KVM_CREATE_VCPU IOCTL failed for vCPU %lu", vcpu_id);
|
||||
return kvm_fd;
|
||||
}
|
||||
}
|
||||
|
||||
cpu->kvm_fd = kvm_fd;
|
||||
cpu->kvm_state = s;
|
||||
cpu->vcpu_dirty = true;
|
||||
cpu->dirty_pages = 0;
|
||||
cpu->throttle_us_per_full = 0;
|
||||
|
||||
trace_kvm_create_vcpu(cpu->cpu_index, vcpu_id, kvm_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_kvm_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
long mmap_size;
|
||||
struct KVMParkedVcpu *vcpu = NULL;
|
||||
int ret = 0;
|
||||
|
||||
trace_kvm_destroy_vcpu();
|
||||
trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||
|
||||
ret = kvm_arch_destroy_vcpu(cpu);
|
||||
if (ret < 0) {
|
||||
|
@ -373,10 +430,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
vcpu = g_malloc0(sizeof(*vcpu));
|
||||
vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
|
||||
vcpu->kvm_fd = cpu->kvm_fd;
|
||||
QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
|
||||
kvm_park_vcpu(cpu);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
@ -389,24 +443,6 @@ void kvm_destroy_vcpu(CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
|
||||
{
|
||||
struct KVMParkedVcpu *cpu;
|
||||
|
||||
QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
|
||||
if (cpu->vcpu_id == vcpu_id) {
|
||||
int kvm_fd;
|
||||
|
||||
QLIST_REMOVE(cpu, node);
|
||||
kvm_fd = cpu->kvm_fd;
|
||||
g_free(cpu);
|
||||
return kvm_fd;
|
||||
}
|
||||
}
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
|
||||
}
|
||||
|
||||
int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
|
@ -415,19 +451,14 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
|||
|
||||
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||
|
||||
ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
|
||||
ret = kvm_create_vcpu(cpu);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)",
|
||||
error_setg_errno(errp, -ret,
|
||||
"kvm_init_vcpu: kvm_create_vcpu failed (%lu)",
|
||||
kvm_arch_vcpu_id(cpu));
|
||||
goto err;
|
||||
}
|
||||
|
||||
cpu->kvm_fd = ret;
|
||||
cpu->kvm_state = s;
|
||||
cpu->vcpu_dirty = true;
|
||||
cpu->dirty_pages = 0;
|
||||
cpu->throttle_us_per_full = 0;
|
||||
|
||||
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
|
||||
if (mmap_size < 0) {
|
||||
ret = mmap_size;
|
||||
|
|
|
@ -22,5 +22,4 @@ bool kvm_supports_guest_debug(void);
|
|||
int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len);
|
||||
int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len);
|
||||
void kvm_remove_all_breakpoints(CPUState *cpu);
|
||||
|
||||
#endif /* KVM_CPUS_H */
|
||||
|
|
|
@ -9,6 +9,10 @@ kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p"
|
|||
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
|
||||
kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s"
|
||||
kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
|
||||
kvm_create_vcpu(int cpu_index, unsigned long arch_cpu_id, int kvm_fd) "index: %d, id: %lu, kvm fd: %d"
|
||||
kvm_destroy_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
|
||||
kvm_park_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
|
||||
kvm_unpark_vcpu(unsigned long arch_cpu_id, const char *msg) "id: %lu %s"
|
||||
kvm_irqchip_commit_routes(void) ""
|
||||
kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d"
|
||||
kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
|
||||
|
@ -25,7 +29,6 @@ kvm_dirty_ring_reaper(const char *s) "%s"
|
|||
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
|
||||
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
|
||||
kvm_dirty_ring_flush(int finished) "%d"
|
||||
kvm_destroy_vcpu(void) ""
|
||||
kvm_failed_get_vcpu_mmap_size(void) ""
|
||||
kvm_cpu_exec(void) ""
|
||||
kvm_interrupt_exit_request(void) ""
|
||||
|
|
|
@ -3,3 +3,7 @@ source tpm/Kconfig
|
|||
config IOMMUFD
|
||||
bool
|
||||
depends on VFIO
|
||||
|
||||
config SPDM_SOCKET
|
||||
bool
|
||||
default y
|
||||
|
|
|
@ -33,4 +33,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')
|
||||
|
|
216
backends/spdm-socket.c
Normal file
216
backends/spdm-socket.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -196,7 +196,7 @@ vub_discard_write_zeroes(VubReq *req, struct iovec *iov, uint32_t iovcnt,
|
|||
VubDev *vdev_blk = req->vdev_blk;
|
||||
desc = buf;
|
||||
uint64_t range[2] = { le64_to_cpu(desc->sector) << 9,
|
||||
le32_to_cpu(desc->num_sectors) << 9 };
|
||||
(uint64_t)le32_to_cpu(desc->num_sectors) << 9 };
|
||||
if (type == VIRTIO_BLK_T_DISCARD) {
|
||||
if (ioctl(vdev_blk->blk_fd, BLKDISCARD, range) == 0) {
|
||||
g_free(buf);
|
||||
|
|
|
@ -64,7 +64,8 @@ GED IO interface (4 byte access)
|
|||
0: Memory hotplug event
|
||||
1: System power down event
|
||||
2: NVDIMM hotplug event
|
||||
3-31: Reserved
|
||||
3: CPU hotplug event
|
||||
4-31: Reserved
|
||||
|
||||
**write_access:**
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ guest hardware that is specific to QEMU.
|
|||
edu
|
||||
ivshmem-spec
|
||||
pvpanic
|
||||
spdm
|
||||
standard-vga
|
||||
virt-ctlr
|
||||
vmcoreinfo
|
||||
|
|
134
docs/specs/spdm.rst
Normal file
134
docs/specs/spdm.rst
Normal file
|
@ -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
|
|
@ -39,3 +39,4 @@ or Hypervisor.Framework.
|
|||
multi-process
|
||||
confidential-guest-support
|
||||
vm-templating
|
||||
sriov
|
||||
|
|
36
docs/system/sriov.rst
Normal file
36
docs/system/sriov.rst
Normal file
|
@ -0,0 +1,36 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Compsable SR-IOV device
|
||||
=======================
|
||||
|
||||
SR-IOV (Single Root I/O Virtualization) is an optional extended capability of a
|
||||
PCI Express device. It allows a single physical function (PF) to appear as
|
||||
multiple virtual functions (VFs) for the main purpose of eliminating software
|
||||
overhead in I/O from virtual machines.
|
||||
|
||||
There are devices with predefined SR-IOV configurations, but it is also possible
|
||||
to compose an SR-IOV device yourself. Composing an SR-IOV device is currently
|
||||
only supported by virtio-net-pci.
|
||||
|
||||
Users can configure an SR-IOV-capable virtio-net device by adding
|
||||
virtio-net-pci functions to a bus. Below is a command line example:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
-netdev user,id=n -netdev user,id=o
|
||||
-netdev user,id=p -netdev user,id=q
|
||||
-device pcie-root-port,id=b
|
||||
-device virtio-net-pci,bus=b,addr=0x0.0x3,netdev=q,sriov-pf=f
|
||||
-device virtio-net-pci,bus=b,addr=0x0.0x2,netdev=p,sriov-pf=f
|
||||
-device virtio-net-pci,bus=b,addr=0x0.0x1,netdev=o,sriov-pf=f
|
||||
-device virtio-net-pci,bus=b,addr=0x0.0x0,netdev=n,id=f
|
||||
|
||||
The VFs specify the paired PF with ``sriov-pf`` property. The PF must be
|
||||
added after all VFs. It is the user's responsibility to ensure that VFs have
|
||||
function numbers larger than one of the PF, and that the function numbers
|
||||
have a consistent stride.
|
||||
|
||||
You may also need to perform additional steps to activate the SR-IOV feature on
|
||||
your guest. For Linux, refer to [1]_.
|
||||
|
||||
.. [1] https://docs.kernel.org/PCI/pci-iov-howto.html
|
|
@ -618,6 +618,19 @@ void gdb_register_coprocessor(CPUState *cpu,
|
|||
}
|
||||
}
|
||||
|
||||
void gdb_unregister_coprocessor_all(CPUState *cpu)
|
||||
{
|
||||
/*
|
||||
* Safe to nuke everything. GDBRegisterState::xml is static const char so
|
||||
* it won't be freed
|
||||
*/
|
||||
g_array_free(cpu->gdb_regs, true);
|
||||
|
||||
cpu->gdb_regs = NULL;
|
||||
cpu->gdb_num_regs = 0;
|
||||
cpu->gdb_num_g_regs = 0;
|
||||
}
|
||||
|
||||
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
|
||||
{
|
||||
CPUState *cpu = gdb_get_first_cpu_in_process(p);
|
||||
|
|
|
@ -19,6 +19,12 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
|||
return;
|
||||
}
|
||||
|
||||
void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
|
||||
CPUHotplugState *state, hwaddr base_addr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
|
||||
{
|
||||
return;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "trace.h"
|
||||
#include "sysemu/numa.h"
|
||||
|
||||
#define ACPI_CPU_HOTPLUG_REG_LEN 12
|
||||
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
|
||||
#define ACPI_CPU_FLAGS_OFFSET_RW 4
|
||||
#define ACPI_CPU_CMD_OFFSET_WR 5
|
||||
|
@ -339,9 +338,10 @@ const VMStateDescription vmstate_cpu_hotplug = {
|
|||
#define CPU_FW_EJECT_EVENT "CEJF"
|
||||
|
||||
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
build_madt_cpu_fn build_madt_cpu, hwaddr io_base,
|
||||
build_madt_cpu_fn build_madt_cpu, hwaddr base_addr,
|
||||
const char *res_root,
|
||||
const char *event_handler_method)
|
||||
const char *event_handler_method,
|
||||
AmlRegionSpace rs)
|
||||
{
|
||||
Aml *ifctx;
|
||||
Aml *field;
|
||||
|
@ -365,14 +365,22 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
|||
aml_name_decl("_UID", aml_string("CPU Hotplug resources")));
|
||||
aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
|
||||
|
||||
assert((rs == AML_SYSTEM_IO) || (rs == AML_SYSTEM_MEMORY));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
|
||||
if (rs == AML_SYSTEM_IO) {
|
||||
aml_append(crs, aml_io(AML_DECODE16, base_addr, base_addr, 1,
|
||||
ACPI_CPU_HOTPLUG_REG_LEN));
|
||||
} else if (rs == AML_SYSTEM_MEMORY) {
|
||||
aml_append(crs, aml_memory32_fixed(base_addr,
|
||||
ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE));
|
||||
}
|
||||
|
||||
aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
/* declare CPU hotplug MMIO region with related access fields */
|
||||
aml_append(cpu_ctrl_dev,
|
||||
aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base),
|
||||
aml_operation_region("PRST", rs, aml_int(base_addr),
|
||||
ACPI_CPU_HOTPLUG_REG_LEN));
|
||||
|
||||
field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,
|
||||
|
|
|
@ -25,6 +25,7 @@ static const uint32_t ged_supported_events[] = {
|
|||
ACPI_GED_MEM_HOTPLUG_EVT,
|
||||
ACPI_GED_PWR_DOWN_EVT,
|
||||
ACPI_GED_NVDIMM_HOTPLUG_EVT,
|
||||
ACPI_GED_CPU_HOTPLUG_EVT,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -107,6 +108,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
|
|||
aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
|
||||
MEMORY_SLOT_SCAN_METHOD));
|
||||
break;
|
||||
case ACPI_GED_CPU_HOTPLUG_EVT:
|
||||
aml_append(if_ctx, aml_call0(AML_GED_EVT_CPU_SCAN_METHOD));
|
||||
break;
|
||||
case ACPI_GED_PWR_DOWN_EVT:
|
||||
aml_append(if_ctx,
|
||||
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
|
||||
|
@ -234,6 +238,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
|
|||
} else {
|
||||
acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
|
||||
}
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "virt: device plug request for unsupported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
|
@ -248,6 +254,8 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||
if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
|
||||
!(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) {
|
||||
acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug request for unsupported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
|
@ -261,6 +269,8 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
|
|||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
acpi_memory_unplug_cb(&s->memhp_state, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug for unsupported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
|
@ -272,6 +282,7 @@ static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
|
|||
AcpiGedState *s = ACPI_GED(adev);
|
||||
|
||||
acpi_memory_ospm_status(&s->memhp_state, list);
|
||||
acpi_cpu_ospm_status(&s->cpuhp_state, list);
|
||||
}
|
||||
|
||||
static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
|
||||
|
@ -286,6 +297,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
|
|||
sel = ACPI_GED_PWR_DOWN_EVT;
|
||||
} else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) {
|
||||
sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
|
||||
} else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
|
||||
sel = ACPI_GED_CPU_HOTPLUG_EVT;
|
||||
} else {
|
||||
/* Unknown event. Return without generating interrupt. */
|
||||
warn_report("GED: Unsupported event %d. No irq injected", ev);
|
||||
|
@ -371,6 +384,42 @@ static const VMStateDescription vmstate_acpi_ged = {
|
|||
}
|
||||
};
|
||||
|
||||
static void acpi_ged_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AcpiGedState *s = ACPI_GED(dev);
|
||||
uint32_t ged_events;
|
||||
int i;
|
||||
|
||||
ged_events = ctpop32(s->ged_event_bitmap);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
|
||||
uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
|
||||
|
||||
if (!event) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case ACPI_GED_CPU_HOTPLUG_EVT:
|
||||
/* initialize CPU Hotplug related regions */
|
||||
memory_region_init(&s->container_cpuhp, OBJECT(dev),
|
||||
"cpuhp container",
|
||||
ACPI_CPU_HOTPLUG_REG_LEN);
|
||||
sysbus_init_mmio(sbd, &s->container_cpuhp);
|
||||
cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
|
||||
&s->cpuhp_state, 0);
|
||||
break;
|
||||
}
|
||||
ged_events--;
|
||||
}
|
||||
|
||||
if (ged_events) {
|
||||
error_report("Unsupported events specified");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_ged_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
@ -411,6 +460,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
|
|||
dc->desc = "ACPI Generic Event Device";
|
||||
device_class_set_props(dc, acpi_ged_properties);
|
||||
dc->vmsd = &vmstate_acpi_ged;
|
||||
dc->realize = acpi_ged_realize;
|
||||
|
||||
hc->plug = acpi_ged_device_plug_cb;
|
||||
hc->unplug_request = acpi_ged_unplug_request_cb;
|
||||
|
|
|
@ -3308,6 +3308,7 @@ DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
|
|||
static void virt_machine_9_0_options(MachineClass *mc)
|
||||
{
|
||||
virt_machine_9_1_options(mc);
|
||||
mc->smbios_memory_device_size = 16 * GiB;
|
||||
compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
|
||||
}
|
||||
DEFINE_VIRT_MACHINE(9, 0)
|
||||
|
|
|
@ -282,11 +282,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
|
|||
error_report("Number of channels is not supported.");
|
||||
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
|
||||
}
|
||||
if (!(supported_formats & BIT(params->format))) {
|
||||
if (BIT(params->format) > sizeof(supported_formats) ||
|
||||
!(supported_formats & BIT(params->format))) {
|
||||
error_report("Stream format is not supported.");
|
||||
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
|
||||
}
|
||||
if (!(supported_rates & BIT(params->rate))) {
|
||||
if (BIT(params->rate) > sizeof(supported_rates) ||
|
||||
!(supported_rates & BIT(params->rate))) {
|
||||
error_report("Stream rate is not supported.");
|
||||
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
|
||||
}
|
||||
|
@ -1261,7 +1263,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
|
|||
{
|
||||
VirtIOSoundPCMStream *stream = data;
|
||||
VirtIOSoundPCMBuffer *buffer;
|
||||
size_t size;
|
||||
size_t size, max_size;
|
||||
|
||||
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
|
||||
while (!QSIMPLEQ_EMPTY(&stream->queue)) {
|
||||
|
@ -1275,7 +1277,12 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
|
|||
continue;
|
||||
}
|
||||
|
||||
max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
|
||||
for (;;) {
|
||||
if (buffer->size >= max_size) {
|
||||
return_rx_buffer(stream, buffer);
|
||||
break;
|
||||
}
|
||||
size = AUD_read(stream->voice.in,
|
||||
buffer->data + buffer->size,
|
||||
MIN(available, (stream->params.period_bytes -
|
||||
|
|
|
@ -51,6 +51,7 @@ static const int user_feature_bits[] = {
|
|||
VIRTIO_F_RING_PACKED,
|
||||
VIRTIO_F_IOMMU_PLATFORM,
|
||||
VIRTIO_F_RING_RESET,
|
||||
VIRTIO_F_IN_ORDER,
|
||||
VIRTIO_F_NOTIFICATION_DATA,
|
||||
VHOST_INVALID_FEATURE_BIT
|
||||
};
|
||||
|
|
|
@ -282,7 +282,10 @@ static void cpu_common_finalize(Object *obj)
|
|||
}
|
||||
#endif
|
||||
free_queued_cpu_work(cpu);
|
||||
g_array_free(cpu->gdb_regs, TRUE);
|
||||
/* If cleanup didn't happen in context to gdb_unregister_coprocessor_all */
|
||||
if (cpu->gdb_regs) {
|
||||
g_array_free(cpu->gdb_regs, TRUE);
|
||||
}
|
||||
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
|
||||
qemu_mutex_destroy(&cpu->work_mutex);
|
||||
qemu_cond_destroy(cpu->halt_cond);
|
||||
|
|
|
@ -1005,6 +1005,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
|||
/* Default 128 MB as guest ram size */
|
||||
mc->default_ram_size = 128 * MiB;
|
||||
mc->rom_file_has_mr = true;
|
||||
/*
|
||||
* SMBIOS 3.1.0 7.18.5 Memory Device — Extended Size
|
||||
* use max possible value that could be encoded into
|
||||
* 'Extended Size' field (2047Tb).
|
||||
*/
|
||||
mc->smbios_memory_device_size = 2047 * TiB;
|
||||
|
||||
/* numa node memory size aligned on 8MB by default.
|
||||
* On Linux, each node's border has to be 8MB aligned
|
||||
|
|
|
@ -139,6 +139,19 @@ bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type,
|
|||
return cxl_event_count(log) == 1;
|
||||
}
|
||||
|
||||
void cxl_discard_all_event_records(CXLDeviceState *cxlds)
|
||||
{
|
||||
CXLEventLogType log_type;
|
||||
CXLEventLog *log;
|
||||
|
||||
for (log_type = 0; log_type < CXL_EVENT_TYPE_MAX; log_type++) {
|
||||
log = &cxlds->event_logs[log_type];
|
||||
while (!cxl_event_empty(log)) {
|
||||
cxl_event_delete_head(cxlds, log_type, log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl,
|
||||
uint8_t log_type, int max_recs,
|
||||
size_t *len)
|
||||
|
|
|
@ -315,7 +315,8 @@ static void machine_set_cxl(Object *obj, Visitor *v, const char *name,
|
|||
static void machine_get_cfmw(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
CXLFixedMemoryWindowOptionsList **list = opaque;
|
||||
CXLState *state = opaque;
|
||||
CXLFixedMemoryWindowOptionsList **list = &state->cfmw_list;
|
||||
|
||||
visit_type_CXLFixedMemoryWindowOptionsList(v, name, list, errp);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1536,7 +1536,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
.fw_unplugs_cpu = pm->smi_on_cpu_unplug,
|
||||
};
|
||||
build_cpus_aml(dsdt, machine, opts, pc_madt_cpu_entry,
|
||||
pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02");
|
||||
pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02",
|
||||
AML_SYSTEM_IO);
|
||||
}
|
||||
|
||||
if (pcms->memhp_io_base && nr_mem) {
|
||||
|
|
|
@ -358,7 +358,7 @@ static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
|||
{
|
||||
struct vtd_iotlb_key key;
|
||||
VTDIOTLBEntry *entry;
|
||||
int level;
|
||||
unsigned level;
|
||||
|
||||
for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
|
||||
key.gfn = vtd_get_iotlb_gfn(addr, level);
|
||||
|
|
|
@ -264,10 +264,10 @@
|
|||
#define VTD_FRCD_FR(val) (((val) & 0xffULL) << 32)
|
||||
#define VTD_FRCD_SID_MASK 0xffffULL
|
||||
#define VTD_FRCD_SID(val) ((val) & VTD_FRCD_SID_MASK)
|
||||
#define VTD_FRCD_PV(val) (((val) & 0xffffULL) << 40)
|
||||
#define VTD_FRCD_PP(val) (((val) & 0x1ULL) << 31)
|
||||
/* For the low 64-bit of 128-bit */
|
||||
#define VTD_FRCD_FI(val) ((val) & ~0xfffULL)
|
||||
#define VTD_FRCD_PV(val) (((val) & 0xffffULL) << 40)
|
||||
#define VTD_FRCD_PP(val) (((val) & 0x1) << 31)
|
||||
#define VTD_FRCD_IR_IDX(val) (((val) & 0xffffULL) << 48)
|
||||
|
||||
/* DMA Remapping Fault Conditions */
|
||||
|
@ -436,7 +436,7 @@ struct VTDIOTLBPageInvInfo {
|
|||
uint16_t domain_id;
|
||||
uint32_t pasid;
|
||||
uint64_t addr;
|
||||
uint8_t mask;
|
||||
uint64_t mask;
|
||||
};
|
||||
typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
|
||||
|
||||
|
|
|
@ -495,6 +495,7 @@ static void pc_i440fx_machine_9_0_options(MachineClass *m)
|
|||
pc_i440fx_machine_9_1_options(m);
|
||||
m->alias = NULL;
|
||||
m->is_default = false;
|
||||
m->smbios_memory_device_size = 16 * GiB;
|
||||
|
||||
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
|
||||
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
|
||||
|
|
|
@ -374,6 +374,7 @@ static void pc_q35_machine_9_0_options(MachineClass *m)
|
|||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_machine_9_1_options(m);
|
||||
m->alias = NULL;
|
||||
m->smbios_memory_device_size = 16 * GiB;
|
||||
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
|
||||
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
|
||||
pcmc->isa_bios_alias = false;
|
||||
|
|
|
@ -737,6 +737,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
|
|||
error_setg(errp, "volatile memdev must have backing device");
|
||||
return false;
|
||||
}
|
||||
if (host_memory_backend_is_mapped(ct3d->hostvmem)) {
|
||||
error_setg(errp, "memory backend %s can't be used multiple times.",
|
||||
object_get_canonical_path_component(OBJECT(ct3d->hostvmem)));
|
||||
return false;
|
||||
}
|
||||
memory_region_set_nonvolatile(vmr, false);
|
||||
memory_region_set_enabled(vmr, true);
|
||||
host_memory_backend_set_mapped(ct3d->hostvmem, true);
|
||||
|
@ -760,6 +765,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
|
|||
error_setg(errp, "persistent memdev must have backing device");
|
||||
return false;
|
||||
}
|
||||
if (host_memory_backend_is_mapped(ct3d->hostpmem)) {
|
||||
error_setg(errp, "memory backend %s can't be used multiple times.",
|
||||
object_get_canonical_path_component(OBJECT(ct3d->hostpmem)));
|
||||
return false;
|
||||
}
|
||||
memory_region_set_nonvolatile(pmr, true);
|
||||
memory_region_set_enabled(pmr, true);
|
||||
host_memory_backend_set_mapped(ct3d->hostpmem, true);
|
||||
|
@ -790,6 +800,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (host_memory_backend_is_mapped(ct3d->dc.host_dc)) {
|
||||
error_setg(errp, "memory backend %s can't be used multiple times.",
|
||||
object_get_canonical_path_component(OBJECT(ct3d->dc.host_dc)));
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Set DC regions as volatile for now, non-volatile support can
|
||||
* be added in the future if needed.
|
||||
|
@ -829,6 +844,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
|
|||
uint8_t *pci_conf = pci_dev->config;
|
||||
unsigned short msix_num = 6;
|
||||
int i, rc;
|
||||
uint16_t count;
|
||||
|
||||
QTAILQ_INIT(&ct3d->error_list);
|
||||
|
||||
|
@ -893,6 +909,28 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
|
|||
}
|
||||
cxl_event_init(&ct3d->cxl_dstate, 2);
|
||||
|
||||
/* Set default value for patrol scrub attributes */
|
||||
ct3d->patrol_scrub_attrs.scrub_cycle_cap =
|
||||
CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_DEFAULT |
|
||||
CXL_MEMDEV_PS_SCRUB_REALTIME_REPORT_CAP_DEFAULT;
|
||||
ct3d->patrol_scrub_attrs.scrub_cycle =
|
||||
CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_DEFAULT |
|
||||
(CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_DEFAULT << 8);
|
||||
ct3d->patrol_scrub_attrs.scrub_flags = CXL_MEMDEV_PS_ENABLE_DEFAULT;
|
||||
|
||||
/* Set default value for DDR5 ECS read attributes */
|
||||
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
|
||||
ct3d->ecs_attrs[count].ecs_log_cap =
|
||||
CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
|
||||
ct3d->ecs_attrs[count].ecs_cap =
|
||||
CXL_ECS_REALTIME_REPORT_CAP_DEFAULT;
|
||||
ct3d->ecs_attrs[count].ecs_config =
|
||||
CXL_ECS_THRESHOLD_COUNT_DEFAULT |
|
||||
(CXL_ECS_MODE_DEFAULT << 3);
|
||||
/* Reserved */
|
||||
ct3d->ecs_attrs[count].ecs_flags = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_release_cdat:
|
||||
|
@ -1127,7 +1165,7 @@ MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
|
|||
return MEMTX_ERROR;
|
||||
}
|
||||
|
||||
if (sanitize_running(&ct3d->cci)) {
|
||||
if (cxl_dev_media_disabled(&ct3d->cxl_dstate)) {
|
||||
qemu_guest_getrandom_nofail(data, size);
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
@ -1149,7 +1187,7 @@ MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
|
|||
return MEMTX_ERROR;
|
||||
}
|
||||
|
||||
if (sanitize_running(&ct3d->cci)) {
|
||||
if (cxl_dev_media_disabled(&ct3d->cxl_dstate)) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
|
@ -1304,6 +1342,12 @@ void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d)
|
|||
cxl_device_get_timestamp(&ct3d->cxl_dstate);
|
||||
}
|
||||
|
||||
void cxl_clear_poison_list_overflowed(CXLType3Dev *ct3d)
|
||||
{
|
||||
ct3d->poison_list_overflowed = false;
|
||||
ct3d->poison_list_overflow_ts = 0;
|
||||
}
|
||||
|
||||
void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -1340,19 +1384,21 @@ void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
|
|||
}
|
||||
}
|
||||
|
||||
if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) {
|
||||
cxl_set_poison_list_overflowed(ct3d);
|
||||
return;
|
||||
}
|
||||
|
||||
p = g_new0(CXLPoison, 1);
|
||||
p->length = length;
|
||||
p->start = start;
|
||||
/* Different from injected via the mbox */
|
||||
p->type = CXL_POISON_TYPE_INTERNAL;
|
||||
|
||||
QLIST_INSERT_HEAD(&ct3d->poison_list, p, node);
|
||||
ct3d->poison_list_cnt++;
|
||||
if (ct3d->poison_list_cnt < CXL_POISON_LIST_LIMIT) {
|
||||
QLIST_INSERT_HEAD(&ct3d->poison_list, p, node);
|
||||
ct3d->poison_list_cnt++;
|
||||
} else {
|
||||
if (!ct3d->poison_list_overflowed) {
|
||||
cxl_set_poison_list_overflowed(ct3d);
|
||||
}
|
||||
QLIST_INSERT_HEAD(&ct3d->poison_list_bkp, p, node);
|
||||
}
|
||||
}
|
||||
|
||||
/* For uncorrectable errors include support for multiple header recording */
|
||||
|
|
|
@ -48,6 +48,7 @@ static const int kernel_feature_bits[] = {
|
|||
VIRTIO_F_IOMMU_PLATFORM,
|
||||
VIRTIO_F_RING_PACKED,
|
||||
VIRTIO_F_RING_RESET,
|
||||
VIRTIO_F_IN_ORDER,
|
||||
VIRTIO_F_NOTIFICATION_DATA,
|
||||
VIRTIO_NET_F_HASH_REPORT,
|
||||
VHOST_INVALID_FEATURE_BIT
|
||||
|
@ -78,6 +79,7 @@ static const int user_feature_bits[] = {
|
|||
VIRTIO_F_IOMMU_PLATFORM,
|
||||
VIRTIO_F_RING_PACKED,
|
||||
VIRTIO_F_RING_RESET,
|
||||
VIRTIO_F_IN_ORDER,
|
||||
VIRTIO_NET_F_RSS,
|
||||
VIRTIO_NET_F_HASH_REPORT,
|
||||
VIRTIO_NET_F_GUEST_USO4,
|
||||
|
|
|
@ -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"
|
||||
|
@ -8315,6 +8316,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();
|
||||
|
@ -8402,6 +8424,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);
|
||||
}
|
||||
|
@ -8650,6 +8691,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);
|
||||
}
|
||||
|
@ -8695,6 +8741,7 @@ static Property nvme_props[] = {
|
|||
DEFINE_PROP_BOOL("msix-exclusive-bar", NvmeCtrl, params.msix_exclusive_bar,
|
||||
false),
|
||||
DEFINE_PROP_UINT16("mqes", NvmeCtrl, params |