mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* rust: miscellaneous fixes * rust: qemu-api-macros: cleanup and add unit tests for TryInto * rust: log: implement io::Write, avoid memory allocations when logging constant strings * target/i386: fix usage of properties whenever accelerators change the default (e.g. vendor) * target/i386: add support for TDVMCALL_SETUP_EVENT_NOTIFY_INTERRUPT * target/i386: add support for booting an SEV VM from an IGVM file * target/i386: unify cache model descriptions between CPUID 2, CPUID 4 and AMD specific CPUID 0x80000006 * target/i386: introduce cache models for recent Intel CPU models * target/i386: mark some 0x80000000-0x80000008 bits as reserved on Intel * target/i386: cleanups # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmh0v+sUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOQUQf8CTsCnl2xYrnrkVfSVj6kuAE+JYD6 # oLSXsOEG4yrVknuhwIfVsqNScmleJCdz85ej7CZxy3vzzgjLfmy7nwifKEIKku7E # XO/Q3HbB898MnzqceQRmwe1AzELoj1Lave215CPhUBo60LCRPwaIZsiHprnNZgXi # TyHlmywDVRjyFLtKkx3El0dnLAhFqPWeGh81CD5lPLZZJ+Wt2FuAw2zqSOGB2ztM # FkJmunFJiaTItjyCN/uNvBSbDKecAHgCXvSCVNG3+I4U2R0gK1lcwm3TRo7yKia+ # HUHGa3UEXoIqlRfXdX6zuc8tW1/u6SPv+8WX53t204PAeSWDUrtIe9jZ4A== # =y4/a # -----END PGP SIGNATURE----- # gpg: Signature made Mon 14 Jul 2025 04:29:31 EDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (77 commits) i386/cpu: Honor maximum value for CPUID.8000001DH.EAX[25:14] i386/cpu: Fix overflow of cache topology fields in CPUID.04H i386/cpu: Fix cpu number overflow in CPUID.01H.EBX[23:16] i386/cpu: Fix number of addressable IDs field for CPUID.01H.EBX[23:16] i386/cpu: Reorder CPUID leaves in cpu_x86_cpuid() tests/vm: bump FreeBSD image to 14.3 tests/functional: test_x86_cpu_model_versions: remove dead tests i386/cpu: Mark CPUID 0x80000008 ECX bits[0:7] & [12:15] as reserved for Intel/Zhaoxin i386/cpu: Mark CPUID 0x80000007[EBX] as reserved for Intel i386/cpu: Mark EBX/ECX/EDX in CPUID 0x80000000 leaf as reserved for Intel i386/cpu: Enable 0x1f leaf for YongFeng by default i386/cpu: Enable 0x1f leaf for SapphireRapids by default i386/cpu: Enable 0x1f leaf for GraniteRapids by default i386/cpu: Enable 0x1f leaf for SierraForest by default i386/cpu: Enable 0x1f leaf for SierraForest by default i386/cpu: Add a "x-force-cpuid-0x1f" property i386/cpu: Introduce cache model for YongFeng i386/cpu: Introduce cache model for SapphireRapids i386/cpu: Introduce cache model for GraniteRapids i386/cpu: Introduce cache model for SierraForest ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
@@ -14,15 +14,58 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "system/confidential-guest-support.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
OBJECT_DEFINE_ABSTRACT_TYPE(ConfidentialGuestSupport,
|
||||
confidential_guest_support,
|
||||
CONFIDENTIAL_GUEST_SUPPORT,
|
||||
OBJECT)
|
||||
|
||||
static bool check_support(ConfidentialGuestPlatformType platform,
|
||||
uint16_t platform_version, uint8_t highest_vtl,
|
||||
uint64_t shared_gpa_boundary)
|
||||
{
|
||||
/* Default: no support. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static int set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len,
|
||||
ConfidentialGuestPageType memory_type,
|
||||
uint16_t cpu_index, Error **errp)
|
||||
{
|
||||
error_setg(errp,
|
||||
"Setting confidential guest state is not supported for this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int set_guest_policy(ConfidentialGuestPolicyType policy_type,
|
||||
uint64_t policy,
|
||||
void *policy_data1, uint32_t policy_data1_size,
|
||||
void *policy_data2, uint32_t policy_data2_size,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp,
|
||||
"Setting confidential guest policy is not supported for this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_mem_map_entry(int index, ConfidentialGuestMemoryMapEntry *entry,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(
|
||||
errp,
|
||||
"Obtaining the confidential guest memory map is not supported for this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void confidential_guest_support_class_init(ObjectClass *oc,
|
||||
const void *data)
|
||||
{
|
||||
ConfidentialGuestSupportClass *cgsc = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
|
||||
cgsc->check_support = check_support;
|
||||
cgsc->set_guest_state = set_guest_state;
|
||||
cgsc->set_guest_policy = set_guest_policy;
|
||||
cgsc->get_mem_map_entry = get_mem_map_entry;
|
||||
}
|
||||
|
||||
static void confidential_guest_support_init(Object *obj)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QEMU IGVM interface
|
||||
*
|
||||
* Copyright (C) 2023-2024 SUSE
|
||||
*
|
||||
* Authors:
|
||||
* Roy Hopkins <roy.hopkins@randomman.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "system/igvm-cfg.h"
|
||||
#include "igvm.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
static char *get_igvm(Object *obj, Error **errp)
|
||||
{
|
||||
IgvmCfg *igvm = IGVM_CFG(obj);
|
||||
return g_strdup(igvm->filename);
|
||||
}
|
||||
|
||||
static void set_igvm(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
IgvmCfg *igvm = IGVM_CFG(obj);
|
||||
g_free(igvm->filename);
|
||||
igvm->filename = g_strdup(value);
|
||||
}
|
||||
|
||||
OBJECT_DEFINE_TYPE_WITH_INTERFACES(IgvmCfg, igvm_cfg, IGVM_CFG, OBJECT,
|
||||
{ TYPE_USER_CREATABLE }, { NULL })
|
||||
|
||||
static void igvm_cfg_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
IgvmCfgClass *igvmc = IGVM_CFG_CLASS(oc);
|
||||
|
||||
object_class_property_add_str(oc, "file", get_igvm, set_igvm);
|
||||
object_class_property_set_description(oc, "file",
|
||||
"Set the IGVM filename to use");
|
||||
|
||||
igvmc->process = qigvm_process_file;
|
||||
}
|
||||
|
||||
static void igvm_cfg_init(Object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static void igvm_cfg_finalize(Object *obj)
|
||||
{
|
||||
}
|
||||
+988
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* QEMU IGVM configuration backend for Confidential Guests
|
||||
*
|
||||
* Copyright (C) 2023-2024 SUSE
|
||||
*
|
||||
* Authors:
|
||||
* Roy Hopkins <roy.hopkins@randomman.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_IGVM_H
|
||||
#define BACKENDS_IGVM_H
|
||||
|
||||
#include "system/confidential-guest-support.h"
|
||||
#include "system/igvm-cfg.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
int qigvm_process_file(IgvmCfg *igvm, ConfidentialGuestSupport *cgs,
|
||||
bool onlyVpContext, Error **errp);
|
||||
|
||||
#endif
|
||||
@@ -34,6 +34,11 @@ if have_vhost_user_crypto
|
||||
endif
|
||||
system_ss.add(when: gio, if_true: files('dbus-vmstate.c'))
|
||||
system_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
|
||||
if igvm.found()
|
||||
system_ss.add(igvm)
|
||||
system_ss.add(files('igvm-cfg.c'), igvm)
|
||||
system_ss.add(files('igvm.c'), igvm)
|
||||
endif
|
||||
|
||||
system_ss.add(when: 'CONFIG_SPDM_SOCKET', if_true: files('spdm-socket.c'))
|
||||
|
||||
|
||||
+6
-5
@@ -351,7 +351,7 @@ Writing procedural macros
|
||||
'''''''''''''''''''''''''
|
||||
|
||||
By conventions, procedural macros are split in two functions, one
|
||||
returning ``Result<proc_macro2::TokenStream, MacroError>`` with the body of
|
||||
returning ``Result<proc_macro2::TokenStream, syn::Error>`` with the body of
|
||||
the procedural macro, and the second returning ``proc_macro::TokenStream``
|
||||
which is the actual procedural macro. The former's name is the same as
|
||||
the latter with the ``_or_error`` suffix. The code for the latter is more
|
||||
@@ -361,18 +361,19 @@ from the type after ``as`` in the invocation of ``parse_macro_input!``::
|
||||
#[proc_macro_derive(Object)]
|
||||
pub fn derive_object(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let expanded = derive_object_or_error(input).unwrap_or_else(Into::into);
|
||||
|
||||
TokenStream::from(expanded)
|
||||
derive_object_or_error(input)
|
||||
.unwrap_or_else(syn::Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
The ``qemu_api_macros`` crate has utility functions to examine a
|
||||
``DeriveInput`` and perform common checks (e.g. looking for a struct
|
||||
with named fields). These functions return ``Result<..., MacroError>``
|
||||
with named fields). These functions return ``Result<..., syn::Error>``
|
||||
and can be used easily in the procedural macro function::
|
||||
|
||||
fn derive_object_or_error(input: DeriveInput) ->
|
||||
Result<proc_macro2::TokenStream, MacroError>
|
||||
Result<proc_macro2::TokenStream, Error>
|
||||
{
|
||||
is_c_repr(&input, "#[derive(Object)]")?;
|
||||
|
||||
|
||||
@@ -57,10 +57,17 @@
|
||||
#
|
||||
# @memory: The firmware is to be mapped into memory.
|
||||
#
|
||||
# @igvm: The firmware is defined by a file conforming to the IGVM
|
||||
# specification and mapped into memory according to directives
|
||||
# defined in the file. This is similar to @memory but may
|
||||
# include additional processing defined by the IGVM file
|
||||
# including initial CPU state or population of metadata into
|
||||
# the guest address space. Since: 10.1
|
||||
#
|
||||
# Since: 3.0
|
||||
##
|
||||
{ 'enum' : 'FirmwareDevice',
|
||||
'data' : [ 'flash', 'kernel', 'memory' ] }
|
||||
'data' : [ 'flash', 'kernel', 'memory', 'igvm' ] }
|
||||
|
||||
##
|
||||
# @FirmwareArchitecture:
|
||||
@@ -377,6 +384,24 @@
|
||||
{ 'struct' : 'FirmwareMappingMemory',
|
||||
'data' : { 'filename' : 'str' } }
|
||||
|
||||
##
|
||||
# @FirmwareMappingIgvm:
|
||||
#
|
||||
# Describes loading and mapping properties for the firmware executable,
|
||||
# when @FirmwareDevice is @igvm.
|
||||
#
|
||||
# @filename: Identifies the IGVM file containing the firmware executable
|
||||
# along with other information used to configure the initial
|
||||
# state of the guest. The IGVM file may be shared by multiple
|
||||
# virtual machine definitions. This corresponds to creating
|
||||
# an object on the command line with "-object igvm-cfg,
|
||||
# file=@filename".
|
||||
#
|
||||
# Since: 10.1
|
||||
##
|
||||
{ 'struct' : 'FirmwareMappingIgvm',
|
||||
'data' : { 'filename' : 'str' } }
|
||||
|
||||
##
|
||||
# @FirmwareMapping:
|
||||
#
|
||||
@@ -393,7 +418,8 @@
|
||||
'discriminator' : 'device',
|
||||
'data' : { 'flash' : 'FirmwareMappingFlash',
|
||||
'kernel' : 'FirmwareMappingKernel',
|
||||
'memory' : 'FirmwareMappingMemory' } }
|
||||
'memory' : 'FirmwareMappingMemory',
|
||||
'igvm' : 'FirmwareMappingIgvm' } }
|
||||
|
||||
##
|
||||
# @Firmware:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.. _amd-sev:
|
||||
|
||||
AMD Secure Encrypted Virtualization (SEV)
|
||||
=========================================
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
Independent Guest Virtual Machine (IGVM) support
|
||||
================================================
|
||||
|
||||
IGVM files are designed to encapsulate all the information required to launch a
|
||||
virtual machine on any given virtualization stack in a deterministic way. This
|
||||
allows the cryptographic measurement of initial guest state for Confidential
|
||||
Guests to be calculated when the IGVM file is built, allowing a relying party to
|
||||
verify the initial state of a guest via a remote attestation.
|
||||
|
||||
Although IGVM files are designed with Confidential Computing in mind, they can
|
||||
also be used to configure non-confidential guests. Multiple platforms can be
|
||||
defined by a single IGVM file, allowing a single IGVM file to configure a
|
||||
virtual machine that can run on, for example, TDX, SEV and non-confidential
|
||||
hosts.
|
||||
|
||||
QEMU supports IGVM files through the user-creatable ``igvm-cfg`` object. This
|
||||
object is used to define the filename of the IGVM file to process. A reference
|
||||
to the object is added to the ``-machine`` to configure the virtual machine
|
||||
to use the IGVM file for configuration.
|
||||
|
||||
Confidential platform support is provided through the use of
|
||||
the ``ConfidentialGuestSupport`` object. If the virtual machine provides an
|
||||
instance of this object then this is used by the IGVM loader to configure the
|
||||
isolation properties of the directives within the file.
|
||||
|
||||
Further Information on IGVM
|
||||
---------------------------
|
||||
|
||||
Information about the IGVM format, including links to the format specification
|
||||
and documentation for the Rust and C libraries can be found at the project
|
||||
repository:
|
||||
|
||||
https://github.com/microsoft/igvm
|
||||
|
||||
|
||||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
Currently, IGVM files can be provided for Confidential Guests on host systems
|
||||
that support AMD SEV, SEV-ES and SEV-SNP with KVM. IGVM files can also be
|
||||
provided for non-confidential guests.
|
||||
|
||||
|
||||
Limitations when using IGVM with AMD SEV, SEV-ES and SEV-SNP
|
||||
------------------------------------------------------------
|
||||
|
||||
IGVM files configure the initial state of the guest using a set of directives.
|
||||
Not every directive is supported by every Confidential Guest type. For example,
|
||||
AMD SEV does not support encrypted save state regions, therefore setting the
|
||||
initial CPU state using IGVM for SEV is not possible. When an IGVM file contains
|
||||
directives that are not supported for the active platform, an error is generated
|
||||
and the guest launch is aborted.
|
||||
|
||||
The table below describes the list of directives that are supported for SEV,
|
||||
SEV-ES, SEV-SNP and non-confidential platforms.
|
||||
|
||||
.. list-table:: SEV, SEV-ES, SEV-SNP & non-confidential Supported Directives
|
||||
:widths: 35 65
|
||||
:header-rows: 1
|
||||
|
||||
* - IGVM directive
|
||||
- Notes
|
||||
* - IGVM_VHT_PAGE_DATA
|
||||
- ``NORMAL`` zero, measured and unmeasured page types are supported. Other
|
||||
page types result in an error.
|
||||
* - IGVM_VHT_PARAMETER_AREA
|
||||
-
|
||||
* - IGVM_VHT_PARAMETER_INSERT
|
||||
-
|
||||
* - IGVM_VHT_VP_COUNT_PARAMETER
|
||||
- The guest parameter page is populated with the CPU count.
|
||||
* - IGVM_VHT_ENVIRONMENT_INFO_PARAMETER
|
||||
- The ``memory_is_shared`` parameter is set to 1 in the guest parameter
|
||||
page.
|
||||
|
||||
.. list-table:: Additional SEV, SEV-ES & SEV_SNP Supported Directives
|
||||
:widths: 25 75
|
||||
:header-rows: 1
|
||||
|
||||
* - IGVM directive
|
||||
- Notes
|
||||
* - IGVM_VHT_MEMORY_MAP
|
||||
- The memory map page is populated using entries from the E820 table.
|
||||
* - IGVM_VHT_REQUIRED_MEMORY
|
||||
- Ensures memory is available in the guest at the specified range.
|
||||
|
||||
.. list-table:: Additional SEV-ES & SEV-SNP Supported Directives
|
||||
:widths: 25 75
|
||||
:header-rows: 1
|
||||
|
||||
* - IGVM directive
|
||||
- Notes
|
||||
* - IGVM_VHT_VP_CONTEXT
|
||||
- Setting of the initial CPU state for the boot CPU and additional CPUs is
|
||||
supported with limitations on the fields that can be provided in the
|
||||
VMSA. See below for details on which fields are supported.
|
||||
|
||||
Initial CPU state with VMSA
|
||||
---------------------------
|
||||
|
||||
The initial state of guest CPUs can be defined in the IGVM file for AMD SEV-ES
|
||||
and SEV-SNP. The state data is provided as a VMSA structure as defined in Table
|
||||
B-4 in the AMD64 Architecture Programmer's Manual, Volume 2 [1].
|
||||
|
||||
The IGVM VMSA is translated to CPU state in QEMU which is then synchronized
|
||||
by KVM to the guest VMSA during the launch process where it contributes to the
|
||||
launch measurement. See :ref:`amd-sev` for details on the launch process and
|
||||
guest launch measurement.
|
||||
|
||||
It is important that no information is lost or changed when translating the
|
||||
VMSA provided by the IGVM file into the VSMA that is used to launch the guest.
|
||||
Therefore, QEMU restricts the VMSA fields that can be provided in the IGVM
|
||||
VMSA structure to the following registers:
|
||||
|
||||
RAX, RCX, RDX, RBX, RBP, RSI, RDI, R8-R15, RSP, RIP, CS, DS, ES, FS, GS, SS,
|
||||
CR0, CR3, CR4, XCR0, EFER, PAT, GDT, IDT, LDTR, TR, DR6, DR7, RFLAGS, X87_FCW,
|
||||
MXCSR.
|
||||
|
||||
When processing the IGVM file, QEMU will check if any fields other than the
|
||||
above are non-zero and generate an error if this is the case.
|
||||
|
||||
KVM uses a hardcoded GPA of 0xFFFFFFFFF000 for the VMSA. When an IGVM file
|
||||
defines initial CPU state, the GPA for each VMSA must match this hardcoded
|
||||
value.
|
||||
|
||||
Firmware Images with IGVM
|
||||
-------------------------
|
||||
|
||||
When an IGVM filename is specified for a Confidential Guest Support object it
|
||||
overrides the default handling of system firmware: the firmware image, such as
|
||||
an OVMF binary should be contained as a payload of the IGVM file and not
|
||||
provided as a flash drive or via the ``-bios`` parameter. The default QEMU
|
||||
firmware is not automatically populated into the guest memory space.
|
||||
|
||||
If an IGVM file is provided along with either the ``-bios`` parameter or pflash
|
||||
devices then an error is displayed and the guest startup is aborted.
|
||||
|
||||
Running a guest configured using IGVM
|
||||
-------------------------------------
|
||||
|
||||
To run a guest configured with IGVM you firstly need to generate an IGVM file
|
||||
that contains a guest configuration compatible with the platform you are
|
||||
targeting.
|
||||
|
||||
The ``buildigvm`` tool [2] is an example of a tool that can be used to generate
|
||||
IGVM files for non-confidential X86 platforms as well as for SEV, SEV-ES and
|
||||
SEV-SNP confidential platforms.
|
||||
|
||||
Example using this tool to generate an IGVM file for AMD SEV-SNP::
|
||||
|
||||
buildigvm --firmware /path/to/OVMF.fd --output sev-snp.igvm \
|
||||
--cpucount 4 sev-snp
|
||||
|
||||
To run a guest configured with the generated IGVM you need to add an
|
||||
``igvm-cfg`` object and refer to it from the ``-machine`` parameter:
|
||||
|
||||
Example (for AMD SEV)::
|
||||
|
||||
qemu-system-x86_64 \
|
||||
<other parameters> \
|
||||
-machine ...,confidential-guest-support=sev0,igvm-cfg=igvm0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1 \
|
||||
-object igvm-cfg,id=igvm0,file=/path/to/sev-snp.igvm
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
[1] AMD64 Architecture Programmer's Manual, Volume 2: System Programming
|
||||
Rev 3.41
|
||||
https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24593.pdf
|
||||
|
||||
[2] ``buildigvm`` - A tool to build example IGVM files containing OVMF firmware
|
||||
https://github.com/roy-hopkins/buildigvm
|
||||
@@ -38,5 +38,6 @@ or Hypervisor.Framework.
|
||||
security
|
||||
multi-process
|
||||
confidential-guest-support
|
||||
igvm
|
||||
vm-templating
|
||||
sriov
|
||||
|
||||
+16
-1
@@ -81,7 +81,10 @@
|
||||
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
|
||||
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
|
||||
|
||||
GlobalProperty pc_compat_10_0[] = {};
|
||||
GlobalProperty pc_compat_10_0[] = {
|
||||
{ TYPE_X86_CPU, "x-consistent-cache", "false" },
|
||||
{ TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
|
||||
};
|
||||
const size_t pc_compat_10_0_len = G_N_ELEMENTS(pc_compat_10_0);
|
||||
|
||||
GlobalProperty pc_compat_9_2[] = {};
|
||||
@@ -1827,6 +1830,18 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
|
||||
object_class_property_add_bool(oc, "fd-bootchk",
|
||||
pc_machine_get_fd_bootchk,
|
||||
pc_machine_set_fd_bootchk);
|
||||
|
||||
#if defined(CONFIG_IGVM)
|
||||
object_class_property_add_link(oc, "igvm-cfg",
|
||||
TYPE_IGVM_CFG,
|
||||
offsetof(X86MachineState, igvm),
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_STRONG);
|
||||
object_class_property_set_description(oc, "igvm-cfg",
|
||||
"Set IGVM configuration");
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo pc_machine_info = {
|
||||
|
||||
@@ -366,6 +366,16 @@ static void pc_init1(MachineState *machine, const char *pci_type)
|
||||
x86_nvdimm_acpi_dsmio,
|
||||
x86ms->fw_cfg, OBJECT(pcms));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IGVM)
|
||||
/* Apply guest state from IGVM if supplied */
|
||||
if (x86ms->igvm) {
|
||||
if (IGVM_CFG_GET_CLASS(x86ms->igvm)
|
||||
->process(x86ms->igvm, machine->cgs, false, &error_fatal) < 0) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef enum PCSouthBridgeOption {
|
||||
|
||||
@@ -325,6 +325,16 @@ static void pc_q35_init(MachineState *machine)
|
||||
x86_nvdimm_acpi_dsmio,
|
||||
x86ms->fw_cfg, OBJECT(pcms));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IGVM)
|
||||
/* Apply guest state from IGVM if supplied */
|
||||
if (x86ms->igvm) {
|
||||
if (IGVM_CFG_GET_CLASS(x86ms->igvm)
|
||||
->process(x86ms->igvm, machine->cgs, false, &error_fatal) < 0) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DEFINE_Q35_MACHINE(major, minor) \
|
||||
|
||||
+28
-3
@@ -220,7 +220,13 @@ void pc_system_firmware_init(PCMachineState *pcms,
|
||||
BlockBackend *pflash_blk[ARRAY_SIZE(pcms->flash)];
|
||||
|
||||
if (!pcmc->pci_enabled) {
|
||||
x86_bios_rom_init(X86_MACHINE(pcms), "bios.bin", rom_memory, true);
|
||||
/*
|
||||
* If an IGVM file is specified then the firmware must be provided
|
||||
* in the IGVM file.
|
||||
*/
|
||||
if (!X86_MACHINE(pcms)->igvm) {
|
||||
x86_bios_rom_init(X86_MACHINE(pcms), "bios.bin", rom_memory, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -240,8 +246,13 @@ void pc_system_firmware_init(PCMachineState *pcms,
|
||||
}
|
||||
|
||||
if (!pflash_blk[0]) {
|
||||
/* Machine property pflash0 not set, use ROM mode */
|
||||
x86_bios_rom_init(X86_MACHINE(pcms), "bios.bin", rom_memory, false);
|
||||
/*
|
||||
* Machine property pflash0 not set, use ROM mode unless using IGVM,
|
||||
* in which case the firmware must be provided by the IGVM file.
|
||||
*/
|
||||
if (!X86_MACHINE(pcms)->igvm) {
|
||||
x86_bios_rom_init(X86_MACHINE(pcms), "bios.bin", rom_memory, false);
|
||||
}
|
||||
} else {
|
||||
if (kvm_enabled() && !kvm_readonly_mem_enabled()) {
|
||||
/*
|
||||
@@ -257,6 +268,20 @@ void pc_system_firmware_init(PCMachineState *pcms,
|
||||
}
|
||||
|
||||
pc_system_flash_cleanup_unused(pcms);
|
||||
|
||||
/*
|
||||
* The user should not have specified any pflash devices when using IGVM
|
||||
* to configure the guest.
|
||||
*/
|
||||
if (X86_MACHINE(pcms)->igvm) {
|
||||
for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
|
||||
if (pcms->flash[i]) {
|
||||
error_report("pflash devices cannot be configured when "
|
||||
"using IGVM");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void x86_firmware_configure(hwaddr gpa, void *ptr, int size)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "hw/intc/ioapic.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "qom/object.h"
|
||||
#include "system/igvm-cfg.h"
|
||||
|
||||
struct X86MachineClass {
|
||||
MachineClass parent;
|
||||
@@ -92,6 +93,8 @@ struct X86MachineState {
|
||||
* which means no limitation on the guest's bus locks.
|
||||
*/
|
||||
uint64_t bus_lock_ratelimit;
|
||||
|
||||
IgvmCfg *igvm;
|
||||
};
|
||||
|
||||
#define X86_MACHINE_SMM "smm"
|
||||
|
||||
@@ -84,6 +84,8 @@ typedef struct QEMULogItem {
|
||||
|
||||
extern const QEMULogItem qemu_log_items[];
|
||||
|
||||
ssize_t rust_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
|
||||
bool qemu_set_log(int log_flags, Error **errp);
|
||||
bool qemu_set_log_filename(const char *filename, Error **errp);
|
||||
bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define QEMU_CONFIDENTIAL_GUEST_SUPPORT_H
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "exec/hwaddr.h"
|
||||
|
||||
#define TYPE_CONFIDENTIAL_GUEST_SUPPORT "confidential-guest-support"
|
||||
OBJECT_DECLARE_TYPE(ConfidentialGuestSupport,
|
||||
@@ -26,6 +27,40 @@ OBJECT_DECLARE_TYPE(ConfidentialGuestSupport,
|
||||
CONFIDENTIAL_GUEST_SUPPORT)
|
||||
|
||||
|
||||
typedef enum ConfidentialGuestPlatformType {
|
||||
CGS_PLATFORM_SEV,
|
||||
CGS_PLATFORM_SEV_ES,
|
||||
CGS_PLATFORM_SEV_SNP,
|
||||
} ConfidentialGuestPlatformType;
|
||||
|
||||
typedef enum ConfidentialGuestMemoryType {
|
||||
CGS_MEM_RAM,
|
||||
CGS_MEM_RESERVED,
|
||||
CGS_MEM_ACPI,
|
||||
CGS_MEM_NVS,
|
||||
CGS_MEM_UNUSABLE,
|
||||
} ConfidentialGuestMemoryType;
|
||||
|
||||
typedef struct ConfidentialGuestMemoryMapEntry {
|
||||
uint64_t gpa;
|
||||
uint64_t size;
|
||||
ConfidentialGuestMemoryType type;
|
||||
} ConfidentialGuestMemoryMapEntry;
|
||||
|
||||
typedef enum ConfidentialGuestPageType {
|
||||
CGS_PAGE_TYPE_NORMAL,
|
||||
CGS_PAGE_TYPE_VMSA,
|
||||
CGS_PAGE_TYPE_ZERO,
|
||||
CGS_PAGE_TYPE_UNMEASURED,
|
||||
CGS_PAGE_TYPE_SECRETS,
|
||||
CGS_PAGE_TYPE_CPUID,
|
||||
CGS_PAGE_TYPE_REQUIRED_MEMORY,
|
||||
} ConfidentialGuestPageType;
|
||||
|
||||
typedef enum ConfidentialGuestPolicyType {
|
||||
GUEST_POLICY_SEV,
|
||||
} ConfidentialGuestPolicyType;
|
||||
|
||||
struct ConfidentialGuestSupport {
|
||||
Object parent;
|
||||
|
||||
@@ -64,6 +99,59 @@ typedef struct ConfidentialGuestSupportClass {
|
||||
|
||||
int (*kvm_init)(ConfidentialGuestSupport *cgs, Error **errp);
|
||||
int (*kvm_reset)(ConfidentialGuestSupport *cgs, Error **errp);
|
||||
|
||||
/*
|
||||
* Check to see if this confidential guest supports a particular
|
||||
* platform or configuration.
|
||||
*
|
||||
* Return true if supported or false if not supported.
|
||||
*/
|
||||
bool (*check_support)(ConfidentialGuestPlatformType platform,
|
||||
uint16_t platform_version, uint8_t highest_vtl,
|
||||
uint64_t shared_gpa_boundary);
|
||||
|
||||
/*
|
||||
* Configure part of the state of a guest for a particular set of data, page
|
||||
* type and gpa. This can be used for example to pre-populate and measure
|
||||
* guest memory contents, define private ranges or set the initial CPU state
|
||||
* for one or more CPUs.
|
||||
*
|
||||
* If memory_type is CGS_PAGE_TYPE_VMSA then ptr points to the initial CPU
|
||||
* context for a virtual CPU. The format of the data depends on the type of
|
||||
* confidential virtual machine. For example, for SEV-ES ptr will point to a
|
||||
* vmcb_save_area structure that should be copied into guest memory at the
|
||||
* address specified in gpa. The cpu_index parameter contains the index of
|
||||
* the CPU the VMSA applies to.
|
||||
*/
|
||||
int (*set_guest_state)(hwaddr gpa, uint8_t *ptr, uint64_t len,
|
||||
ConfidentialGuestPageType memory_type,
|
||||
uint16_t cpu_index, Error **errp);
|
||||
|
||||
/*
|
||||
* Set the guest policy. The policy can be used to configure the
|
||||
* confidential platform, such as if debug is enabled or not and can contain
|
||||
* information about expected launch measurements, signed verification of
|
||||
* guest configuration and other platform data.
|
||||
*
|
||||
* The format of the policy data is specific to each platform. For example,
|
||||
* SEV-SNP uses a policy bitfield in the 'policy' argument and provides an
|
||||
* ID block and ID authentication in the 'policy_data' parameters. The type
|
||||
* of policy data is identified by the 'policy_type' argument.
|
||||
*/
|
||||
int (*set_guest_policy)(ConfidentialGuestPolicyType policy_type,
|
||||
uint64_t policy,
|
||||
void *policy_data1, uint32_t policy_data1_size,
|
||||
void *policy_data2, uint32_t policy_data2_size,
|
||||
Error **errp);
|
||||
|
||||
/*
|
||||
* Iterate the system memory map, getting the entry with the given index
|
||||
* that can be populated into guest memory.
|
||||
*
|
||||
* Returns 0 for ok, 1 if the index is out of range and -1 on error.
|
||||
*/
|
||||
int (*get_mem_map_entry)(int index, ConfidentialGuestMemoryMapEntry *entry,
|
||||
Error **errp);
|
||||
} ConfidentialGuestSupportClass;
|
||||
|
||||
static inline int confidential_guest_kvm_init(ConfidentialGuestSupport *cgs,
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* QEMU IGVM interface
|
||||
*
|
||||
* Copyright (C) 2024 SUSE
|
||||
*
|
||||
* Authors:
|
||||
* Roy Hopkins <roy.hopkins@randomman.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef QEMU_IGVM_CFG_H
|
||||
#define QEMU_IGVM_CFG_H
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
typedef struct IgvmCfg {
|
||||
ObjectClass parent_class;
|
||||
|
||||
/*
|
||||
* filename: Filename that specifies a file that contains the configuration
|
||||
* of the guest in Independent Guest Virtual Machine (IGVM)
|
||||
* format.
|
||||
*/
|
||||
char *filename;
|
||||
} IgvmCfg;
|
||||
|
||||
typedef struct IgvmCfgClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
/*
|
||||
* If an IGVM filename has been specified then process the IGVM file.
|
||||
* Performs a no-op if no filename has been specified.
|
||||
* If onlyVpContext is true then only the IGVM_VHT_VP_CONTEXT entries
|
||||
* in the IGVM file will be processed, allowing information about the
|
||||
* CPU state to be determined before processing the entire file.
|
||||
*
|
||||
* Returns 0 for ok and -1 on error.
|
||||
*/
|
||||
int (*process)(IgvmCfg *cfg, ConfidentialGuestSupport *cgs,
|
||||
bool onlyVpContext, Error **errp);
|
||||
|
||||
} IgvmCfgClass;
|
||||
|
||||
#define TYPE_IGVM_CFG "igvm-cfg"
|
||||
|
||||
OBJECT_DECLARE_TYPE(IgvmCfg, IgvmCfgClass, IGVM_CFG)
|
||||
|
||||
#endif
|
||||
@@ -963,7 +963,13 @@ struct kvm_tdx_cmd {
|
||||
struct kvm_tdx_capabilities {
|
||||
__u64 supported_attrs;
|
||||
__u64 supported_xfam;
|
||||
__u64 reserved[254];
|
||||
|
||||
__u64 kernel_tdvmcallinfo_1_r11;
|
||||
__u64 user_tdvmcallinfo_1_r11;
|
||||
__u64 kernel_tdvmcallinfo_1_r12;
|
||||
__u64 user_tdvmcallinfo_1_r12;
|
||||
|
||||
__u64 reserved[250];
|
||||
|
||||
/* Configurable CPUID bits for userspace */
|
||||
struct kvm_cpuid2 cpuid;
|
||||
|
||||
@@ -459,6 +459,10 @@ struct kvm_run {
|
||||
__u64 leaf;
|
||||
__u64 r11, r12, r13, r14;
|
||||
} get_tdvmcall_info;
|
||||
struct {
|
||||
__u64 ret;
|
||||
__u64 vector;
|
||||
} setup_event_notify;
|
||||
};
|
||||
} tdx;
|
||||
/* Fix the size of the union. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user