mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 16:23:55 -06:00
* target/i386/kvm: Intel TDX support
* target/i386/emulate: more lflags cleanups * meson: remove need for explicit listing of dependencies in hw_common_arch and target_common_arch * rust: small fixes * hpet: Reorganize register decoding to be more similar to Rust code * target/i386: fixes for AMD models * target/i386: new EPYC-Turin CPU model -----BEGIN PGP SIGNATURE----- iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmg4BxwUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroP67gf+PEP4EDQP0AJUfxXYVsczGf5snGjz ro8jYmKG+huBZcrS6uPK5zHYxtOI9bHr4ipTHJyHd61lyzN6Ys9amPbs/CRE2Q4x Ky4AojPhCuaL2wHcYNcu41L+hweVQ3myj97vP3hWvkatulXYeMqW3/4JZgr4WZ69 A9LGLtLabobTz5yLc8x6oHLn/BZ2y7gjd2LzTz8bqxx7C/kamjoDrF2ZHbX9DLQW BKWQ3edSO6rorSNHWGZsy9BE20AEkW2LgJdlV9eXglFEuEs6cdPKwGEZepade4bQ Rdt2gHTlQdUDTFmAbz8pttPxFGMC9Zpmb3nnicKJpKQAmkT/x4k9ncjyAQ== =XmkU -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * target/i386/kvm: Intel TDX support * target/i386/emulate: more lflags cleanups * meson: remove need for explicit listing of dependencies in hw_common_arch and target_common_arch * rust: small fixes * hpet: Reorganize register decoding to be more similar to Rust code * target/i386: fixes for AMD models * target/i386: new EPYC-Turin CPU model # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmg4BxwUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroP67gf+PEP4EDQP0AJUfxXYVsczGf5snGjz # ro8jYmKG+huBZcrS6uPK5zHYxtOI9bHr4ipTHJyHd61lyzN6Ys9amPbs/CRE2Q4x # Ky4AojPhCuaL2wHcYNcu41L+hweVQ3myj97vP3hWvkatulXYeMqW3/4JZgr4WZ69 # A9LGLtLabobTz5yLc8x6oHLn/BZ2y7gjd2LzTz8bqxx7C/kamjoDrF2ZHbX9DLQW # BKWQ3edSO6rorSNHWGZsy9BE20AEkW2LgJdlV9eXglFEuEs6cdPKwGEZepade4bQ # Rdt2gHTlQdUDTFmAbz8pttPxFGMC9Zpmb3nnicKJpKQAmkT/x4k9ncjyAQ== # =XmkU # -----END PGP SIGNATURE----- # gpg: Signature made Thu 29 May 2025 03:05:00 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) target/i386/tcg/helper-tcg: fix file references in comments target/i386: Add support for EPYC-Turin model target/i386: Update EPYC-Genoa for Cache property, perfmon-v2, RAS and SVM feature bits target/i386: Add couple of feature bits in CPUID_Fn80000021_EAX target/i386: Update EPYC-Milan CPU model for Cache property, RAS, SVM feature bits target/i386: Update EPYC-Rome CPU model for Cache property, RAS, SVM feature bits target/i386: Update EPYC CPU model for Cache property, RAS, SVM feature bits rust: make declaration of dependent crates more consistent docs: Add TDX documentation i386/tdx: Validate phys_bits against host value i386/tdx: Make invtsc default on i386/tdx: Don't treat SYSCALL as unavailable i386/tdx: Fetch and validate CPUID of TD guest target/i386: Print CPUID subleaf info for unsupported feature i386: Remove unused parameter "uint32_t bit" in feature_word_description() i386/cgs: Introduce x86_confidential_guest_check_features() i386/tdx: Define supported KVM features for TDX i386/tdx: Add XFD to supported bit of TDX i386/tdx: Add supported CPUID bits relates to XFAM i386/tdx: Add supported CPUID bits related to TD Attributes ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
98721058d6
66 changed files with 3231 additions and 346 deletions
|
@ -471,7 +471,9 @@ int kvm_create_vcpu(CPUState *cpu)
|
|||
|
||||
cpu->kvm_fd = kvm_fd;
|
||||
cpu->kvm_state = s;
|
||||
cpu->vcpu_dirty = true;
|
||||
if (!s->guest_state_protected) {
|
||||
cpu->vcpu_dirty = true;
|
||||
}
|
||||
cpu->dirty_pages = 0;
|
||||
cpu->throttle_us_per_full = 0;
|
||||
|
||||
|
@ -545,6 +547,11 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
|||
|
||||
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||
|
||||
ret = kvm_arch_pre_create_vcpu(cpu, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = kvm_create_vcpu(cpu);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret,
|
||||
|
@ -2426,7 +2433,7 @@ static int kvm_recommended_vcpus(KVMState *s)
|
|||
|
||||
static int kvm_max_vcpus(KVMState *s)
|
||||
{
|
||||
int ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
|
||||
int ret = kvm_vm_check_extension(s, KVM_CAP_MAX_VCPUS);
|
||||
return (ret) ? ret : kvm_recommended_vcpus(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,15 +18,15 @@ if get_option('plugins')
|
|||
tcg_ss.add(files('plugin-gen.c'))
|
||||
endif
|
||||
|
||||
libuser_ss.add_all(tcg_ss)
|
||||
libsystem_ss.add_all(tcg_ss)
|
||||
user_ss.add_all(tcg_ss)
|
||||
system_ss.add_all(tcg_ss)
|
||||
|
||||
libuser_ss.add(files(
|
||||
user_ss.add(files(
|
||||
'user-exec.c',
|
||||
'user-exec-stub.c',
|
||||
))
|
||||
|
||||
libsystem_ss.add(files(
|
||||
system_ss.add(files(
|
||||
'cputlb.c',
|
||||
'icount-common.c',
|
||||
'monitor.c',
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#CONFIG_QXL=n
|
||||
#CONFIG_SEV=n
|
||||
#CONFIG_SGA=n
|
||||
#CONFIG_TDX=n
|
||||
#CONFIG_TEST_DEVICES=n
|
||||
#CONFIG_TPM_CRB=n
|
||||
#CONFIG_TPM_TIS_ISA=n
|
||||
|
|
|
@ -38,6 +38,7 @@ Supported mechanisms
|
|||
Currently supported confidential guest mechanisms are:
|
||||
|
||||
* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
|
||||
* Intel Trust Domain Extension (TDX) (see :doc:`i386/tdx`)
|
||||
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
|
||||
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
|
||||
|
||||
|
|
161
docs/system/i386/tdx.rst
Normal file
161
docs/system/i386/tdx.rst
Normal file
|
@ -0,0 +1,161 @@
|
|||
Intel Trusted Domain eXtension (TDX)
|
||||
====================================
|
||||
|
||||
Intel Trusted Domain eXtensions (TDX) refers to an Intel technology that extends
|
||||
Virtual Machine Extensions (VMX) and Multi-Key Total Memory Encryption (MKTME)
|
||||
with a new kind of virtual machine guest called a Trust Domain (TD). A TD runs
|
||||
in a CPU mode that is designed to protect the confidentiality of its memory
|
||||
contents and its CPU state from any other software, including the hosting
|
||||
Virtual Machine Monitor (VMM), unless explicitly shared by the TD itself.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
To run TD, the physical machine needs to have TDX module loaded and initialized
|
||||
while KVM hypervisor has TDX support and has TDX enabled. If those requirements
|
||||
are met, the ``KVM_CAP_VM_TYPES`` will report the support of ``KVM_X86_TDX_VM``.
|
||||
|
||||
Trust Domain Virtual Firmware (TDVF)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Trust Domain Virtual Firmware (TDVF) is required to provide TD services to boot
|
||||
TD Guest OS. TDVF needs to be copied to guest private memory and measured before
|
||||
the TD boots.
|
||||
|
||||
KVM vcpu ioctl ``KVM_TDX_INIT_MEM_REGION`` can be used to populate the TDVF
|
||||
content into its private memory.
|
||||
|
||||
Since TDX doesn't support readonly memslot, TDVF cannot be mapped as pflash
|
||||
device and it actually works as RAM. "-bios" option is chosen to load TDVF.
|
||||
|
||||
OVMF is the opensource firmware that implements the TDVF support. Thus the
|
||||
command line to specify and load TDVF is ``-bios OVMF.fd``
|
||||
|
||||
Feature Configuration
|
||||
---------------------
|
||||
|
||||
Unlike non-TDX VM, the CPU features (enumerated by CPU or MSR) of a TD are not
|
||||
under full control of VMM. VMM can only configure part of features of a TD on
|
||||
``KVM_TDX_INIT_VM`` command of VM scope ``MEMORY_ENCRYPT_OP`` ioctl.
|
||||
|
||||
The configurable features have three types:
|
||||
|
||||
- Attributes:
|
||||
- PKS (bit 30) controls whether Supervisor Protection Keys is exposed to TD,
|
||||
which determines related CPUID bit and CR4 bit;
|
||||
- PERFMON (bit 63) controls whether PMU is exposed to TD.
|
||||
|
||||
- XSAVE related features (XFAM):
|
||||
XFAM is a 64b mask, which has the same format as XCR0 or IA32_XSS MSR. It
|
||||
determines the set of extended features available for use by the guest TD.
|
||||
|
||||
- CPUID features:
|
||||
Only some bits of some CPUID leaves are directly configurable by VMM.
|
||||
|
||||
What features can be configured is reported via TDX capabilities.
|
||||
|
||||
TDX capabilities
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The VM scope ``MEMORY_ENCRYPT_OP`` ioctl provides command ``KVM_TDX_CAPABILITIES``
|
||||
to get the TDX capabilities from KVM. It returns a data structure of
|
||||
``struct kvm_tdx_capabilities``, which tells the supported configuration of
|
||||
attributes, XFAM and CPUIDs.
|
||||
|
||||
TD attributes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
QEMU supports configuring raw 64-bit TD attributes directly via "attributes"
|
||||
property of "tdx-guest" object. Note, it's users' responsibility to provide a
|
||||
valid value because some bits may not supported by current QEMU or KVM yet.
|
||||
|
||||
QEMU also supports the configuration of individual attribute bits that are
|
||||
supported by it, via properties of "tdx-guest" object.
|
||||
E.g., "sept-ve-disable" (bit 28).
|
||||
|
||||
MSR based features
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Current KVM doesn't support MSR based feature (e.g., MSR_IA32_ARCH_CAPABILITIES)
|
||||
configuration for TDX, and it's a future work to enable it in QEMU when KVM adds
|
||||
support of it.
|
||||
|
||||
Feature check
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
QEMU checks if the final (CPU) features, determined by given cpu model and
|
||||
explicit feature adjustment of "+featureA/-featureB", can be supported or not.
|
||||
It can produce feature not supported warning like
|
||||
|
||||
"warning: host doesn't support requested feature: CPUID.07H:EBX.intel-pt [bit 25]"
|
||||
|
||||
It can also produce warning like
|
||||
|
||||
"warning: TDX forcibly sets the feature: CPUID.80000007H:EDX.invtsc [bit 8]"
|
||||
|
||||
if the fixed-1 feature is requested to be disabled explicitly. This is newly
|
||||
added to QEMU for TDX because TDX has fixed-1 features that are forcibly enabled
|
||||
by TDX module and VMM cannot disable them.
|
||||
|
||||
Launching a TD (TDX VM)
|
||||
-----------------------
|
||||
|
||||
To launch a TD, the necessary command line options are tdx-guest object and
|
||||
split kernel-irqchip, as below:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system_x86| \\
|
||||
-accel kvm \\
|
||||
-cpu host \\
|
||||
-object tdx-guest,id=tdx0 \\
|
||||
-machine ...,confidential-guest-support=tdx0 \\
|
||||
-bios OVMF.fd \\
|
||||
|
||||
Restrictions
|
||||
------------
|
||||
|
||||
- kernel-irqchip must be split;
|
||||
|
||||
This is set by default for TDX guest if kernel-irqchip is left on its default
|
||||
'auto' setting.
|
||||
|
||||
- No readonly support for private memory;
|
||||
|
||||
- No SMM support: SMM support requires manipulating the guest register states
|
||||
which is not allowed;
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Bit 0 of TD attributes, is DEBUG bit, which decides if the TD runs in off-TD
|
||||
debug mode. When in off-TD debug mode, TD's VCPU state and private memory are
|
||||
accessible via given SEAMCALLs. This requires KVM to expose APIs to invoke those
|
||||
SEAMCALLs and corresonponding QEMU change.
|
||||
|
||||
It's targeted as future work.
|
||||
|
||||
TD attestation
|
||||
--------------
|
||||
|
||||
In TD guest, the attestation process is used to verify the TDX guest
|
||||
trustworthiness to other entities before provisioning secrets to the guest.
|
||||
|
||||
TD attestation is initiated first by calling TDG.MR.REPORT inside TD to get the
|
||||
REPORT. Then the REPORT data needs to be converted into a remotely verifiable
|
||||
Quote by SGX Quoting Enclave (QE).
|
||||
|
||||
It's a future work in QEMU to add support of TD attestation since it lacks
|
||||
support in current KVM.
|
||||
|
||||
Live Migration
|
||||
--------------
|
||||
|
||||
Future work.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
- `TDX Homepage <https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html>`__
|
||||
|
||||
- `SGX QE <https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/QuoteGeneration>`__
|
|
@ -31,6 +31,7 @@ Architectural features
|
|||
i386/kvm-pv
|
||||
i386/sgx
|
||||
i386/amd-memory-encryption
|
||||
i386/tdx
|
||||
|
||||
OS requirements
|
||||
~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
#
|
||||
|
||||
# We build two versions of gdbstub, one for each mode
|
||||
libuser_ss.add(files(
|
||||
user_ss.add(files(
|
||||
'gdbstub.c',
|
||||
'syscalls.c',
|
||||
'user.c'
|
||||
))
|
||||
|
||||
libsystem_ss.add(files(
|
||||
system_ss.add(files(
|
||||
'gdbstub.c',
|
||||
'syscalls.c',
|
||||
'system.c'
|
||||
|
|
|
@ -8,7 +8,7 @@ arm_common_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c'))
|
|||
arm_common_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_MUSICPAL', if_true: [pixman, files('musicpal.c')])
|
||||
arm_common_ss.add(when: 'CONFIG_MUSICPAL', if_true: [files('musicpal.c')])
|
||||
arm_common_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
|
||||
|
@ -79,7 +79,7 @@ arm_common_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
|
|||
arm_common_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
|
||||
|
||||
arm_common_ss.add(fdt, files('boot.c'))
|
||||
arm_common_ss.add(files('boot.c'))
|
||||
|
||||
hw_arch += {'arm': arm_ss}
|
||||
hw_common_arch += {'arm': arm_common_ss}
|
||||
|
|
|
@ -26,7 +26,7 @@ system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c'))
|
|||
system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c'))
|
||||
system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls])
|
||||
|
||||
libsystem_ss.add(files(
|
||||
system_ss.add(files(
|
||||
'cpu-system.c',
|
||||
'fw-path-provider.c',
|
||||
'gpio.c',
|
||||
|
@ -46,7 +46,7 @@ libsystem_ss.add(files(
|
|||
'vm-change-state-handler.c',
|
||||
'clock-vmstate.c',
|
||||
))
|
||||
libuser_ss.add(files(
|
||||
user_ss.add(files(
|
||||
'cpu-user.c',
|
||||
'qdev-user.c',
|
||||
))
|
||||
|
|
|
@ -10,6 +10,11 @@ config SGX
|
|||
bool
|
||||
depends on KVM
|
||||
|
||||
config TDX
|
||||
bool
|
||||
select X86_FW_OVMF
|
||||
depends on KVM
|
||||
|
||||
config PC
|
||||
bool
|
||||
imply APPLESMC
|
||||
|
@ -26,6 +31,7 @@ config PC
|
|||
imply QXL
|
||||
imply SEV
|
||||
imply SGX
|
||||
imply TDX
|
||||
imply TEST_DEVICES
|
||||
imply TPM_CRB
|
||||
imply TPM_TIS_ISA
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "system/hw_accel.h"
|
||||
#include "system/kvm.h"
|
||||
#include "kvm/kvm_i386.h"
|
||||
#include "kvm/tdx.h"
|
||||
|
||||
static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
|
||||
int reg_id, uint32_t val)
|
||||
|
@ -141,6 +142,10 @@ static void kvm_apic_put(CPUState *cs, run_on_cpu_data data)
|
|||
struct kvm_lapic_state kapic;
|
||||
int ret;
|
||||
|
||||
if (is_tdx_vm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
kvm_put_apicbase(s->cpu, s->apicbase);
|
||||
kvm_put_apic_state(s, &kapic);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files(
|
|||
'port92.c'))
|
||||
i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
|
||||
if_false: files('pc_sysfw_ovmf-stubs.c'))
|
||||
i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c'))
|
||||
|
||||
subdir('kvm')
|
||||
subdir('xen')
|
||||
|
|
29
hw/i386/pc.c
29
hw/i386/pc.c
|
@ -44,6 +44,7 @@
|
|||
#include "system/xen.h"
|
||||
#include "system/reset.h"
|
||||
#include "kvm/kvm_i386.h"
|
||||
#include "kvm/tdx.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qobject/qlist.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@ -976,21 +977,23 @@ void pc_memory_init(PCMachineState *pcms,
|
|||
/* Initialize PC system firmware */
|
||||
pc_system_firmware_init(pcms, rom_memory);
|
||||
|
||||
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
|
||||
if (machine_require_guest_memfd(machine)) {
|
||||
memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
|
||||
PC_ROM_SIZE, &error_fatal);
|
||||
} else {
|
||||
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
|
||||
&error_fatal);
|
||||
if (pcmc->pci_enabled) {
|
||||
memory_region_set_readonly(option_rom_mr, true);
|
||||
if (!is_tdx_vm()) {
|
||||
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
|
||||
if (machine_require_guest_memfd(machine)) {
|
||||
memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
|
||||
PC_ROM_SIZE, &error_fatal);
|
||||
} else {
|
||||
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
|
||||
&error_fatal);
|
||||
if (pcmc->pci_enabled) {
|
||||
memory_region_set_readonly(option_rom_mr, true);
|
||||
}
|
||||
}
|
||||
memory_region_add_subregion_overlap(rom_memory,
|
||||
PC_ROM_MIN_VGA,
|
||||
option_rom_mr,
|
||||
1);
|
||||
}
|
||||
memory_region_add_subregion_overlap(rom_memory,
|
||||
PC_ROM_MIN_VGA,
|
||||
option_rom_mr,
|
||||
1);
|
||||
|
||||
fw_cfg = fw_cfg_arch_create(machine,
|
||||
x86ms->boot_cpus, x86ms->apic_id_limit);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "hw/block/flash.h"
|
||||
#include "system/kvm.h"
|
||||
#include "target/i386/sev.h"
|
||||
#include "kvm/tdx.h"
|
||||
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
|
||||
|
@ -280,5 +281,11 @@ void x86_firmware_configure(hwaddr gpa, void *ptr, int size)
|
|||
}
|
||||
|
||||
sev_encrypt_flash(gpa, ptr, size, &error_fatal);
|
||||
} else if (is_tdx_vm()) {
|
||||
ret = tdx_parse_tdvf(ptr, size);
|
||||
if (ret) {
|
||||
error_report("failed to parse TDVF for TDX VM");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
130
hw/i386/tdvf-hob.c
Normal file
130
hw/i386/tdvf-hob.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Intel Corporation
|
||||
* Author: Isaku Yamahata <isaku.yamahata at gmail.com>
|
||||
* <isaku.yamahata at intel.com>
|
||||
* Xiaoyao Li <xiaoyao.li@intel.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "standard-headers/uefi/uefi.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "tdvf-hob.h"
|
||||
|
||||
typedef struct TdvfHob {
|
||||
hwaddr hob_addr;
|
||||
void *ptr;
|
||||
int size;
|
||||
|
||||
/* working area */
|
||||
void *current;
|
||||
void *end;
|
||||
} TdvfHob;
|
||||
|
||||
static uint64_t tdvf_current_guest_addr(const TdvfHob *hob)
|
||||
{
|
||||
return hob->hob_addr + (hob->current - hob->ptr);
|
||||
}
|
||||
|
||||
static void tdvf_align(TdvfHob *hob, size_t align)
|
||||
{
|
||||
hob->current = QEMU_ALIGN_PTR_UP(hob->current, align);
|
||||
}
|
||||
|
||||
static void *tdvf_get_area(TdvfHob *hob, uint64_t size)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (hob->current + size > hob->end) {
|
||||
error_report("TD_HOB overrun, size = 0x%" PRIx64, size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = hob->current;
|
||||
hob->current += size;
|
||||
tdvf_align(hob, 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tdvf_hob_add_memory_resources(TdxGuest *tdx, TdvfHob *hob)
|
||||
{
|
||||
EFI_HOB_RESOURCE_DESCRIPTOR *region;
|
||||
EFI_RESOURCE_ATTRIBUTE_TYPE attr;
|
||||
EFI_RESOURCE_TYPE resource_type;
|
||||
|
||||
TdxRamEntry *e;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tdx->nr_ram_entries; i++) {
|
||||
e = &tdx->ram_entries[i];
|
||||
|
||||
if (e->type == TDX_RAM_UNACCEPTED) {
|
||||
resource_type = EFI_RESOURCE_MEMORY_UNACCEPTED;
|
||||
attr = EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED;
|
||||
} else if (e->type == TDX_RAM_ADDED) {
|
||||
resource_type = EFI_RESOURCE_SYSTEM_MEMORY;
|
||||
attr = EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE;
|
||||
} else {
|
||||
error_report("unknown TDX_RAM_ENTRY type %d", e->type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
region = tdvf_get_area(hob, sizeof(*region));
|
||||
*region = (EFI_HOB_RESOURCE_DESCRIPTOR) {
|
||||
.Header = {
|
||||
.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
|
||||
.HobLength = cpu_to_le16(sizeof(*region)),
|
||||
.Reserved = cpu_to_le32(0),
|
||||
},
|
||||
.Owner = EFI_HOB_OWNER_ZERO,
|
||||
.ResourceType = cpu_to_le32(resource_type),
|
||||
.ResourceAttribute = cpu_to_le32(attr),
|
||||
.PhysicalStart = cpu_to_le64(e->address),
|
||||
.ResourceLength = cpu_to_le64(e->length),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob)
|
||||
{
|
||||
TdvfHob hob = {
|
||||
.hob_addr = td_hob->address,
|
||||
.size = td_hob->size,
|
||||
.ptr = td_hob->mem_ptr,
|
||||
|
||||
.current = td_hob->mem_ptr,
|
||||
.end = td_hob->mem_ptr + td_hob->size,
|
||||
};
|
||||
|
||||
EFI_HOB_GENERIC_HEADER *last_hob;
|
||||
EFI_HOB_HANDOFF_INFO_TABLE *hit;
|
||||
|
||||
/* Note, Efi{Free}Memory{Bottom,Top} are ignored, leave 'em zeroed. */
|
||||
hit = tdvf_get_area(&hob, sizeof(*hit));
|
||||
*hit = (EFI_HOB_HANDOFF_INFO_TABLE) {
|
||||
.Header = {
|
||||
.HobType = EFI_HOB_TYPE_HANDOFF,
|
||||
.HobLength = cpu_to_le16(sizeof(*hit)),
|
||||
.Reserved = cpu_to_le32(0),
|
||||
},
|
||||
.Version = cpu_to_le32(EFI_HOB_HANDOFF_TABLE_VERSION),
|
||||
.BootMode = cpu_to_le32(0),
|
||||
.EfiMemoryTop = cpu_to_le64(0),
|
||||
.EfiMemoryBottom = cpu_to_le64(0),
|
||||
.EfiFreeMemoryTop = cpu_to_le64(0),
|
||||
.EfiFreeMemoryBottom = cpu_to_le64(0),
|
||||
.EfiEndOfHobList = cpu_to_le64(0), /* initialized later */
|
||||
};
|
||||
|
||||
tdvf_hob_add_memory_resources(tdx, &hob);
|
||||
|
||||
last_hob = tdvf_get_area(&hob, sizeof(*last_hob));
|
||||
*last_hob = (EFI_HOB_GENERIC_HEADER) {
|
||||
.HobType = EFI_HOB_TYPE_END_OF_HOB_LIST,
|
||||
.HobLength = cpu_to_le16(sizeof(*last_hob)),
|
||||
.Reserved = cpu_to_le32(0),
|
||||
};
|
||||
hit->EfiEndOfHobList = tdvf_current_guest_addr(&hob);
|
||||
}
|
26
hw/i386/tdvf-hob.h
Normal file
26
hw/i386/tdvf-hob.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef HW_I386_TD_HOB_H
|
||||
#define HW_I386_TD_HOB_H
|
||||
|
||||
#include "hw/i386/tdvf.h"
|
||||
#include "target/i386/kvm/tdx.h"
|
||||
|
||||
void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob);
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE \
|
||||
(EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
||||
EFI_RESOURCE_ATTRIBUTE_TESTED)
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED \
|
||||
(EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
||||
EFI_RESOURCE_ATTRIBUTE_TESTED)
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TDVF_MMIO \
|
||||
(EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
||||
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE)
|
||||
|
||||
#endif
|
189
hw/i386/tdvf.c
Normal file
189
hw/i386/tdvf.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Intel Corporation
|
||||
* Author: Isaku Yamahata <isaku.yamahata at gmail.com>
|
||||
* <isaku.yamahata at intel.com>
|
||||
* Xiaoyao Li <xiaoyao.li@intel.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/tdvf.h"
|
||||
#include "system/kvm.h"
|
||||
|
||||
#define TDX_METADATA_OFFSET_GUID "e47a6535-984a-4798-865e-4685a7bf8ec2"
|
||||
#define TDX_METADATA_VERSION 1
|
||||
#define TDVF_SIGNATURE 0x46564454 /* TDVF as little endian */
|
||||
#define TDVF_ALIGNMENT 4096
|
||||
|
||||
/*
|
||||
* the raw structs read from TDVF keeps the name convention in
|
||||
* TDVF Design Guide spec.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t DataOffset;
|
||||
uint32_t RawDataSize;
|
||||
uint64_t MemoryAddress;
|
||||
uint64_t MemoryDataSize;
|
||||
uint32_t Type;
|
||||
uint32_t Attributes;
|
||||
} TdvfSectionEntry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t Signature;
|
||||
uint32_t Length;
|
||||
uint32_t Version;
|
||||
uint32_t NumberOfSectionEntries;
|
||||
TdvfSectionEntry SectionEntries[];
|
||||
} TdvfMetadata;
|
||||
|
||||
struct tdx_metadata_offset {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
static TdvfMetadata *tdvf_get_metadata(void *flash_ptr, int size)
|
||||
{
|
||||
TdvfMetadata *metadata;
|
||||
uint32_t offset = 0;
|
||||
uint8_t *data;
|
||||
|
||||
if ((uint32_t) size != size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pc_system_ovmf_table_find(TDX_METADATA_OFFSET_GUID, &data, NULL)) {
|
||||
offset = size - le32_to_cpu(((struct tdx_metadata_offset *)data)->offset);
|
||||
|
||||
if (offset + sizeof(*metadata) > size) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
error_report("Cannot find TDX_METADATA_OFFSET_GUID");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
metadata = flash_ptr + offset;
|
||||
|
||||
/* Finally, verify the signature to determine if this is a TDVF image. */
|
||||
metadata->Signature = le32_to_cpu(metadata->Signature);
|
||||
if (metadata->Signature != TDVF_SIGNATURE) {
|
||||
error_report("Invalid TDVF signature in metadata!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sanity check that the TDVF doesn't overlap its own metadata. */
|
||||
metadata->Length = le32_to_cpu(metadata->Length);
|
||||
if (offset + metadata->Length > size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Only version 1 is supported/defined. */
|
||||
metadata->Version = le32_to_cpu(metadata->Version);
|
||||
if (metadata->Version != TDX_METADATA_VERSION) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
static int tdvf_parse_and_check_section_entry(const TdvfSectionEntry *src,
|
||||
TdxFirmwareEntry *entry)
|
||||
{
|
||||
entry->data_offset = le32_to_cpu(src->DataOffset);
|
||||
entry->data_len = le32_to_cpu(src->RawDataSize);
|
||||
entry->address = le64_to_cpu(src->MemoryAddress);
|
||||
entry->size = le64_to_cpu(src->MemoryDataSize);
|
||||
entry->type = le32_to_cpu(src->Type);
|
||||
entry->attributes = le32_to_cpu(src->Attributes);
|
||||
|
||||
/* sanity check */
|
||||
if (entry->size < entry->data_len) {
|
||||
error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%lx",
|
||||
entry->data_len, entry->size);
|
||||
return -1;
|
||||
}
|
||||
if (!QEMU_IS_ALIGNED(entry->address, TDVF_ALIGNMENT)) {
|
||||
error_report("MemoryAddress 0x%lx not page aligned", entry->address);
|
||||
return -1;
|
||||
}
|
||||
if (!QEMU_IS_ALIGNED(entry->size, TDVF_ALIGNMENT)) {
|
||||
error_report("MemoryDataSize 0x%lx not page aligned", entry->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (entry->type) {
|
||||
case TDVF_SECTION_TYPE_BFV:
|
||||
case TDVF_SECTION_TYPE_CFV:
|
||||
/* The sections that must be copied from firmware image to TD memory */
|
||||
if (entry->data_len == 0) {
|
||||
error_report("%d section with RawDataSize == 0", entry->type);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case TDVF_SECTION_TYPE_TD_HOB:
|
||||
case TDVF_SECTION_TYPE_TEMP_MEM:
|
||||
/* The sections that no need to be copied from firmware image */
|
||||
if (entry->data_len != 0) {
|
||||
error_report("%d section with RawDataSize 0x%x != 0",
|
||||
entry->type, entry->data_len);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_report("TDVF contains unsupported section type %d", entry->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size)
|
||||
{
|
||||
g_autofree TdvfSectionEntry *sections = NULL;
|
||||
TdvfMetadata *metadata;
|
||||
ssize_t entries_size;
|
||||
int i;
|
||||
|
||||
metadata = tdvf_get_metadata(flash_ptr, size);
|
||||
if (!metadata) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* load and parse metadata entries */
|
||||
fw->nr_entries = le32_to_cpu(metadata->NumberOfSectionEntries);
|
||||
if (fw->nr_entries < 2) {
|
||||
error_report("Invalid number of fw entries (%u) in TDVF Metadata",
|
||||
fw->nr_entries);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entries_size = fw->nr_entries * sizeof(TdvfSectionEntry);
|
||||
if (metadata->Length != sizeof(*metadata) + entries_size) {
|
||||
error_report("TDVF metadata len (0x%x) mismatch, expected (0x%x)",
|
||||
metadata->Length,
|
||||
(uint32_t)(sizeof(*metadata) + entries_size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw->entries = g_new(TdxFirmwareEntry, fw->nr_entries);
|
||||
sections = g_new(TdvfSectionEntry, fw->nr_entries);
|
||||
|
||||
memcpy(sections, (void *)metadata + sizeof(*metadata), entries_size);
|
||||
|
||||
for (i = 0; i < fw->nr_entries; i++) {
|
||||
if (tdvf_parse_and_check_section_entry(§ions[i], &fw->entries[i])) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
fw->mem_ptr = flash_ptr;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fw->entries = 0;
|
||||
g_free(fw->entries);
|
||||
return -EINVAL;
|
||||
}
|
|
@ -44,6 +44,7 @@
|
|||
#include "standard-headers/asm-x86/bootparam.h"
|
||||
#include CONFIG_DEVICES
|
||||
#include "kvm/kvm_i386.h"
|
||||
#include "kvm/tdx.h"
|
||||
|
||||
#ifdef CONFIG_XEN_EMU
|
||||
#include "hw/xen/xen.h"
|
||||
|
@ -1035,11 +1036,14 @@ void x86_bios_rom_init(X86MachineState *x86ms, const char *default_firmware,
|
|||
if (machine_require_guest_memfd(MACHINE(x86ms))) {
|
||||
memory_region_init_ram_guest_memfd(&x86ms->bios, NULL, "pc.bios",
|
||||
bios_size, &error_fatal);
|
||||
if (is_tdx_vm()) {
|
||||
tdx_set_tdvf_region(&x86ms->bios);
|
||||
}
|
||||
} else {
|
||||
memory_region_init_ram(&x86ms->bios, NULL, "pc.bios",
|
||||
bios_size, &error_fatal);
|
||||
}
|
||||
if (sev_enabled()) {
|
||||
if (sev_enabled() || is_tdx_vm()) {
|
||||
/*
|
||||
* The concept of a "reset" simply doesn't exist for
|
||||
* confidential computing guests, we have to destroy and
|
||||
|
|
|
@ -36,15 +36,7 @@ static inline G_GNUC_PRINTF(1, 2) int DPRINTF(const char *fmt, ...)
|
|||
}
|
||||
#endif
|
||||
|
||||
#define __le16 uint16_t
|
||||
#define __le32 uint32_t
|
||||
#define __le64 uint64_t
|
||||
|
||||
#define __be16 uint16_t
|
||||
#define __be32 uint32_t
|
||||
#define __be64 uint64_t
|
||||
|
||||
static inline bool ipv4_addr_is_multicast(__be32 addr)
|
||||
static inline bool ipv4_addr_is_multicast(uint32_t addr)
|
||||
{
|
||||
return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
|
||||
}
|
||||
|
@ -52,8 +44,8 @@ static inline bool ipv4_addr_is_multicast(__be32 addr)
|
|||
typedef struct ipv6_addr {
|
||||
union {
|
||||
uint8_t addr8[16];
|
||||
__be16 addr16[8];
|
||||
__be32 addr32[4];
|
||||
uint16_t addr16[8];
|
||||
uint32_t addr32[4];
|
||||
};
|
||||
} Ipv6Addr;
|
||||
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
#ifndef ROCKER_HW_H
|
||||
#define ROCKER_HW_H
|
||||
|
||||
#define __le16 uint16_t
|
||||
#define __le32 uint32_t
|
||||
#define __le64 uint64_t
|
||||
|
||||
/*
|
||||
* Return codes
|
||||
*/
|
||||
|
@ -124,12 +120,12 @@ enum {
|
|||
*/
|
||||
|
||||
typedef struct rocker_desc {
|
||||
__le64 buf_addr;
|
||||
uint64_t buf_addr;
|
||||
uint64_t cookie;
|
||||
__le16 buf_size;
|
||||
__le16 tlv_size;
|
||||
__le16 rsvd[5]; /* pad to 32 bytes */
|
||||
__le16 comp_err;
|
||||
uint16_t buf_size;
|
||||
uint16_t tlv_size;
|
||||
uint16_t rsvd[5]; /* pad to 32 bytes */
|
||||
uint16_t comp_err;
|
||||
} __attribute__((packed, aligned(8))) RockerDesc;
|
||||
|
||||
/*
|
||||
|
@ -137,9 +133,9 @@ typedef struct rocker_desc {
|
|||
*/
|
||||
|
||||
typedef struct rocker_tlv {
|
||||
__le32 type;
|
||||
__le16 len;
|
||||
__le16 rsvd;
|
||||
uint32_t type;
|
||||
uint16_t len;
|
||||
uint16_t rsvd;
|
||||
} __attribute__((packed, aligned(8))) RockerTlv;
|
||||
|
||||
/* cmd msg */
|
||||
|
|
|
@ -52,10 +52,10 @@ typedef struct of_dpa_flow_key {
|
|||
uint32_t tunnel_id; /* overlay tunnel id */
|
||||
uint32_t tbl_id; /* table id */
|
||||
struct {
|
||||
__be16 vlan_id; /* 0 if no VLAN */
|
||||
uint16_t vlan_id; /* 0 if no VLAN */
|
||||
MACAddr src; /* ethernet source address */
|
||||
MACAddr dst; /* ethernet destination address */
|
||||
__be16 type; /* ethernet frame type */
|
||||
uint16_t type; /* ethernet frame type */
|
||||
} eth;
|
||||
struct {
|
||||
uint8_t proto; /* IP protocol or ARP opcode */
|
||||
|
@ -66,14 +66,14 @@ typedef struct of_dpa_flow_key {
|
|||
union {
|
||||
struct {
|
||||
struct {
|
||||
__be32 src; /* IP source address */
|
||||
__be32 dst; /* IP destination address */
|
||||
uint32_t src; /* IP source address */
|
||||
uint32_t dst; /* IP destination address */
|
||||
} addr;
|
||||
union {
|
||||
struct {
|
||||
__be16 src; /* TCP/UDP/SCTP source port */
|
||||
__be16 dst; /* TCP/UDP/SCTP destination port */
|
||||
__be16 flags; /* TCP flags */
|
||||
uint16_t src; /* TCP/UDP/SCTP source port */
|
||||
uint16_t dst; /* TCP/UDP/SCTP destination port */
|
||||
uint16_t flags; /* TCP flags */
|
||||
} tp;
|
||||
struct {
|
||||
MACAddr sha; /* ARP source hardware address */
|
||||
|
@ -86,11 +86,11 @@ typedef struct of_dpa_flow_key {
|
|||
Ipv6Addr src; /* IPv6 source address */
|
||||
Ipv6Addr dst; /* IPv6 destination address */
|
||||
} addr;
|
||||
__be32 label; /* IPv6 flow label */
|
||||
uint32_t label; /* IPv6 flow label */
|
||||
struct {
|
||||
__be16 src; /* TCP/UDP/SCTP source port */
|
||||
__be16 dst; /* TCP/UDP/SCTP destination port */
|
||||
__be16 flags; /* TCP flags */
|
||||
uint16_t src; /* TCP/UDP/SCTP source port */
|
||||
uint16_t dst; /* TCP/UDP/SCTP destination port */
|
||||
uint16_t flags; /* TCP flags */
|
||||
} tp;
|
||||
struct {
|
||||
Ipv6Addr target; /* ND target address */
|
||||
|
@ -112,13 +112,13 @@ typedef struct of_dpa_flow_action {
|
|||
struct {
|
||||
uint32_t group_id;
|
||||
uint32_t tun_log_lport;
|
||||
__be16 vlan_id;
|
||||
uint16_t vlan_id;
|
||||
} write;
|
||||
struct {
|
||||
__be16 new_vlan_id;
|
||||
uint16_t new_vlan_id;
|
||||
uint32_t out_pport;
|
||||
uint8_t copy_to_cpu;
|
||||
__be16 vlan_id;
|
||||
uint16_t vlan_id;
|
||||
} apply;
|
||||
} OfDpaFlowAction;
|
||||
|
||||
|
@ -143,7 +143,7 @@ typedef struct of_dpa_flow {
|
|||
typedef struct of_dpa_flow_pkt_fields {
|
||||
uint32_t tunnel_id;
|
||||
struct eth_header *ethhdr;
|
||||
__be16 *h_proto;
|
||||
uint16_t *h_proto;
|
||||
struct vlan_header *vlanhdr;
|
||||
struct ip_header *ipv4hdr;
|
||||
struct ip6_header *ipv6hdr;
|
||||
|
@ -180,7 +180,7 @@ typedef struct of_dpa_group {
|
|||
uint32_t group_id;
|
||||
MACAddr src_mac;
|
||||
MACAddr dst_mac;
|
||||
__be16 vlan_id;
|
||||
uint16_t vlan_id;
|
||||
} l2_rewrite;
|
||||
struct {
|
||||
uint16_t group_count;
|
||||
|
@ -190,13 +190,13 @@ typedef struct of_dpa_group {
|
|||
uint32_t group_id;
|
||||
MACAddr src_mac;
|
||||
MACAddr dst_mac;
|
||||
__be16 vlan_id;
|
||||
uint16_t vlan_id;
|
||||
uint8_t ttl_check;
|
||||
} l3_unicast;
|
||||
};
|
||||
} OfDpaGroup;
|
||||
|
||||
static int of_dpa_mask2prefix(__be32 mask)
|
||||
static int of_dpa_mask2prefix(uint32_t mask)
|
||||
{
|
||||
int i;
|
||||
int count = 32;
|
||||
|
@ -451,7 +451,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
|
|||
fc->iovcnt = iovcnt + 2;
|
||||
}
|
||||
|
||||
static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id)
|
||||
static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, uint16_t vlan_id)
|
||||
{
|
||||
OfDpaFlowPktFields *fields = &fc->fields;
|
||||
uint16_t h_proto = fields->ethhdr->h_proto;
|
||||
|
@ -486,7 +486,7 @@ static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc)
|
|||
|
||||
static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc,
|
||||
uint8_t *src_mac, uint8_t *dst_mac,
|
||||
__be16 vlan_id)
|
||||
uint16_t vlan_id)
|
||||
{
|
||||
OfDpaFlowPktFields *fields = &fc->fields;
|
||||
|
||||
|
|
166
hw/timer/hpet.c
166
hw/timer/hpet.c
|
@ -426,30 +426,11 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
|
|||
uint64_t cur_tick;
|
||||
|
||||
trace_hpet_ram_read(addr);
|
||||
addr &= ~4;
|
||||
|
||||
/*address range of all TN regs*/
|
||||
if (addr >= 0x100 && addr <= 0x3ff) {
|
||||
uint8_t timer_id = (addr - 0x100) / 0x20;
|
||||
HPETTimer *timer = &s->timer[timer_id];
|
||||
|
||||
if (timer_id > s->num_timers) {
|
||||
trace_hpet_timer_id_out_of_range(timer_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (addr & 0x18) {
|
||||
case HPET_TN_CFG: // including interrupt capabilities
|
||||
return timer->config >> shift;
|
||||
case HPET_TN_CMP: // comparator register
|
||||
return timer->cmp >> shift;
|
||||
case HPET_TN_ROUTE:
|
||||
return timer->fsb >> shift;
|
||||
default:
|
||||
trace_hpet_ram_read_invalid();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (addr & ~4) {
|
||||
/*address range of all global regs*/
|
||||
if (addr <= 0xff) {
|
||||
switch (addr) {
|
||||
case HPET_ID: // including HPET_PERIOD
|
||||
return s->capability >> shift;
|
||||
case HPET_CFG:
|
||||
|
@ -468,6 +449,26 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
|
|||
trace_hpet_ram_read_invalid();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
uint8_t timer_id = (addr - 0x100) / 0x20;
|
||||
HPETTimer *timer = &s->timer[timer_id];
|
||||
|
||||
if (timer_id > s->num_timers) {
|
||||
trace_hpet_timer_id_out_of_range(timer_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (addr & 0x1f) {
|
||||
case HPET_TN_CFG: // including interrupt capabilities
|
||||
return timer->config >> shift;
|
||||
case HPET_TN_CMP: // comparator register
|
||||
return timer->cmp >> shift;
|
||||
case HPET_TN_ROUTE:
|
||||
return timer->fsb >> shift;
|
||||
default:
|
||||
trace_hpet_ram_read_invalid();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -482,9 +483,67 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
|
|||
uint64_t old_val, new_val, cleared;
|
||||
|
||||
trace_hpet_ram_write(addr, value);
|
||||
addr &= ~4;
|
||||
|
||||
/*address range of all TN regs*/
|
||||
if (addr >= 0x100 && addr <= 0x3ff) {
|
||||
/*address range of all global regs*/
|
||||
if (addr <= 0xff) {
|
||||
switch (addr) {
|
||||
case HPET_ID:
|
||||
return;
|
||||
case HPET_CFG:
|
||||
old_val = s->config;
|
||||
new_val = deposit64(old_val, shift, len, value);
|
||||
new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
|
||||
s->config = new_val;
|
||||
if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
||||
/* Enable main counter and interrupt generation. */
|
||||
s->hpet_offset =
|
||||
ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
for (i = 0; i < s->num_timers; i++) {
|
||||
if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
|
||||
update_irq(&s->timer[i], 1);
|
||||
}
|
||||
hpet_set_timer(&s->timer[i]);
|
||||
}
|
||||
} else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
||||
/* Halt main counter and disable interrupt generation. */
|
||||
s->hpet_counter = hpet_get_ticks(s);
|
||||
for (i = 0; i < s->num_timers; i++) {
|
||||
hpet_del_timer(&s->timer[i]);
|
||||
}
|
||||
}
|
||||
/* i8254 and RTC output pins are disabled
|
||||
* when HPET is in legacy mode */
|
||||
if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
||||
qemu_set_irq(s->pit_enabled, 0);
|
||||
qemu_irq_lower(s->irqs[0]);
|
||||
qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
|
||||
} else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
||||
qemu_irq_lower(s->irqs[0]);
|
||||
qemu_set_irq(s->pit_enabled, 1);
|
||||
qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
|
||||
}
|
||||
break;
|
||||
case HPET_STATUS:
|
||||
new_val = value << shift;
|
||||
cleared = new_val & s->isr;
|
||||
for (i = 0; i < s->num_timers; i++) {
|
||||
if (cleared & (1 << i)) {
|
||||
update_irq(&s->timer[i], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HPET_COUNTER:
|
||||
if (hpet_enabled(s)) {
|
||||
trace_hpet_ram_write_counter_write_while_enabled();
|
||||
}
|
||||
s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
|
||||
break;
|
||||
default:
|
||||
trace_hpet_ram_write_invalid();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
uint8_t timer_id = (addr - 0x100) / 0x20;
|
||||
HPETTimer *timer = &s->timer[timer_id];
|
||||
|
||||
|
@ -550,63 +609,6 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
|
|||
break;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
switch (addr & ~4) {
|
||||
case HPET_ID:
|
||||
return;
|
||||
case HPET_CFG:
|
||||
old_val = s->config;
|
||||
new_val = deposit64(old_val, shift, len, value);
|
||||
new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
|
||||
s->config = new_val;
|
||||
if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
||||
/* Enable main counter and interrupt generation. */
|
||||
s->hpet_offset =
|
||||
ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
for (i = 0; i < s->num_timers; i++) {
|
||||
if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
|
||||
update_irq(&s->timer[i], 1);
|
||||
}
|
||||
hpet_set_timer(&s->timer[i]);
|
||||
}
|
||||
} else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
||||
/* Halt main counter and disable interrupt generation. */
|
||||
s->hpet_counter = hpet_get_ticks(s);
|
||||
for (i = 0; i < s->num_timers; i++) {
|
||||
hpet_del_timer(&s->timer[i]);
|
||||
}
|
||||
}
|
||||
/* i8254 and RTC output pins are disabled
|
||||
* when HPET is in legacy mode */
|
||||
if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
||||
qemu_set_irq(s->pit_enabled, 0);
|
||||
qemu_irq_lower(s->irqs[0]);
|
||||
qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
|
||||
} else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
||||
qemu_irq_lower(s->irqs[0]);
|
||||
qemu_set_irq(s->pit_enabled, 1);
|
||||
qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
|
||||
}
|
||||
break;
|
||||
case HPET_STATUS:
|
||||
new_val = value << shift;
|
||||
cleared = new_val & s->isr;
|
||||
for (i = 0; i < s->num_timers; i++) {
|
||||
if (cleared & (1 << i)) {
|
||||
update_irq(&s->timer[i], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HPET_COUNTER:
|
||||
if (hpet_enabled(s)) {
|
||||
trace_hpet_ram_write_counter_write_while_enabled();
|
||||
}
|
||||
s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
|
||||
break;
|
||||
default:
|
||||
trace_hpet_ram_write_invalid();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
45
include/hw/i386/tdvf.h
Normal file
45
include/hw/i386/tdvf.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Intel Corporation
|
||||
* Author: Isaku Yamahata <isaku.yamahata at gmail.com>
|
||||
* <isaku.yamahata at intel.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_I386_TDVF_H
|
||||
#define HW_I386_TDVF_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#define TDVF_SECTION_TYPE_BFV 0
|
||||
#define TDVF_SECTION_TYPE_CFV 1
|
||||
#define TDVF_SECTION_TYPE_TD_HOB 2
|
||||
#define TDVF_SECTION_TYPE_TEMP_MEM 3
|
||||
|
||||
#define TDVF_SECTION_ATTRIBUTES_MR_EXTEND (1U << 0)
|
||||
#define TDVF_SECTION_ATTRIBUTES_PAGE_AUG (1U << 1)
|
||||
|
||||
typedef struct TdxFirmwareEntry {
|
||||
uint32_t data_offset;
|
||||
uint32_t data_len;
|
||||
uint64_t address;
|
||||
uint64_t size;
|
||||
uint32_t type;
|
||||
uint32_t attributes;
|
||||
|
||||
void *mem_ptr;
|
||||
} TdxFirmwareEntry;
|
||||
|
||||
typedef struct TdxFirmware {
|
||||
void *mem_ptr;
|
||||
|
||||
uint32_t nr_entries;
|
||||
TdxFirmwareEntry *entries;
|
||||
} TdxFirmware;
|
||||
|
||||
#define for_each_tdx_fw_entry(fw, e) \
|
||||
for (e = (fw)->entries; e != (fw)->entries + (fw)->nr_entries; e++)
|
||||
|
||||
int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size);
|
||||
|
||||
#endif /* HW_I386_TDVF_H */
|
187
include/standard-headers/uefi/uefi.h
Normal file
187
include/standard-headers/uefi/uefi.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*
|
||||
* Author: Isaku Yamahata <isaku.yamahata at gmail.com>
|
||||
* <isaku.yamahata at intel.com>
|
||||
* Xiaoyao Li <xiaoyao.li@intel.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_I386_UEFI_H
|
||||
#define HW_I386_UEFI_H
|
||||
|
||||
/***************************************************************************/
|
||||
/*
|
||||
* basic EFI definitions
|
||||
* supplemented with UEFI Specification Version 2.8 (Errata A)
|
||||
* released February 2020
|
||||
*/
|
||||
/* UEFI integer is little endian */
|
||||
|
||||
typedef struct {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} EFI_GUID;
|
||||
|
||||
typedef enum {
|
||||
EfiReservedMemoryType,
|
||||
EfiLoaderCode,
|
||||
EfiLoaderData,
|
||||
EfiBootServicesCode,
|
||||
EfiBootServicesData,
|
||||
EfiRuntimeServicesCode,
|
||||
EfiRuntimeServicesData,
|
||||
EfiConventionalMemory,
|
||||
EfiUnusableMemory,
|
||||
EfiACPIReclaimMemory,
|
||||
EfiACPIMemoryNVS,
|
||||
EfiMemoryMappedIO,
|
||||
EfiMemoryMappedIOPortSpace,
|
||||
EfiPalCode,
|
||||
EfiPersistentMemory,
|
||||
EfiUnacceptedMemoryType,
|
||||
EfiMaxMemoryType
|
||||
} EFI_MEMORY_TYPE;
|
||||
|
||||
#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009
|
||||
|
||||
#define EFI_HOB_TYPE_HANDOFF 0x0001
|
||||
#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002
|
||||
#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003
|
||||
#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004
|
||||
#define EFI_HOB_TYPE_FV 0x0005
|
||||
#define EFI_HOB_TYPE_CPU 0x0006
|
||||
#define EFI_HOB_TYPE_MEMORY_POOL 0x0007
|
||||
#define EFI_HOB_TYPE_FV2 0x0009
|
||||
#define EFI_HOB_TYPE_LOAD_PEIM_UNUSED 0x000A
|
||||
#define EFI_HOB_TYPE_UEFI_CAPSULE 0x000B
|
||||
#define EFI_HOB_TYPE_FV3 0x000C
|
||||
#define EFI_HOB_TYPE_UNUSED 0xFFFE
|
||||
#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF
|
||||
|
||||
typedef struct {
|
||||
uint16_t HobType;
|
||||
uint16_t HobLength;
|
||||
uint32_t Reserved;
|
||||
} EFI_HOB_GENERIC_HEADER;
|
||||
|
||||
typedef uint64_t EFI_PHYSICAL_ADDRESS;
|
||||
typedef uint32_t EFI_BOOT_MODE;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
uint32_t Version;
|
||||
EFI_BOOT_MODE BootMode;
|
||||
EFI_PHYSICAL_ADDRESS EfiMemoryTop;
|
||||
EFI_PHYSICAL_ADDRESS EfiMemoryBottom;
|
||||
EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop;
|
||||
EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom;
|
||||
EFI_PHYSICAL_ADDRESS EfiEndOfHobList;
|
||||
} EFI_HOB_HANDOFF_INFO_TABLE;
|
||||
|
||||
#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000
|
||||
#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001
|
||||
#define EFI_RESOURCE_IO 0x00000002
|
||||
#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003
|
||||
#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004
|
||||
#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005
|
||||
#define EFI_RESOURCE_IO_RESERVED 0x00000006
|
||||
#define EFI_RESOURCE_MEMORY_UNACCEPTED 0x00000007
|
||||
#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000008
|
||||
|
||||
#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
|
||||
#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
|
||||
#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
|
||||
#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008
|
||||
#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010
|
||||
#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020
|
||||
#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040
|
||||
#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
|
||||
#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100
|
||||
#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200
|
||||
#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
|
||||
#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
|
||||
#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED 0x00040000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE 0x00080000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE 0x00100000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE 0x00200000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE 0x00400000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_PERSISTENT 0x00800000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_PERSISTABLE 0x01000000
|
||||
#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE 0x02000000
|
||||
|
||||
typedef uint32_t EFI_RESOURCE_TYPE;
|
||||
typedef uint32_t EFI_RESOURCE_ATTRIBUTE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
EFI_GUID Owner;
|
||||
EFI_RESOURCE_TYPE ResourceType;
|
||||
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
|
||||
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
||||
uint64_t ResourceLength;
|
||||
} EFI_HOB_RESOURCE_DESCRIPTOR;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
EFI_GUID Name;
|
||||
|
||||
/* guid specific data follows */
|
||||
} EFI_HOB_GUID_TYPE;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
uint64_t Length;
|
||||
} EFI_HOB_FIRMWARE_VOLUME;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
uint64_t Length;
|
||||
EFI_GUID FvName;
|
||||
EFI_GUID FileName;
|
||||
} EFI_HOB_FIRMWARE_VOLUME2;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
uint64_t Length;
|
||||
uint32_t AuthenticationStatus;
|
||||
bool ExtractedFv;
|
||||
EFI_GUID FvName;
|
||||
EFI_GUID FileName;
|
||||
} EFI_HOB_FIRMWARE_VOLUME3;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
uint8_t SizeOfMemorySpace;
|
||||
uint8_t SizeOfIoSpace;
|
||||
uint8_t Reserved[6];
|
||||
} EFI_HOB_CPU;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
} EFI_HOB_MEMORY_POOL;
|
||||
|
||||
typedef struct {
|
||||
EFI_HOB_GENERIC_HEADER Header;
|
||||
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
uint64_t Length;
|
||||
} EFI_HOB_UEFI_CAPSULE;
|
||||
|
||||
#define EFI_HOB_OWNER_ZERO \
|
||||
((EFI_GUID){ 0x00000000, 0x0000, 0x0000, \
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
|
||||
|
||||
#endif
|
|
@ -376,6 +376,7 @@ int kvm_arch_get_default_type(MachineState *ms);
|
|||
|
||||
int kvm_arch_init(MachineState *ms, KVMState *s);
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp);
|
||||
int kvm_arch_init_vcpu(CPUState *cpu);
|
||||
int kvm_arch_destroy_vcpu(CPUState *cpu);
|
||||
|
||||
|
|
122
meson.build
122
meson.build
|
@ -3272,6 +3272,7 @@ config_devices_mak_list = []
|
|||
config_devices_h = {}
|
||||
config_target_h = {}
|
||||
config_target_mak = {}
|
||||
config_base_arch_mak = {}
|
||||
|
||||
disassemblers = {
|
||||
'alpha' : ['CONFIG_ALPHA_DIS'],
|
||||
|
@ -3463,6 +3464,11 @@ foreach target : target_dirs
|
|||
config_all_devices += config_devices
|
||||
endif
|
||||
config_target_mak += {target: config_target}
|
||||
|
||||
# build a merged config for all targets with the same TARGET_BASE_ARCH
|
||||
target_base_arch = config_target['TARGET_BASE_ARCH']
|
||||
config_base_arch = config_base_arch_mak.get(target_base_arch, {}) + config_target
|
||||
config_base_arch_mak += {target_base_arch: config_base_arch}
|
||||
endforeach
|
||||
target_dirs = actual_target_dirs
|
||||
|
||||
|
@ -3718,14 +3724,12 @@ io_ss = ss.source_set()
|
|||
qmp_ss = ss.source_set()
|
||||
qom_ss = ss.source_set()
|
||||
system_ss = ss.source_set()
|
||||
libsystem_ss = ss.source_set()
|
||||
specific_fuzz_ss = ss.source_set()
|
||||
specific_ss = ss.source_set()
|
||||
rust_devices_ss = ss.source_set()
|
||||
stub_ss = ss.source_set()
|
||||
trace_ss = ss.source_set()
|
||||
user_ss = ss.source_set()
|
||||
libuser_ss = ss.source_set()
|
||||
util_ss = ss.source_set()
|
||||
|
||||
# accel modules
|
||||
|
@ -4102,30 +4106,20 @@ common_ss.add(hwcore)
|
|||
system_ss.add(authz, blockdev, chardev, crypto, io, qmp)
|
||||
common_ss.add(qom, qemuutil)
|
||||
|
||||
common_ss.add_all(when: 'CONFIG_SYSTEM_ONLY', if_true: [system_ss])
|
||||
common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss)
|
||||
|
||||
libuser_ss = libuser_ss.apply({})
|
||||
libuser = static_library('user',
|
||||
libuser_ss.sources() + genh,
|
||||
user_ss.all_sources() + genh,
|
||||
c_args: ['-DCONFIG_USER_ONLY',
|
||||
'-DCOMPILING_SYSTEM_VS_USER'],
|
||||
dependencies: libuser_ss.dependencies(),
|
||||
include_directories: common_user_inc,
|
||||
dependencies: user_ss.all_dependencies(),
|
||||
build_by_default: false)
|
||||
libuser = declare_dependency(objects: libuser.extract_all_objects(recursive: false),
|
||||
dependencies: libuser_ss.dependencies())
|
||||
common_ss.add(when: 'CONFIG_USER_ONLY', if_true: libuser)
|
||||
|
||||
libsystem_ss = libsystem_ss.apply({})
|
||||
libsystem = static_library('system',
|
||||
libsystem_ss.sources() + genh,
|
||||
system_ss.all_sources() + genh,
|
||||
c_args: ['-DCONFIG_SOFTMMU',
|
||||
'-DCOMPILING_SYSTEM_VS_USER'],
|
||||
dependencies: libsystem_ss.dependencies(),
|
||||
dependencies: system_ss.all_dependencies(),
|
||||
build_by_default: false)
|
||||
libsystem = declare_dependency(objects: libsystem.extract_all_objects(recursive: false),
|
||||
dependencies: libsystem_ss.dependencies())
|
||||
common_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: libsystem)
|
||||
|
||||
# Note that this library is never used directly (only through extract_objects)
|
||||
# and is not built by default; therefore, source files not used by the build
|
||||
|
@ -4133,65 +4127,71 @@ common_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: libsystem)
|
|||
common_all = static_library('common',
|
||||
build_by_default: false,
|
||||
sources: common_ss.all_sources() + genh,
|
||||
include_directories: common_user_inc,
|
||||
implicit_include_directories: false,
|
||||
dependencies: common_ss.all_dependencies())
|
||||
|
||||
# construct common libraries per base architecture
|
||||
hw_common_arch_libs = {}
|
||||
target_common_arch_libs = {}
|
||||
target_common_system_arch_libs = {}
|
||||
foreach target : target_dirs
|
||||
foreach target_base_arch, config_base_arch : config_base_arch_mak
|
||||
config_target = config_target_mak[target]
|
||||
target_base_arch = config_target['TARGET_BASE_ARCH']
|
||||
target_inc = [include_directories('target' / target_base_arch)]
|
||||
inc = [common_user_inc + target_inc]
|
||||
|
||||
target_common = common_ss.apply(config_target, strict: false)
|
||||
target_system = system_ss.apply(config_target, strict: false)
|
||||
target_user = user_ss.apply(config_target, strict: false)
|
||||
common_deps = []
|
||||
system_deps = []
|
||||
user_deps = []
|
||||
foreach dep: target_common.dependencies()
|
||||
common_deps += dep.partial_dependency(compile_args: true, includes: true)
|
||||
endforeach
|
||||
foreach dep: target_system.dependencies()
|
||||
system_deps += dep.partial_dependency(compile_args: true, includes: true)
|
||||
endforeach
|
||||
foreach dep: target_user.dependencies()
|
||||
user_deps += dep.partial_dependency(compile_args: true, includes: true)
|
||||
endforeach
|
||||
|
||||
# prevent common code to access cpu compile time definition,
|
||||
# but still allow access to cpu.h
|
||||
target_c_args = ['-DCPU_DEFS_H']
|
||||
target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU']
|
||||
|
||||
if target_base_arch in hw_common_arch
|
||||
if target_base_arch not in hw_common_arch_libs
|
||||
src = hw_common_arch[target_base_arch]
|
||||
lib = static_library(
|
||||
'hw_' + target_base_arch,
|
||||
build_by_default: false,
|
||||
sources: src.all_sources() + genh,
|
||||
include_directories: inc,
|
||||
c_args: target_system_c_args,
|
||||
dependencies: src.all_dependencies())
|
||||
hw_common_arch_libs += {target_base_arch: lib}
|
||||
endif
|
||||
if target_base_arch in target_common_arch
|
||||
src = target_common_arch[target_base_arch]
|
||||
lib = static_library(
|
||||
'common_' + target_base_arch,
|
||||
build_by_default: false,
|
||||
sources: src.all_sources() + genh,
|
||||
include_directories: inc,
|
||||
c_args: target_c_args,
|
||||
dependencies: src.all_dependencies() + common_deps +
|
||||
system_deps + user_deps)
|
||||
target_common_arch_libs += {target_base_arch: lib}
|
||||
endif
|
||||
|
||||
if target_base_arch in target_common_arch
|
||||
if target_base_arch not in target_common_arch_libs
|
||||
src = target_common_arch[target_base_arch]
|
||||
lib = static_library(
|
||||
'target_' + target_base_arch,
|
||||
build_by_default: false,
|
||||
sources: src.all_sources() + genh,
|
||||
include_directories: inc,
|
||||
c_args: target_c_args,
|
||||
dependencies: src.all_dependencies())
|
||||
target_common_arch_libs += {target_base_arch: lib}
|
||||
# merge hw_common_arch in target_common_system_arch
|
||||
if target_base_arch in hw_common_arch
|
||||
hw_src = hw_common_arch[target_base_arch]
|
||||
if target_base_arch in target_common_system_arch
|
||||
target_common_system_arch[target_base_arch].add_all(hw_src)
|
||||
else
|
||||
target_common_system_arch += {target_base_arch: hw_src}
|
||||
endif
|
||||
endif
|
||||
|
||||
if target_base_arch in target_common_system_arch
|
||||
if target_base_arch not in target_common_system_arch_libs
|
||||
src = target_common_system_arch[target_base_arch]
|
||||
lib = static_library(
|
||||
'target_system_' + target_base_arch,
|
||||
build_by_default: false,
|
||||
sources: src.all_sources() + genh,
|
||||
include_directories: inc,
|
||||
c_args: target_system_c_args,
|
||||
dependencies: src.all_dependencies())
|
||||
target_common_system_arch_libs += {target_base_arch: lib}
|
||||
endif
|
||||
src = target_common_system_arch[target_base_arch]
|
||||
lib = static_library(
|
||||
'system_' + target_base_arch,
|
||||
build_by_default: false,
|
||||
sources: src.all_sources() + genh,
|
||||
include_directories: inc,
|
||||
c_args: target_system_c_args,
|
||||
dependencies: src.all_dependencies() + common_deps + system_deps)
|
||||
target_common_system_arch_libs += {target_base_arch: lib}
|
||||
endif
|
||||
endforeach
|
||||
|
||||
|
@ -4368,10 +4368,14 @@ foreach target : target_dirs
|
|||
objects += lib.extract_objects(src.sources())
|
||||
arch_deps += src.dependencies()
|
||||
endif
|
||||
if target_type == 'system' and target_base_arch in hw_common_arch_libs
|
||||
src = hw_common_arch[target_base_arch].apply(config_target, strict: false)
|
||||
lib = hw_common_arch_libs[target_base_arch]
|
||||
objects += lib.extract_objects(src.sources())
|
||||
if target_type == 'system'
|
||||
src = system_ss.apply(config_target, strict: false)
|
||||
objects += libsystem.extract_objects(src.sources())
|
||||
arch_deps += src.dependencies()
|
||||
endif
|
||||
if target_type == 'user'
|
||||
src = user_ss.apply(config_target, strict: false)
|
||||
objects += libuser.extract_objects(src.sources())
|
||||
arch_deps += src.dependencies()
|
||||
endif
|
||||
if target_type == 'system' and target_base_arch in target_common_system_arch_libs
|
||||
|
|
|
@ -61,8 +61,8 @@ endif
|
|||
user_ss.add(files('user.c', 'api-user.c'))
|
||||
system_ss.add(files('system.c', 'api-system.c'))
|
||||
|
||||
libuser_ss.add(files('api.c', 'core.c'))
|
||||
libsystem_ss.add(files('api.c', 'core.c'))
|
||||
user_ss.add(files('api.c', 'core.c'))
|
||||
system_ss.add(files('api.c', 'core.c'))
|
||||
|
||||
common_ss.add(files('loader.c'))
|
||||
|
||||
|
|
|
@ -1047,6 +1047,39 @@
|
|||
'*host-data': 'str',
|
||||
'*vcek-disabled': 'bool' } }
|
||||
|
||||
##
|
||||
# @TdxGuestProperties:
|
||||
#
|
||||
# Properties for tdx-guest objects.
|
||||
#
|
||||
# @attributes: The 'attributes' of a TD guest that is passed to
|
||||
# KVM_TDX_INIT_VM
|
||||
#
|
||||
# @sept-ve-disable: toggle bit 28 of TD attributes to control disabling
|
||||
# of EPT violation conversion to #VE on guest TD access of PENDING
|
||||
# pages. Some guest OS (e.g., Linux TD guest) may require this to
|
||||
# be set, otherwise they refuse to boot.
|
||||
#
|
||||
# @mrconfigid: ID for non-owner-defined configuration of the guest TD,
|
||||
# e.g., run-time or OS configuration (base64 encoded SHA384 digest).
|
||||
# Defaults to all zeros.
|
||||
#
|
||||
# @mrowner: ID for the guest TD’s owner (base64 encoded SHA384 digest).
|
||||
# Defaults to all zeros.
|
||||
#
|
||||
# @mrownerconfig: ID for owner-defined configuration of the guest TD,
|
||||
# e.g., specific to the workload rather than the run-time or OS
|
||||
# (base64 encoded SHA384 digest). Defaults to all zeros.
|
||||
#
|
||||
# Since: 10.1
|
||||
##
|
||||
{ 'struct': 'TdxGuestProperties',
|
||||
'data': { '*attributes': 'uint64',
|
||||
'*sept-ve-disable': 'bool',
|
||||
'*mrconfigid': 'str',
|
||||
'*mrowner': 'str',
|
||||
'*mrownerconfig': 'str' } }
|
||||
|
||||
##
|
||||
# @ThreadContextProperties:
|
||||
#
|
||||
|
@ -1132,6 +1165,7 @@
|
|||
'sev-snp-guest',
|
||||
'thread-context',
|
||||
's390-pv-guest',
|
||||
'tdx-guest',
|
||||
'throttle-group',
|
||||
'tls-creds-anon',
|
||||
'tls-creds-psk',
|
||||
|
@ -1204,6 +1238,7 @@
|
|||
'if': 'CONFIG_SECRET_KEYRING' },
|
||||
'sev-guest': 'SevGuestProperties',
|
||||
'sev-snp-guest': 'SevSnpGuestProperties',
|
||||
'tdx-guest': 'TdxGuestProperties',
|
||||
'thread-context': 'ThreadContextProperties',
|
||||
'throttle-group': 'ThrottleGroupProperties',
|
||||
'tls-creds-anon': 'TlsCredsAnonProperties',
|
||||
|
|
|
@ -501,10 +501,12 @@
|
|||
#
|
||||
# @s390: s390 guest panic information type (Since: 2.12)
|
||||
#
|
||||
# @tdx: tdx guest panic information type (Since: 10.1)
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'enum': 'GuestPanicInformationType',
|
||||
'data': [ 'hyper-v', 's390' ] }
|
||||
'data': [ 'hyper-v', 's390', 'tdx' ] }
|
||||
|
||||
##
|
||||
# @GuestPanicInformation:
|
||||
|
@ -519,7 +521,8 @@
|
|||
'base': {'type': 'GuestPanicInformationType'},
|
||||
'discriminator': 'type',
|
||||
'data': {'hyper-v': 'GuestPanicInformationHyperV',
|
||||
's390': 'GuestPanicInformationS390'}}
|
||||
's390': 'GuestPanicInformationS390',
|
||||
'tdx' : 'GuestPanicInformationTdx'}}
|
||||
|
||||
##
|
||||
# @GuestPanicInformationHyperV:
|
||||
|
@ -598,6 +601,30 @@
|
|||
'psw-addr': 'uint64',
|
||||
'reason': 'S390CrashReason'}}
|
||||
|
||||
##
|
||||
# @GuestPanicInformationTdx:
|
||||
#
|
||||
# TDX Guest panic information specific to TDX, as specified in the
|
||||
# "Guest-Hypervisor Communication Interface (GHCI) Specification",
|
||||
# section TDG.VP.VMCALL<ReportFatalError>.
|
||||
#
|
||||
# @error-code: TD-specific error code
|
||||
#
|
||||
# @message: Human-readable error message provided by the guest. Not
|
||||
# to be trusted.
|
||||
#
|
||||
# @gpa: guest-physical address of a page that contains more verbose
|
||||
# error information, as zero-terminated string. Present when the
|
||||
# "GPA valid" bit (bit 63) is set in @error-code.
|
||||
#
|
||||
#
|
||||
# Since: 10.1
|
||||
##
|
||||
{'struct': 'GuestPanicInformationTdx',
|
||||
'data': {'error-code': 'uint32',
|
||||
'message': 'str',
|
||||
'*gpa': 'uint64'}}
|
||||
|
||||
##
|
||||
# @MEMORY_FAILURE:
|
||||
#
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
subproject('bilge-0.2-rs', required: true)
|
||||
subproject('bilge-impl-0.2-rs', required: true)
|
||||
|
||||
bilge_dep = dependency('bilge-0.2-rs')
|
||||
bilge_impl_dep = dependency('bilge-impl-0.2-rs')
|
||||
|
||||
_libpl011_rs = static_library(
|
||||
'pl011',
|
||||
files('src/lib.rs'),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
dependencies: [
|
||||
bilge_dep,
|
||||
bilge_impl_dep,
|
||||
bilge_rs,
|
||||
bilge_impl_rs,
|
||||
qemu_api,
|
||||
qemu_api_macros,
|
||||
],
|
||||
|
@ -21,6 +15,6 @@ rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency(
|
|||
link_whole: [_libpl011_rs],
|
||||
# Putting proc macro crates in `dependencies` is necessary for Meson to find
|
||||
# them when compiling the root per-target static rust lib.
|
||||
dependencies: [bilge_impl_dep, qemu_api_macros],
|
||||
dependencies: [bilge_impl_rs, qemu_api_macros],
|
||||
variables: {'crate': 'pl011'},
|
||||
)])
|
||||
|
|
|
@ -480,13 +480,13 @@ impl PL011Registers {
|
|||
}
|
||||
|
||||
impl PL011State {
|
||||
/// Initializes a pre-allocated, unitialized instance of `PL011State`.
|
||||
/// Initializes a pre-allocated, uninitialized instance of `PL011State`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `self` must point to a correctly sized and aligned location for the
|
||||
/// `PL011State` type. It must not be called more than once on the same
|
||||
/// location/instance. All its fields are expected to hold unitialized
|
||||
/// location/instance. All its fields are expected to hold uninitialized
|
||||
/// values with the sole exception of `parent_obj`.
|
||||
unsafe fn init(&mut self) {
|
||||
static PL011_OPS: MemoryRegionOps<PL011State> = MemoryRegionOpsBuilder::<PL011State>::new()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (C) 2024 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// Author(s): Zhao Liu <zhao1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::{
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (C) 2024 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// Author(s): Zhao Liu <zhao1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::ptr::addr_of_mut;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (C) 2024 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// Author(s): Zhao Liu <zhao1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//! # HPET QEMU Device Model
|
||||
|
@ -7,7 +7,7 @@
|
|||
//! This library implements a device model for the IA-PC HPET (High
|
||||
//! Precision Event Timers) device in QEMU.
|
||||
|
||||
pub mod device;
|
||||
pub mod fw_cfg;
|
||||
pub mod hpet;
|
||||
|
||||
pub const TYPE_HPET: &::std::ffi::CStr = c"hpet";
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
subproject('bilge-0.2-rs', required: true)
|
||||
subproject('bilge-impl-0.2-rs', required: true)
|
||||
subproject('libc-0.2-rs', required: true)
|
||||
|
||||
bilge_rs = dependency('bilge-0.2-rs')
|
||||
bilge_impl_rs = dependency('bilge-impl-0.2-rs')
|
||||
libc_rs = dependency('libc-0.2-rs')
|
||||
|
||||
subproject('proc-macro2-1-rs', required: true)
|
||||
subproject('quote-1-rs', required: true)
|
||||
subproject('syn-2-rs', required: true)
|
||||
|
||||
quote_rs_native = dependency('quote-1-rs', native: true)
|
||||
syn_rs_native = dependency('syn-2-rs', native: true)
|
||||
proc_macro2_rs_native = dependency('proc-macro2-1-rs', native: true)
|
||||
|
||||
subdir('qemu-api-macros')
|
||||
subdir('qemu-api')
|
||||
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
subproject('proc-macro2-1-rs', required: true)
|
||||
subproject('quote-1-rs', required: true)
|
||||
subproject('syn-2-rs', required: true)
|
||||
|
||||
quote_dep = dependency('quote-1-rs', native: true)
|
||||
syn_dep = dependency('syn-2-rs', native: true)
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
|
||||
_qemu_api_macros_rs = rust.proc_macro(
|
||||
'qemu_api_macros',
|
||||
files('src/lib.rs'),
|
||||
|
@ -16,9 +8,9 @@ _qemu_api_macros_rs = rust.proc_macro(
|
|||
'--cfg', 'feature="proc-macro"',
|
||||
],
|
||||
dependencies: [
|
||||
proc_macro2_dep,
|
||||
quote_dep,
|
||||
syn_dep,
|
||||
proc_macro2_rs_native,
|
||||
quote_rs_native,
|
||||
syn_rs_native,
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ _qemu_api_cfg = run_command(rustc_args,
|
|||
'--config-headers', config_host_h, '--features', files('Cargo.toml'),
|
||||
capture: true, check: true).stdout().strip().splitlines()
|
||||
|
||||
libc_dep = dependency('libc-0.2-rs')
|
||||
|
||||
# _qemu_api_cfg += ['--cfg', 'feature="allocator"']
|
||||
if get_option('debug_mutex')
|
||||
_qemu_api_cfg += ['--cfg', 'feature="debug_cell"']
|
||||
|
@ -37,7 +35,7 @@ _qemu_api_rs = static_library(
|
|||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: _qemu_api_cfg,
|
||||
dependencies: [libc_dep, qemu_api_macros],
|
||||
dependencies: [libc_rs, qemu_api_macros],
|
||||
)
|
||||
|
||||
rust.test('rust-qemu-api-tests', _qemu_api_rs,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (C) 2024 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// Author(s): Zhao Liu <zhao1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//! This module provides bit operation extensions to integer types.
|
||||
|
|
|
@ -291,7 +291,7 @@ pub unsafe trait ObjectType: Sized {
|
|||
}
|
||||
|
||||
/// Return the receiver as a const raw pointer to Object.
|
||||
/// This is preferrable to `as_object_mut_ptr()` if a C
|
||||
/// This is preferable to `as_object_mut_ptr()` if a C
|
||||
/// function only needs a `const Object *`.
|
||||
fn as_object_ptr(&self) -> *const bindings::Object {
|
||||
self.as_object().as_ptr()
|
||||
|
@ -485,7 +485,7 @@ pub trait ObjectImpl: ObjectType + IsA<Object> {
|
|||
/// `INSTANCE_INIT` functions have been called.
|
||||
const INSTANCE_POST_INIT: Option<fn(&Self)> = None;
|
||||
|
||||
/// Called on descendent classes after all parent class initialization
|
||||
/// Called on descendant classes after all parent class initialization
|
||||
/// has occurred, but before the class itself is initialized. This
|
||||
/// is only useful if a class is not a leaf, and can be used to undo
|
||||
/// the effects of copying the contents of the parent's class struct
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (C) 2024 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// Author(s): Zhao Liu <zhao1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
//! * [`vmstate_unused!`](crate::vmstate_unused) and
|
||||
//! [`vmstate_of!`](crate::vmstate_of), which are used to express the
|
||||
//! migration format for a struct. This is based on the [`VMState`] trait,
|
||||
//! which is defined by all migrateable types.
|
||||
//! which is defined by all migratable types.
|
||||
//!
|
||||
//! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and
|
||||
//! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (C) 2025 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// Author(s): Zhao Liu <zhao1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::{
|
||||
|
|
|
@ -7,7 +7,7 @@ system_ss.add(files(
|
|||
'vl.c',
|
||||
), sdl, libpmem, libdaxctl)
|
||||
|
||||
libsystem_ss.add(files(
|
||||
system_ss.add(files(
|
||||
'balloon.c',
|
||||
'bootdevice.c',
|
||||
'cpus.c',
|
||||
|
|
|
@ -590,6 +590,58 @@ static void qemu_system_wakeup(void)
|
|||
}
|
||||
}
|
||||
|
||||
static char *tdx_parse_panic_message(char *message)
|
||||
{
|
||||
bool printable = false;
|
||||
char *buf = NULL;
|
||||
int len = 0, i;
|
||||
|
||||
/*
|
||||
* Although message is defined as a json string, we shouldn't
|
||||
* unconditionally treat it as is because the guest generated it and
|
||||
* it's not necessarily trustable.
|
||||
*/
|
||||
if (message) {
|
||||
/* The caller guarantees the NULL-terminated string. */
|
||||
len = strlen(message);
|
||||
|
||||
printable = len > 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!(0x20 <= message[i] && message[i] <= 0x7e)) {
|
||||
printable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
buf = g_malloc(1);
|
||||
buf[0] = '\0';
|
||||
} else {
|
||||
if (!printable) {
|
||||
/* 3 = length of "%02x " */
|
||||
buf = g_malloc(len * 3);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (message[i] == '\0') {
|
||||
break;
|
||||
} else {
|
||||
sprintf(buf + 3 * i, "%02x ", message[i]);
|
||||
}
|
||||
}
|
||||
if (i > 0) {
|
||||
/* replace the last ' '(space) to NULL */
|
||||
buf[i * 3 - 1] = '\0';
|
||||
} else {
|
||||
buf[0] = '\0';
|
||||
}
|
||||
} else {
|
||||
buf = g_strdup(message);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void qemu_system_guest_panicked(GuestPanicInformation *info)
|
||||
{
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed");
|
||||
|
@ -631,7 +683,20 @@ void qemu_system_guest_panicked(GuestPanicInformation *info)
|
|||
S390CrashReason_str(info->u.s390.reason),
|
||||
info->u.s390.psw_mask,
|
||||
info->u.s390.psw_addr);
|
||||
} else if (info->type == GUEST_PANIC_INFORMATION_TYPE_TDX) {
|
||||
char *message = tdx_parse_panic_message(info->u.tdx.message);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"\nTDX guest reports fatal error."
|
||||
" error code: 0x%" PRIx32 " error message:\"%s\"\n",
|
||||
info->u.tdx.error_code, message);
|
||||
g_free(message);
|
||||
if (info->u.tdx.gpa != -1ull) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Additional error information "
|
||||
"can be found at gpa page: 0x%" PRIx64 "\n",
|
||||
info->u.tdx.gpa);
|
||||
}
|
||||
}
|
||||
|
||||
qapi_free_GuestPanicInformation(info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1846,6 +1846,11 @@ static int kvm_arm_sve_set_vls(ARMCPU *cpu)
|
|||
|
||||
#define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
int ret;
|
||||
|
|
|
@ -28,7 +28,7 @@ arm_user_ss.add(files(
|
|||
'vfp_fpscr.c',
|
||||
))
|
||||
|
||||
arm_common_system_ss.add(files('cpu.c'), capstone)
|
||||
arm_common_system_ss.add(files('cpu.c'))
|
||||
arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files(
|
||||
'cpu32-stubs.c'))
|
||||
arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
|
||||
|
|
|
@ -39,8 +39,10 @@ struct X86ConfidentialGuestClass {
|
|||
|
||||
/* <public> */
|
||||
int (*kvm_type)(X86ConfidentialGuest *cg);
|
||||
uint32_t (*mask_cpuid_features)(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index,
|
||||
int reg, uint32_t value);
|
||||
void (*cpu_instance_init)(X86ConfidentialGuest *cg, CPUState *cpu);
|
||||
uint32_t (*adjust_cpuid_features)(X86ConfidentialGuest *cg, uint32_t feature,
|
||||
uint32_t index, int reg, uint32_t value);
|
||||
int (*check_features)(X86ConfidentialGuest *cg, CPUState *cs);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -59,25 +61,47 @@ static inline int x86_confidential_guest_kvm_type(X86ConfidentialGuest *cg)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void x86_confidential_guest_cpu_instance_init(X86ConfidentialGuest *cg,
|
||||
CPUState *cpu)
|
||||
{
|
||||
X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg);
|
||||
|
||||
if (klass->cpu_instance_init) {
|
||||
klass->cpu_instance_init(cg, cpu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* x86_confidential_guest_mask_cpuid_features:
|
||||
* x86_confidential_guest_adjust_cpuid_features:
|
||||
*
|
||||
* Removes unsupported features from a confidential guest's CPUID values, returns
|
||||
* the value with the bits removed. The bits removed should be those that KVM
|
||||
* provides independent of host-supported CPUID features, but are not supported by
|
||||
* the confidential computing firmware.
|
||||
* Adjust the supported features from a confidential guest's CPUID values,
|
||||
* returns the adjusted value. There are bits being removed that are not
|
||||
* supported by the confidential computing firmware or bits being added that
|
||||
* are forcibly exposed to guest by the confidential computing firmware.
|
||||
*/
|
||||
static inline int x86_confidential_guest_mask_cpuid_features(X86ConfidentialGuest *cg,
|
||||
static inline int x86_confidential_guest_adjust_cpuid_features(X86ConfidentialGuest *cg,
|
||||
uint32_t feature, uint32_t index,
|
||||
int reg, uint32_t value)
|
||||
{
|
||||
X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg);
|
||||
|
||||
if (klass->mask_cpuid_features) {
|
||||
return klass->mask_cpuid_features(cg, feature, index, reg, value);
|
||||
if (klass->adjust_cpuid_features) {
|
||||
return klass->adjust_cpuid_features(cg, feature, index, reg, value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int x86_confidential_guest_check_features(X86ConfidentialGuest *cg,
|
||||
CPUState *cs)
|
||||
{
|
||||
X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg);
|
||||
|
||||
if (klass->check_features) {
|
||||
return klass->check_features(cg, cs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "hw/i386/topology.h"
|
||||
#include "exec/watchpoint.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include "confidential-guest.h"
|
||||
#include "system/reset.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "system/address-spaces.h"
|
||||
|
@ -1252,12 +1253,12 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||
[FEAT_8000_0021_EAX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
"no-nested-data-bp", NULL, "lfence-always-serializing", NULL,
|
||||
"no-nested-data-bp", "fs-gs-base-ns", "lfence-always-serializing", NULL,
|
||||
NULL, NULL, "null-sel-clr-base", NULL,
|
||||
"auto-ibrs", NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
"prefetchi", NULL, NULL, NULL,
|
||||
"eraps", NULL, NULL, "sbpb",
|
||||
"ibpb-brtype", "srso-no", "srso-user-kernel-no", NULL,
|
||||
},
|
||||
|
@ -1677,14 +1678,21 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||
},
|
||||
};
|
||||
|
||||
typedef struct FeatureMask {
|
||||
FeatureWord index;
|
||||
uint64_t mask;
|
||||
} FeatureMask;
|
||||
bool is_feature_word_cpuid(uint32_t feature, uint32_t index, int reg)
|
||||
{
|
||||
FeatureWordInfo *wi;
|
||||
FeatureWord w;
|
||||
|
||||
typedef struct FeatureDep {
|
||||
FeatureMask from, to;
|
||||
} FeatureDep;
|
||||
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||
wi = &feature_word_info[w];
|
||||
if (wi->type == CPUID_FEATURE_WORD && wi->cpuid.eax == feature &&
|
||||
(!wi->cpuid.needs_ecx || wi->cpuid.ecx == index) &&
|
||||
wi->cpuid.reg == reg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static FeatureDep feature_dependencies[] = {
|
||||
{
|
||||
|
@ -1854,9 +1862,6 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
|
|||
};
|
||||
#undef REGISTER
|
||||
|
||||
/* CPUID feature bits available in XSS */
|
||||
#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK)
|
||||
|
||||
ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = {
|
||||
[XSTATE_FP_BIT] = {
|
||||
/* x87 FP state component is always enabled if XSAVE is supported */
|
||||
|
@ -2206,6 +2211,60 @@ static CPUCaches epyc_v4_cache_info = {
|
|||
},
|
||||
};
|
||||
|
||||
static CPUCaches epyc_v5_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
.level = 1,
|
||||
.size = 64 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 4,
|
||||
.partitions = 1,
|
||||
.sets = 256,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 2,
|
||||
.size = 512 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 3,
|
||||
.size = 8 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 16,
|
||||
.partitions = 1,
|
||||
.sets = 8192,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.no_invd_sharing = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_rome_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
|
@ -2314,6 +2373,60 @@ static const CPUCaches epyc_rome_v3_cache_info = {
|
|||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_rome_v5_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 2,
|
||||
.size = 512 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 3,
|
||||
.size = 16 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 16,
|
||||
.partitions = 1,
|
||||
.sets = 16384,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.no_invd_sharing = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_milan_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
|
@ -2422,6 +2535,60 @@ static const CPUCaches epyc_milan_v2_cache_info = {
|
|||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_milan_v3_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 2,
|
||||
.size = 512 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 3,
|
||||
.size = 32 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 16,
|
||||
.partitions = 1,
|
||||
.sets = 32768,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.no_invd_sharing = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_genoa_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
|
@ -2476,6 +2643,114 @@ static const CPUCaches epyc_genoa_cache_info = {
|
|||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_genoa_v2_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 2,
|
||||
.size = 1 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 2048,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 3,
|
||||
.size = 32 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 16,
|
||||
.partitions = 1,
|
||||
.sets = 32768,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.no_invd_sharing = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
static const CPUCaches epyc_turin_cache_info = {
|
||||
.l1d_cache = &(CPUCacheInfo) {
|
||||
.type = DATA_CACHE,
|
||||
.level = 1,
|
||||
.size = 48 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 12,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
.level = 1,
|
||||
.size = 32 * KiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.partitions = 1,
|
||||
.sets = 64,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 2,
|
||||
.size = 1 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 16,
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
.level = 3,
|
||||
.size = 32 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 16,
|
||||
.partitions = 1,
|
||||
.sets = 32768,
|
||||
.lines_per_tag = 1,
|
||||
.self_init = true,
|
||||
.no_invd_sharing = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
/* The following VMX features are not supported by KVM and are left out in the
|
||||
* CPU definitions:
|
||||
*
|
||||
|
@ -5233,6 +5508,25 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||
},
|
||||
.cache_info = &epyc_v4_cache_info
|
||||
},
|
||||
{
|
||||
.version = 5,
|
||||
.props = (PropValue[]) {
|
||||
{ "overflow-recov", "on" },
|
||||
{ "succor", "on" },
|
||||
{ "lbrv", "on" },
|
||||
{ "tsc-scale", "on" },
|
||||
{ "vmcb-clean", "on" },
|
||||
{ "flushbyasid", "on" },
|
||||
{ "pause-filter", "on" },
|
||||
{ "pfthreshold", "on" },
|
||||
{ "v-vmsave-vmload", "on" },
|
||||
{ "vgif", "on" },
|
||||
{ "model-id",
|
||||
"AMD EPYC-v5 Processor" },
|
||||
{ /* end of list */ }
|
||||
},
|
||||
.cache_info = &epyc_v5_cache_info
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
|
@ -5371,6 +5665,25 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||
{ /* end of list */ }
|
||||
},
|
||||
},
|
||||
{
|
||||
.version = 5,
|
||||
.props = (PropValue[]) {
|
||||
{ "overflow-recov", "on" },
|
||||
{ "succor", "on" },
|
||||
{ "lbrv", "on" },
|
||||
{ "tsc-scale", "on" },
|
||||
{ "vmcb-clean", "on" },
|
||||
{ "flushbyasid", "on" },
|
||||
{ "pause-filter", "on" },
|
||||
{ "pfthreshold", "on" },
|
||||
{ "v-vmsave-vmload", "on" },
|
||||
{ "vgif", "on" },
|
||||
{ "model-id",
|
||||
"AMD EPYC-Rome-v5 Processor" },
|
||||
{ /* end of list */ }
|
||||
},
|
||||
.cache_info = &epyc_rome_v5_cache_info
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
|
@ -5446,6 +5759,25 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||
},
|
||||
.cache_info = &epyc_milan_v2_cache_info
|
||||
},
|
||||
{
|
||||
.version = 3,
|
||||
.props = (PropValue[]) {
|
||||
{ "overflow-recov", "on" },
|
||||
{ "succor", "on" },
|
||||
{ "lbrv", "on" },
|
||||
{ "tsc-scale", "on" },
|
||||
{ "vmcb-clean", "on" },
|
||||
{ "flushbyasid", "on" },
|
||||
{ "pause-filter", "on" },
|
||||
{ "pfthreshold", "on" },
|
||||
{ "v-vmsave-vmload", "on" },
|
||||
{ "vgif", "on" },
|
||||
{ "model-id",
|
||||
"AMD EPYC-Milan-v3 Processor" },
|
||||
{ /* end of list */ }
|
||||
},
|
||||
.cache_info = &epyc_milan_v3_cache_info
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
|
@ -5520,6 +5852,31 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||
.xlevel = 0x80000022,
|
||||
.model_id = "AMD EPYC-Genoa Processor",
|
||||
.cache_info = &epyc_genoa_cache_info,
|
||||
.versions = (X86CPUVersionDefinition[]) {
|
||||
{ .version = 1 },
|
||||
{
|
||||
.version = 2,
|
||||
.props = (PropValue[]) {
|
||||
{ "overflow-recov", "on" },
|
||||
{ "succor", "on" },
|
||||
{ "lbrv", "on" },
|
||||
{ "tsc-scale", "on" },
|
||||
{ "vmcb-clean", "on" },
|
||||
{ "flushbyasid", "on" },
|
||||
{ "pause-filter", "on" },
|
||||
{ "pfthreshold", "on" },
|
||||
{ "v-vmsave-vmload", "on" },
|
||||
{ "vgif", "on" },
|
||||
{ "fs-gs-base-ns", "on" },
|
||||
{ "perfmon-v2", "on" },
|
||||
{ "model-id",
|
||||
"AMD EPYC-Genoa-v2 Processor" },
|
||||
{ /* end of list */ }
|
||||
},
|
||||
.cache_info = &epyc_genoa_v2_cache_info
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "YongFeng",
|
||||
|
@ -5657,6 +6014,89 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "EPYC-Turin",
|
||||
.level = 0xd,
|
||||
.vendor = CPUID_VENDOR_AMD,
|
||||
.family = 26,
|
||||
.model = 0,
|
||||
.stepping = 0,
|
||||
.features[FEAT_1_ECX] =
|
||||
CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX |
|
||||
CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
|
||||
CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
||||
CPUID_EXT_PCID | CPUID_EXT_CX16 | CPUID_EXT_FMA |
|
||||
CPUID_EXT_SSSE3 | CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ |
|
||||
CPUID_EXT_SSE3,
|
||||
.features[FEAT_1_EDX] =
|
||||
CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH |
|
||||
CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE |
|
||||
CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE |
|
||||
CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE |
|
||||
CPUID_VME | CPUID_FP87,
|
||||
.features[FEAT_6_EAX] =
|
||||
CPUID_6_EAX_ARAT,
|
||||
.features[FEAT_7_0_EBX] =
|
||||
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
|
||||
CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS |
|
||||
CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_AVX512F |
|
||||
CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
|
||||
CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
|
||||
CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI |
|
||||
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL,
|
||||
.features[FEAT_7_0_ECX] =
|
||||
CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
|
||||
CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI |
|
||||
CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ |
|
||||
CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG |
|
||||
CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 |
|
||||
CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_MOVDIRI |
|
||||
CPUID_7_0_ECX_MOVDIR64B,
|
||||
.features[FEAT_7_0_EDX] =
|
||||
CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_AVX512_VP2INTERSECT,
|
||||
.features[FEAT_7_1_EAX] =
|
||||
CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16,
|
||||
.features[FEAT_8000_0001_ECX] =
|
||||
CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH |
|
||||
CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
|
||||
CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM |
|
||||
CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE,
|
||||
.features[FEAT_8000_0001_EDX] =
|
||||
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB |
|
||||
CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX |
|
||||
CPUID_EXT2_SYSCALL,
|
||||
.features[FEAT_8000_0007_EBX] =
|
||||
CPUID_8000_0007_EBX_OVERFLOW_RECOV | CPUID_8000_0007_EBX_SUCCOR,
|
||||
.features[FEAT_8000_0008_EBX] =
|
||||
CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR |
|
||||
CPUID_8000_0008_EBX_WBNOINVD | CPUID_8000_0008_EBX_IBPB |
|
||||
CPUID_8000_0008_EBX_IBRS | CPUID_8000_0008_EBX_STIBP |
|
||||
CPUID_8000_0008_EBX_STIBP_ALWAYS_ON |
|
||||
CPUID_8000_0008_EBX_AMD_SSBD | CPUID_8000_0008_EBX_AMD_PSFD,
|
||||
.features[FEAT_8000_0021_EAX] =
|
||||
CPUID_8000_0021_EAX_NO_NESTED_DATA_BP |
|
||||
CPUID_8000_0021_EAX_FS_GS_BASE_NS |
|
||||
CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING |
|
||||
CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE |
|
||||
CPUID_8000_0021_EAX_AUTO_IBRS | CPUID_8000_0021_EAX_PREFETCHI |
|
||||
CPUID_8000_0021_EAX_SBPB | CPUID_8000_0021_EAX_IBPB_BRTYPE |
|
||||
CPUID_8000_0021_EAX_SRSO_USER_KERNEL_NO,
|
||||
.features[FEAT_8000_0022_EAX] =
|
||||
CPUID_8000_0022_EAX_PERFMON_V2,
|
||||
.features[FEAT_XSAVE] =
|
||||
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
||||
CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES,
|
||||
.features[FEAT_SVM] =
|
||||
CPUID_SVM_NPT | CPUID_SVM_LBRV | CPUID_SVM_NRIPSAVE |
|
||||
CPUID_SVM_TSCSCALE | CPUID_SVM_VMCBCLEAN | CPUID_SVM_FLUSHASID |
|
||||
CPUID_SVM_PAUSEFILTER | CPUID_SVM_PFTHRESHOLD |
|
||||
CPUID_SVM_V_VMSAVE_VMLOAD | CPUID_SVM_VGIF |
|
||||
CPUID_SVM_VNMI | CPUID_SVM_SVME_ADDR_CHK,
|
||||
.xlevel = 0x80000022,
|
||||
.model_id = "AMD EPYC-Turin Processor",
|
||||
.cache_info = &epyc_turin_cache_info,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -5766,7 +6206,7 @@ static const TypeInfo max_x86_cpu_type_info = {
|
|||
.class_init = max_x86_cpu_class_init,
|
||||
};
|
||||
|
||||
static char *feature_word_description(FeatureWordInfo *f, uint32_t bit)
|
||||
static char *feature_word_description(FeatureWordInfo *f)
|
||||
{
|
||||
assert(f->type == CPUID_FEATURE_WORD || f->type == MSR_FEATURE_WORD);
|
||||
|
||||
|
@ -5775,11 +6215,15 @@ static char *feature_word_description(FeatureWordInfo *f, uint32_t bit)
|
|||
{
|
||||
const char *reg = get_register_name_32(f->cpuid.reg);
|
||||
assert(reg);
|
||||
return g_strdup_printf("CPUID.%02XH:%s",
|
||||
f->cpuid.eax, reg);
|
||||
if (!f->cpuid.needs_ecx) {
|
||||
return g_strdup_printf("CPUID[eax=%02Xh].%s", f->cpuid.eax, reg);
|
||||
} else {
|
||||
return g_strdup_printf("CPUID[eax=%02Xh,ecx=%02Xh].%s",
|
||||
f->cpuid.eax, f->cpuid.ecx, reg);
|
||||
}
|
||||
}
|
||||
case MSR_FEATURE_WORD:
|
||||
return g_strdup_printf("MSR(%02XH)",
|
||||
return g_strdup_printf("MSR(%02Xh)",
|
||||
f->msr.index);
|
||||
}
|
||||
|
||||
|
@ -5799,12 +6243,13 @@ static bool x86_cpu_have_filtered_features(X86CPU *cpu)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
||||
const char *verbose_prefix)
|
||||
void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
||||
const char *verbose_prefix)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
FeatureWordInfo *f = &feature_word_info[w];
|
||||
int i;
|
||||
g_autofree char *feat_word_str = feature_word_description(f);
|
||||
|
||||
if (!cpu->force_features) {
|
||||
env->features[w] &= ~mask;
|
||||
|
@ -5817,7 +6262,35 @@ static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
|||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
if ((1ULL << i) & mask) {
|
||||
g_autofree char *feat_word_str = feature_word_description(f, i);
|
||||
warn_report("%s: %s%s%s [bit %d]",
|
||||
verbose_prefix,
|
||||
feat_word_str,
|
||||
f->feat_names[i] ? "." : "",
|
||||
f->feat_names[i] ? f->feat_names[i] : "", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mark_forced_on_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
||||
const char *verbose_prefix)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
FeatureWordInfo *f = &feature_word_info[w];
|
||||
int i;
|
||||
|
||||
if (!cpu->force_features) {
|
||||
env->features[w] |= mask;
|
||||
}
|
||||
|
||||
cpu->forced_on_features[w] |= mask;
|
||||
|
||||
if (!verbose_prefix) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
if ((1ULL << i) & mask) {
|
||||
g_autofree char *feat_word_str = feature_word_description(f);
|
||||
warn_report("%s: %s%s%s [bit %d]",
|
||||
verbose_prefix,
|
||||
feat_word_str,
|
||||
|
@ -7044,7 +7517,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||
break;
|
||||
case 0x1F:
|
||||
/* V2 Extended Topology Enumeration Leaf */
|
||||
if (!x86_has_extended_topo(env->avail_cpu_topo)) {
|
||||
if (!x86_has_cpuid_0x1f(cpu)) {
|
||||
*eax = *ebx = *ecx = *edx = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -7908,7 +8381,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|||
* cpu->vendor_cpuid_only has been unset for compatibility with older
|
||||
* machine types.
|
||||
*/
|
||||
if (x86_has_extended_topo(env->avail_cpu_topo) &&
|
||||
if (x86_has_cpuid_0x1f(cpu) &&
|
||||
(IS_INTEL_CPU(env) || !cpu->vendor_cpuid_only)) {
|
||||
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F);
|
||||
}
|
||||
|
@ -8543,6 +9016,13 @@ static void x86_cpu_post_initfn(Object *obj)
|
|||
}
|
||||
|
||||
accel_cpu_instance_init(CPU(obj));
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (current_machine && current_machine->cgs) {
|
||||
x86_confidential_guest_cpu_instance_init(
|
||||
X86_CONFIDENTIAL_GUEST(current_machine->cgs), (CPU(obj)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void x86_cpu_init_default_topo(X86CPU *cpu)
|
||||
|
|
|
@ -584,6 +584,7 @@ typedef enum X86Seg {
|
|||
#define XSTATE_OPMASK_BIT 5
|
||||
#define XSTATE_ZMM_Hi256_BIT 6
|
||||
#define XSTATE_Hi16_ZMM_BIT 7
|
||||
#define XSTATE_PT_BIT 8
|
||||
#define XSTATE_PKRU_BIT 9
|
||||
#define XSTATE_ARCH_LBR_BIT 15
|
||||
#define XSTATE_XTILE_CFG_BIT 17
|
||||
|
@ -597,6 +598,7 @@ typedef enum X86Seg {
|
|||
#define XSTATE_OPMASK_MASK (1ULL << XSTATE_OPMASK_BIT)
|
||||
#define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT)
|
||||
#define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT)
|
||||
#define XSTATE_PT_MASK (1ULL << XSTATE_PT_BIT)
|
||||
#define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT)
|
||||
#define XSTATE_ARCH_LBR_MASK (1ULL << XSTATE_ARCH_LBR_BIT)
|
||||
#define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT)
|
||||
|
@ -619,6 +621,11 @@ typedef enum X86Seg {
|
|||
XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK | \
|
||||
XSTATE_XTILE_CFG_MASK | XSTATE_XTILE_DATA_MASK)
|
||||
|
||||
/* CPUID feature bits available in XSS */
|
||||
#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK)
|
||||
|
||||
#define CPUID_XSTATE_MASK (CPUID_XSTATE_XCR0_MASK | CPUID_XSTATE_XSS_MASK)
|
||||
|
||||
/* CPUID feature words */
|
||||
typedef enum FeatureWord {
|
||||
FEAT_1_EDX, /* CPUID[1].EDX */
|
||||
|
@ -667,6 +674,15 @@ typedef enum FeatureWord {
|
|||
FEATURE_WORDS,
|
||||
} FeatureWord;
|
||||
|
||||
typedef struct FeatureMask {
|
||||
FeatureWord index;
|
||||
uint64_t mask;
|
||||
} FeatureMask;
|
||||
|
||||
typedef struct FeatureDep {
|
||||
FeatureMask from, to;
|
||||
} FeatureDep;
|
||||
|
||||
typedef uint64_t FeatureWordArray[FEATURE_WORDS];
|
||||
uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
||||
|
||||
|
@ -899,6 +915,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
#define CPUID_7_0_ECX_LA57 (1U << 16)
|
||||
/* Read Processor ID */
|
||||
#define CPUID_7_0_ECX_RDPID (1U << 22)
|
||||
/* KeyLocker */
|
||||
#define CPUID_7_0_ECX_KeyLocker (1U << 23)
|
||||
/* Bus Lock Debug Exception */
|
||||
#define CPUID_7_0_ECX_BUS_LOCK_DETECT (1U << 24)
|
||||
/* Cache Line Demote Instruction */
|
||||
|
@ -920,6 +938,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
#define CPUID_7_0_EDX_FSRM (1U << 4)
|
||||
/* AVX512 Vector Pair Intersection to a Pair of Mask Registers */
|
||||
#define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8)
|
||||
/* "md_clear" VERW clears CPU buffers */
|
||||
#define CPUID_7_0_EDX_MD_CLEAR (1U << 10)
|
||||
/* SERIALIZE instruction */
|
||||
#define CPUID_7_0_EDX_SERIALIZE (1U << 14)
|
||||
/* TSX Suspend Load Address Tracking instruction */
|
||||
|
@ -957,6 +977,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
#define CPUID_7_1_EAX_AVX_VNNI (1U << 4)
|
||||
/* AVX512 BFloat16 Instruction */
|
||||
#define CPUID_7_1_EAX_AVX512_BF16 (1U << 5)
|
||||
/* Linear address space separation */
|
||||
#define CPUID_7_1_EAX_LASS (1U << 6)
|
||||
/* CMPCCXADD Instructions */
|
||||
#define CPUID_7_1_EAX_CMPCCXADD (1U << 7)
|
||||
/* Fast Zero REP MOVS */
|
||||
|
@ -1070,12 +1092,16 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
|
||||
/* Processor ignores nested data breakpoints */
|
||||
#define CPUID_8000_0021_EAX_NO_NESTED_DATA_BP (1U << 0)
|
||||
/* WRMSR to FS_BASE, GS_BASE, or KERNEL_GS_BASE is non-serializing */
|
||||
#define CPUID_8000_0021_EAX_FS_GS_BASE_NS (1U << 1)
|
||||
/* LFENCE is always serializing */
|
||||
#define CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING (1U << 2)
|
||||
/* Null Selector Clears Base */
|
||||
#define CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE (1U << 6)
|
||||
/* Automatic IBRS */
|
||||
#define CPUID_8000_0021_EAX_AUTO_IBRS (1U << 8)
|
||||
/* Indicates support for IC prefetch */
|
||||
#define CPUID_8000_0021_EAX_PREFETCHI (1U << 20)
|
||||
/* Enhanced Return Address Predictor Scurity */
|
||||
#define CPUID_8000_0021_EAX_ERAPS (1U << 24)
|
||||
/* Selective Branch Predictor Barrier */
|
||||
|
@ -1100,6 +1126,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
||||
#define CPUID_XSAVE_XGETBV1 (1U << 2)
|
||||
#define CPUID_XSAVE_XSAVES (1U << 3)
|
||||
#define CPUID_XSAVE_XFD (1U << 4)
|
||||
|
||||
#define CPUID_6_EAX_ARAT (1U << 2)
|
||||
|
||||
|
@ -2192,6 +2219,9 @@ struct ArchCPU {
|
|||
/* Features that were filtered out because of missing host capabilities */
|
||||
FeatureWordArray filtered_features;
|
||||
|
||||
/* Features that are forced enabled by underlying hypervisor, e.g., TDX */
|
||||
FeatureWordArray forced_on_features;
|
||||
|
||||
/* Enable PMU CPUID bits. This can't be enabled by default yet because
|
||||
* it doesn't have ABI stability guarantees, as it passes all PMU CPUID
|
||||
* bits returned by GET_SUPPORTED_CPUID (that depend on host CPU and kernel
|
||||
|
@ -2239,6 +2269,9 @@ struct ArchCPU {
|
|||
/* Compatibility bits for old machine types: */
|
||||
bool enable_cpuid_0xb;
|
||||
|
||||
/* Force to enable cpuid 0x1f */
|
||||
bool enable_cpuid_0x1f;
|
||||
|
||||
/* Enable auto level-increase for all CPUID leaves */
|
||||
bool full_cpuid_auto_level;
|
||||
|
||||
|
@ -2499,6 +2532,17 @@ void cpu_set_apic_feature(CPUX86State *env);
|
|||
void host_cpuid(uint32_t function, uint32_t count,
|
||||
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
|
||||
bool cpu_has_x2apic_feature(CPUX86State *env);
|
||||
bool is_feature_word_cpuid(uint32_t feature, uint32_t index, int reg);
|
||||
void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
||||
const char *verbose_prefix);
|
||||
void mark_forced_on_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
|
||||
const char *verbose_prefix);
|
||||
|
||||
static inline bool x86_has_cpuid_0x1f(X86CPU *cpu)
|
||||
{
|
||||
return cpu->enable_cpuid_0x1f ||
|
||||
x86_has_extended_topo(cpu->env.avail_cpu_topo);
|
||||
}
|
||||
|
||||
/* helper.c */
|
||||
void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
|
||||
|
|
|
@ -255,19 +255,19 @@ void lflags_to_rflags(CPUX86State *env)
|
|||
|
||||
void rflags_to_lflags(CPUX86State *env)
|
||||
{
|
||||
target_ulong cf_xor_of;
|
||||
target_ulong cf_af, cf_xor_of;
|
||||
|
||||
/* Leave the low byte zero so that parity is always even... */
|
||||
env->cc_dst = !(env->eflags & CC_Z) << 8;
|
||||
|
||||
/* ... and therefore cc_src always uses opposite polarity. */
|
||||
env->cc_src = CC_P;
|
||||
env->cc_src ^= env->eflags & (CC_S | CC_P);
|
||||
|
||||
/* rotate right by one to move CF and AF into the carry-out positions */
|
||||
env->cc_src |= (
|
||||
(env->eflags >> 1) |
|
||||
(env->eflags << (TARGET_LONG_BITS - 1))) & (CC_C | CC_A);
|
||||
cf_af = env->eflags & (CC_C | CC_A);
|
||||
env->cc_src |= ((cf_af >> 1) | (cf_af << (TARGET_LONG_BITS - 1)));
|
||||
|
||||
cf_xor_of = (env->eflags & (CC_C | CC_O)) + (CC_O - CC_C);
|
||||
cf_xor_of = ((env->eflags & (CC_C | CC_O)) + (CC_O - CC_C)) & CC_O;
|
||||
env->cc_src |= -cf_xor_of & LF_MASK_PO;
|
||||
|
||||
/* Leave the low byte zero so that parity is not affected. */
|
||||
env->cc_dst = !(env->eflags & CC_Z) << 8;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "system/system.h"
|
||||
|
||||
/* Note: Only safe for use on x86(-64) hosts */
|
||||
static uint32_t host_cpu_phys_bits(void)
|
||||
uint32_t host_cpu_phys_bits(void)
|
||||
{
|
||||
uint32_t eax;
|
||||
uint32_t host_phys_bits;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef HOST_CPU_H
|
||||
#define HOST_CPU_H
|
||||
|
||||
uint32_t host_cpu_phys_bits(void);
|
||||
void host_cpu_instance_init(X86CPU *cpu);
|
||||
void host_cpu_max_instance_init(X86CPU *cpu);
|
||||
bool host_cpu_realizefn(CPUState *cs, Error **errp);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "kvm_i386.h"
|
||||
#include "../confidential-guest.h"
|
||||
#include "sev.h"
|
||||
#include "tdx.h"
|
||||
#include "xen-emu.h"
|
||||
#include "hyperv.h"
|
||||
#include "hyperv-proto.h"
|
||||
|
@ -192,6 +193,7 @@ static const char *vm_type_name[] = {
|
|||
[KVM_X86_SEV_VM] = "SEV",
|
||||
[KVM_X86_SEV_ES_VM] = "SEV-ES",
|
||||
[KVM_X86_SNP_VM] = "SEV-SNP",
|
||||
[KVM_X86_TDX_VM] = "TDX",
|
||||
};
|
||||
|
||||
bool kvm_is_vm_type_supported(int type)
|
||||
|
@ -326,7 +328,7 @@ void kvm_synchronize_all_tsc(void)
|
|||
{
|
||||
CPUState *cpu;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
if (kvm_enabled() && !is_tdx_vm()) {
|
||||
CPU_FOREACH(cpu) {
|
||||
run_on_cpu(cpu, do_kvm_synchronize_tsc, RUN_ON_CPU_NULL);
|
||||
}
|
||||
|
@ -392,7 +394,7 @@ static bool host_tsx_broken(void)
|
|||
|
||||
/* Returns the value for a specific register on the cpuid entry
|
||||
*/
|
||||
static uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg)
|
||||
uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
switch (reg) {
|
||||
|
@ -414,9 +416,9 @@ static uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg)
|
|||
|
||||
/* Find matching entry for function/index on kvm_cpuid2 struct
|
||||
*/
|
||||
static struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid,
|
||||
uint32_t function,
|
||||
uint32_t index)
|
||||
struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid,
|
||||
uint32_t function,
|
||||
uint32_t index)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cpuid->nent; ++i) {
|
||||
|
@ -572,7 +574,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
|
|||
}
|
||||
|
||||
if (current_machine->cgs) {
|
||||
ret = x86_confidential_guest_mask_cpuid_features(
|
||||
ret = x86_confidential_guest_adjust_cpuid_features(
|
||||
X86_CONFIDENTIAL_GUEST(current_machine->cgs),
|
||||
function, index, reg, ret);
|
||||
}
|
||||
|
@ -868,6 +870,15 @@ static int kvm_arch_set_tsc_khz(CPUState *cs)
|
|||
int r, cur_freq;
|
||||
bool set_ioctl = false;
|
||||
|
||||
/*
|
||||
* TSC of TD vcpu is immutable, it cannot be set/changed via vcpu scope
|
||||
* VM_SET_TSC_KHZ, but only be initialized via VM scope VM_SET_TSC_KHZ
|
||||
* before ioctl KVM_TDX_INIT_VM in tdx_pre_create_vcpu()
|
||||
*/
|
||||
if (is_tdx_vm()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!env->tsc_khz) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1779,8 +1790,6 @@ static int hyperv_init_vcpu(X86CPU *cpu)
|
|||
|
||||
static Error *invtsc_mig_blocker;
|
||||
|
||||
#define KVM_MAX_CPUID_ENTRIES 100
|
||||
|
||||
static void kvm_init_xsave(CPUX86State *env)
|
||||
{
|
||||
if (has_xsave2) {
|
||||
|
@ -1823,9 +1832,8 @@ static void kvm_init_nested_state(CPUX86State *env)
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
|
||||
struct kvm_cpuid_entry2 *entries,
|
||||
uint32_t cpuid_i)
|
||||
uint32_t kvm_x86_build_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries,
|
||||
uint32_t cpuid_i)
|
||||
{
|
||||
uint32_t limit, i, j;
|
||||
uint32_t unused;
|
||||
|
@ -1864,7 +1872,7 @@ static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
|
|||
break;
|
||||
}
|
||||
case 0x1f:
|
||||
if (!x86_has_extended_topo(env->avail_cpu_topo)) {
|
||||
if (!x86_has_cpuid_0x1f(env_archcpu(env))) {
|
||||
cpuid_i--;
|
||||
break;
|
||||
}
|
||||
|
@ -2052,6 +2060,15 @@ full:
|
|||
abort();
|
||||
}
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
if (is_tdx_vm()) {
|
||||
return tdx_pre_create_vcpu(cpu, errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
struct {
|
||||
|
@ -2076,6 +2093,14 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
|||
int r;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (current_machine->cgs) {
|
||||
r = x86_confidential_guest_check_features(
|
||||
X86_CONFIDENTIAL_GUEST(current_machine->cgs), cs);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&cpuid_data, 0, sizeof(cpuid_data));
|
||||
|
||||
cpuid_i = 0;
|
||||
|
@ -3206,16 +3231,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
|||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* Initialize SEV context, if required
|
||||
*
|
||||
* If no memory encryption is requested (ms->cgs == NULL) this is
|
||||
* a no-op.
|
||||
*
|
||||
* It's also a no-op if a non-SEV confidential guest support
|
||||
* mechanism is selected. SEV is the only mechanism available to
|
||||
* select on x86 at present, so this doesn't arise, but if new
|
||||
* mechanisms are supported in future (e.g. TDX), they'll need
|
||||
* their own initialization either here or elsewhere.
|
||||
* Initialize confidential guest (SEV/TDX) context, if required
|
||||
*/
|
||||
if (ms->cgs) {
|
||||
ret = confidential_guest_kvm_init(ms->cgs, &local_err);
|
||||
|
@ -3856,32 +3872,34 @@ static void kvm_init_msrs(X86CPU *cpu)
|
|||
CPUX86State *env = &cpu->env;
|
||||
|
||||
kvm_msr_buf_reset(cpu);
|
||||
if (has_msr_arch_capabs) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_ARCH_CAPABILITIES,
|
||||
env->features[FEAT_ARCH_CAPABILITIES]);
|
||||
}
|
||||
|
||||
if (has_msr_core_capabs) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY,
|
||||
env->features[FEAT_CORE_CAPABILITY]);
|
||||
}
|
||||
if (!is_tdx_vm()) {
|
||||
if (has_msr_arch_capabs) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_ARCH_CAPABILITIES,
|
||||
env->features[FEAT_ARCH_CAPABILITIES]);
|
||||
}
|
||||
|
||||
if (has_msr_perf_capabs && cpu->enable_pmu) {
|
||||
kvm_msr_entry_add_perf(cpu, env->features);
|
||||
if (has_msr_core_capabs) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY,
|
||||
env->features[FEAT_CORE_CAPABILITY]);
|
||||
}
|
||||
|
||||
if (has_msr_perf_capabs && cpu->enable_pmu) {
|
||||
kvm_msr_entry_add_perf(cpu, env->features);
|
||||
}
|
||||
|
||||
/*
|
||||
* Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but
|
||||
* all kernels with MSR features should have them.
|
||||
*/
|
||||
if (kvm_feature_msrs && cpu_has_vmx(env)) {
|
||||
kvm_msr_entry_add_vmx(cpu, env->features);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_msr_ucode_rev) {
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_UCODE_REV, cpu->ucode_rev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but
|
||||
* all kernels with MSR features should have them.
|
||||
*/
|
||||
if (kvm_feature_msrs && cpu_has_vmx(env)) {
|
||||
kvm_msr_entry_add_vmx(cpu, env->features);
|
||||
}
|
||||
|
||||
assert(kvm_buf_set_msrs(cpu) == 0);
|
||||
}
|
||||
|
||||
|
@ -6121,6 +6139,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
|||
case KVM_EXIT_HYPERCALL:
|
||||
ret = kvm_handle_hypercall(run);
|
||||
break;
|
||||
case KVM_EXIT_SYSTEM_EVENT:
|
||||
switch (run->system_event.type) {
|
||||
case KVM_SYSTEM_EVENT_TDX_FATAL:
|
||||
ret = tdx_handle_report_fatal_error(cpu, run);
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
|
||||
ret = -1;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include "system/kvm.h"
|
||||
|
||||
#define KVM_MAX_CPUID_ENTRIES 100
|
||||
|
||||
/* always false if !CONFIG_KVM */
|
||||
#define kvm_pit_in_kernel() \
|
||||
(kvm_irqchip_in_kernel() && !kvm_irqchip_is_split())
|
||||
|
@ -42,6 +44,13 @@ void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask);
|
|||
|
||||
#ifdef CONFIG_KVM
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
typedef struct KvmCpuidInfo {
|
||||
struct kvm_cpuid2 cpuid;
|
||||
struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
|
||||
} KvmCpuidInfo;
|
||||
|
||||
bool kvm_is_vm_type_supported(int type);
|
||||
bool kvm_has_adjust_clock_stable(void);
|
||||
bool kvm_has_exception_payload(void);
|
||||
|
@ -57,6 +66,12 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
|
|||
void kvm_update_msi_routes_all(void *private, bool global,
|
||||
uint32_t index, uint32_t mask);
|
||||
|
||||
struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid,
|
||||
uint32_t function,
|
||||
uint32_t index);
|
||||
uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg);
|
||||
uint32_t kvm_x86_build_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries,
|
||||
uint32_t cpuid_i);
|
||||
#endif /* CONFIG_KVM */
|
||||
|
||||
void kvm_pc_setup_irq_routing(bool pci_enabled);
|
||||
|
|
|
@ -8,6 +8,8 @@ i386_kvm_ss.add(files(
|
|||
|
||||
i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c'))
|
||||
|
||||
i386_kvm_ss.add(when: 'CONFIG_TDX', if_true: files('tdx.c'), if_false: files('tdx-stub.c'))
|
||||
|
||||
i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c'))
|
||||
|
||||
i386_system_ss.add_all(when: 'CONFIG_KVM', if_true: i386_kvm_ss)
|
||||
|
|
20
target/i386/kvm/tdx-stub.c
Normal file
20
target/i386/kvm/tdx-stub.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "tdx.h"
|
||||
|
||||
int tdx_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tdx_parse_tdvf(void *flash_ptr, int size)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
1289
target/i386/kvm/tdx.c
Normal file
1289
target/i386/kvm/tdx.c
Normal file
File diff suppressed because it is too large
Load diff
65
target/i386/kvm/tdx.h
Normal file
65
target/i386/kvm/tdx.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef QEMU_I386_TDX_H
|
||||
#define QEMU_I386_TDX_H
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include CONFIG_DEVICES /* CONFIG_TDX */
|
||||
#endif
|
||||
|
||||
#include "confidential-guest.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/i386/tdvf.h"
|
||||
|
||||
#define TYPE_TDX_GUEST "tdx-guest"
|
||||
#define TDX_GUEST(obj) OBJECT_CHECK(TdxGuest, (obj), TYPE_TDX_GUEST)
|
||||
|
||||
typedef struct TdxGuestClass {
|
||||
X86ConfidentialGuestClass parent_class;
|
||||
} TdxGuestClass;
|
||||
|
||||
/* TDX requires bus frequency 25MHz */
|
||||
#define TDX_APIC_BUS_CYCLES_NS 40
|
||||
|
||||
enum TdxRamType {
|
||||
TDX_RAM_UNACCEPTED,
|
||||
TDX_RAM_ADDED,
|
||||
};
|
||||
|
||||
typedef struct TdxRamEntry {
|
||||
uint64_t address;
|
||||
uint64_t length;
|
||||
enum TdxRamType type;
|
||||
} TdxRamEntry;
|
||||
|
||||
typedef struct TdxGuest {
|
||||
X86ConfidentialGuest parent_obj;
|
||||
|
||||
QemuMutex lock;
|
||||
|
||||
bool initialized;
|
||||
uint64_t attributes; /* TD attributes */
|
||||
uint64_t xfam;
|
||||
char *mrconfigid; /* base64 encoded sha348 digest */
|
||||
char *mrowner; /* base64 encoded sha348 digest */
|
||||
char *mrownerconfig; /* base64 encoded sha348 digest */
|
||||
|
||||
MemoryRegion *tdvf_mr;
|
||||
TdxFirmware tdvf;
|
||||
|
||||
uint32_t nr_ram_entries;
|
||||
TdxRamEntry *ram_entries;
|
||||
} TdxGuest;
|
||||
|
||||
#ifdef CONFIG_TDX
|
||||
bool is_tdx_vm(void);
|
||||
#else
|
||||
#define is_tdx_vm() 0
|
||||
#endif /* CONFIG_TDX */
|
||||
|
||||
int tdx_pre_create_vcpu(CPUState *cpu, Error **errp);
|
||||
void tdx_set_tdvf_region(MemoryRegion *tdvf_mr);
|
||||
int tdx_parse_tdvf(void *flash_ptr, int size);
|
||||
int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run);
|
||||
|
||||
#endif /* QEMU_I386_TDX_H */
|
|
@ -212,14 +212,6 @@ static const char *const sev_fw_errlist[] = {
|
|||
|
||||
#define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
|
||||
|
||||
/* <linux/kvm.h> doesn't expose this, so re-use the max from kvm.c */
|
||||
#define KVM_MAX_CPUID_ENTRIES 100
|
||||
|
||||
typedef struct KvmCpuidInfo {
|
||||
struct kvm_cpuid2 cpuid;
|
||||
struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
|
||||
} KvmCpuidInfo;
|
||||
|
||||
#define SNP_CPUID_FUNCTION_MAXCOUNT 64
|
||||
#define SNP_CPUID_FUNCTION_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
|
@ -947,7 +939,7 @@ out:
|
|||
}
|
||||
|
||||
static uint32_t
|
||||
sev_snp_mask_cpuid_features(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index,
|
||||
sev_snp_adjust_cpuid_features(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index,
|
||||
int reg, uint32_t value)
|
||||
{
|
||||
switch (feature) {
|
||||
|
@ -2405,7 +2397,7 @@ sev_snp_guest_class_init(ObjectClass *oc, const void *data)
|
|||
klass->launch_finish = sev_snp_launch_finish;
|
||||
klass->launch_update_data = sev_snp_launch_update_data;
|
||||
klass->kvm_init = sev_snp_kvm_init;
|
||||
x86_klass->mask_cpuid_features = sev_snp_mask_cpuid_features;
|
||||
x86_klass->adjust_cpuid_features = sev_snp_adjust_cpuid_features;
|
||||
x86_klass->kvm_type = sev_snp_kvm_type;
|
||||
|
||||
object_class_property_add(oc, "policy", "uint64",
|
||||
|
|
|
@ -97,7 +97,7 @@ static inline unsigned int compute_pf(uint8_t x)
|
|||
/* misc_helper.c */
|
||||
void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask);
|
||||
|
||||
/* sysemu/svm_helper.c */
|
||||
/* system/svm_helper.c */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
G_NORETURN void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code,
|
||||
uint64_t exit_info_1, uintptr_t retaddr);
|
||||
|
@ -115,7 +115,7 @@ int exception_has_error_code(int intno);
|
|||
/* smm_helper.c */
|
||||
void do_smm_enter(X86CPU *cpu);
|
||||
|
||||
/* sysemu/bpt_helper.c */
|
||||
/* system/bpt_helper.c */
|
||||
bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1071,7 +1071,11 @@ static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp)
|
|||
env->pv_features |= BIT(KVM_FEATURE_VIRT_EXTIOI);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,11 @@ int kvm_arch_irqchip_create(KVMState *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
CPUMIPSState *env = cpu_env(cs);
|
||||
|
|
|
@ -479,6 +479,11 @@ static void kvmppc_hw_debug_points_init(CPUPPCState *cenv)
|
|||
}
|
||||
}
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
|
|
@ -1472,6 +1472,11 @@ static int kvm_vcpu_enable_sbi_dbcn(RISCVCPU *cpu, CPUState *cs)
|
|||
return kvm_set_one_reg(cs, kvm_sbi_dbcn.kvm_reg_id, ®);
|
||||
}
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
|
@ -398,6 +398,11 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
|
|||
return cpu->cpu_index;
|
||||
}
|
||||
|
||||
int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
|
||||
|
|
|
@ -27,5 +27,5 @@ if host_os == 'linux'
|
|||
tcg_ss.add(files('perf.c'))
|
||||
endif
|
||||
|
||||
libuser_ss.add_all(tcg_ss)
|
||||
libsystem_ss.add_all(tcg_ss)
|
||||
user_ss.add_all(tcg_ss)
|
||||
system_ss.add_all(tcg_ss)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue