2019-10-08 12:56:49 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
|
|
|
* Copyright (c) 2019 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qemu/error-report.h"
|
|
|
|
#include "qemu/units.h"
|
|
|
|
#include "qapi/error.h"
|
|
|
|
#include "qapi/qapi-visit-common.h"
|
vl: Add sgx compound properties to expose SGX EPC sections to guest
Because SGX EPC is enumerated through CPUID, EPC "devices" need to be
realized prior to realizing the vCPUs themselves, i.e. long before
generic devices are parsed and realized. From a virtualization
perspective, the CPUID aspect also means that EPC sections cannot be
hotplugged without paravirtualizing the guest kernel (hardware does
not support hotplugging as EPC sections must be locked down during
pre-boot to provide EPC's security properties).
So even though EPC sections could be realized through the generic
-devices command, they need to be created much earlier for them to
actually be usable by the guest. Place all EPC sections in a
contiguous block, somewhat arbitrarily starting after RAM above 4g.
Ensuring EPC is in a contiguous region simplifies calculations, e.g.
device memory base, PCI hole, etc..., allows dynamic calculation of the
total EPC size, e.g. exposing EPC to guests does not require -maxmem,
and last but not least allows all of EPC to be enumerated in a single
ACPI entry, which is expected by some kernels, e.g. Windows 7 and 8.
The new compound properties command for sgx like below:
......
-object memory-backend-epc,id=mem1,size=28M,prealloc=on \
-object memory-backend-epc,id=mem2,size=10M \
-M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20210719112136.57018-6-yang.zhong@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2021-09-28 11:40:58 +03:00
|
|
|
#include "qapi/qapi-visit-machine.h"
|
2019-10-08 12:56:49 +03:00
|
|
|
#include "qapi/visitor.h"
|
|
|
|
#include "sysemu/qtest.h"
|
|
|
|
#include "sysemu/numa.h"
|
2019-12-12 16:14:40 +03:00
|
|
|
#include "trace.h"
|
2019-10-08 12:56:49 +03:00
|
|
|
|
2024-05-09 20:00:41 +03:00
|
|
|
#include "hw/acpi/aml-build.h"
|
2019-10-08 12:56:49 +03:00
|
|
|
#include "hw/i386/x86.h"
|
|
|
|
#include "hw/i386/topology.h"
|
|
|
|
|
|
|
|
#include "hw/nmi.h"
|
2020-12-12 18:55:08 +03:00
|
|
|
#include "kvm/kvm_i386.h"
|
2019-10-08 12:56:49 +03:00
|
|
|
|
2023-01-13 23:41:19 +03:00
|
|
|
|
2024-05-09 20:00:41 +03:00
|
|
|
void init_topo_info(X86CPUTopoInfo *topo_info,
|
|
|
|
const X86MachineState *x86ms)
|
2020-03-12 01:52:52 +03:00
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(x86ms);
|
|
|
|
|
2021-06-17 18:53:03 +03:00
|
|
|
topo_info->dies_per_pkg = ms->smp.dies;
|
2024-04-24 18:49:21 +03:00
|
|
|
/*
|
|
|
|
* Though smp.modules means the number of modules in one cluster,
|
|
|
|
* i386 doesn't support cluster level so that the smp.clusters
|
|
|
|
* always defaults to 1, therefore using smp.modules directly is
|
|
|
|
* fine here.
|
|
|
|
*/
|
|
|
|
topo_info->modules_per_die = ms->smp.modules;
|
|
|
|
topo_info->cores_per_module = ms->smp.cores;
|
2020-03-12 01:52:52 +03:00
|
|
|
topo_info->threads_per_core = ms->smp.threads;
|
|
|
|
}
|
|
|
|
|
2019-10-08 12:56:49 +03:00
|
|
|
/*
|
|
|
|
* Calculates initial APIC ID for a specific CPU index
|
|
|
|
*
|
|
|
|
* Currently we need to be able to calculate the APIC ID from the CPU index
|
|
|
|
* alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
|
|
|
|
* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
|
|
|
|
* all CPUs up to max_cpus.
|
|
|
|
*/
|
2019-09-30 18:26:29 +03:00
|
|
|
uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms,
|
2019-10-08 12:56:49 +03:00
|
|
|
unsigned int cpu_index)
|
|
|
|
{
|
2020-03-12 01:52:52 +03:00
|
|
|
X86CPUTopoInfo topo_info;
|
2019-10-08 12:56:49 +03:00
|
|
|
|
2020-03-12 01:52:52 +03:00
|
|
|
init_topo_info(&topo_info, x86ms);
|
|
|
|
|
2022-02-28 16:16:34 +03:00
|
|
|
return x86_apicid_from_cpu_idx(&topo_info, cpu_index);
|
2019-10-08 12:56:49 +03:00
|
|
|
}
|
|
|
|
|
2024-05-09 20:00:40 +03:00
|
|
|
static CpuInstanceProperties
|
2019-10-08 12:56:49 +03:00
|
|
|
x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
|
|
|
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
|
|
|
|
|
|
|
|
assert(cpu_index < possible_cpus->len);
|
|
|
|
return possible_cpus->cpus[cpu_index].props;
|
|
|
|
}
|
|
|
|
|
2024-05-09 20:00:40 +03:00
|
|
|
static int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx)
|
2019-10-08 12:56:49 +03:00
|
|
|
{
|
2020-03-03 22:56:58 +03:00
|
|
|
X86CPUTopoIDs topo_ids;
|
2019-10-22 10:39:50 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(ms);
|
2020-03-12 01:52:52 +03:00
|
|
|
X86CPUTopoInfo topo_info;
|
|
|
|
|
|
|
|
init_topo_info(&topo_info, x86ms);
|
2019-10-08 12:56:49 +03:00
|
|
|
|
|
|
|
assert(idx < ms->possible_cpus->len);
|
2020-08-31 21:42:23 +03:00
|
|
|
x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id,
|
|
|
|
&topo_info, &topo_ids);
|
2020-03-03 22:56:58 +03:00
|
|
|
return topo_ids.pkg_id % ms->numa_state->num_nodes;
|
2019-10-08 12:56:49 +03:00
|
|
|
}
|
|
|
|
|
2024-05-09 20:00:40 +03:00
|
|
|
static const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms)
|
2019-10-08 12:56:49 +03:00
|
|
|
{
|
2019-10-22 10:39:50 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(ms);
|
2019-10-08 12:56:49 +03:00
|
|
|
unsigned int max_cpus = ms->smp.max_cpus;
|
2020-03-12 01:52:52 +03:00
|
|
|
X86CPUTopoInfo topo_info;
|
|
|
|
int i;
|
2019-10-08 12:56:49 +03:00
|
|
|
|
|
|
|
if (ms->possible_cpus) {
|
|
|
|
/*
|
|
|
|
* make sure that max_cpus hasn't changed since the first use, i.e.
|
|
|
|
* -smp hasn't been parsed after it
|
|
|
|
*/
|
|
|
|
assert(ms->possible_cpus->len == max_cpus);
|
|
|
|
return ms->possible_cpus;
|
|
|
|
}
|
|
|
|
|
|
|
|
ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
|
|
|
|
sizeof(CPUArchId) * max_cpus);
|
|
|
|
ms->possible_cpus->len = max_cpus;
|
2020-03-12 01:52:52 +03:00
|
|
|
|
|
|
|
init_topo_info(&topo_info, x86ms);
|
|
|
|
|
2019-10-08 12:56:49 +03:00
|
|
|
for (i = 0; i < ms->possible_cpus->len; i++) {
|
2020-03-03 22:56:58 +03:00
|
|
|
X86CPUTopoIDs topo_ids;
|
2019-10-08 12:56:49 +03:00
|
|
|
|
|
|
|
ms->possible_cpus->cpus[i].type = ms->cpu_type;
|
|
|
|
ms->possible_cpus->cpus[i].vcpus_count = 1;
|
2020-08-31 21:42:23 +03:00
|
|
|
ms->possible_cpus->cpus[i].arch_id =
|
|
|
|
x86_cpu_apic_id_from_index(x86ms, i);
|
|
|
|
x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id,
|
|
|
|
&topo_info, &topo_ids);
|
2019-10-08 12:56:49 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.has_socket_id = true;
|
2020-03-03 22:56:58 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.socket_id = topo_ids.pkg_id;
|
2021-06-17 18:53:03 +03:00
|
|
|
if (ms->smp.dies > 1) {
|
2019-10-08 12:56:49 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.has_die_id = true;
|
2020-03-03 22:56:58 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.die_id = topo_ids.die_id;
|
2019-10-08 12:56:49 +03:00
|
|
|
}
|
2024-04-24 18:49:23 +03:00
|
|
|
if (ms->smp.modules > 1) {
|
|
|
|
ms->possible_cpus->cpus[i].props.has_module_id = true;
|
|
|
|
ms->possible_cpus->cpus[i].props.module_id = topo_ids.module_id;
|
|
|
|
}
|
2019-10-08 12:56:49 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.has_core_id = true;
|
2020-03-03 22:56:58 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.core_id = topo_ids.core_id;
|
2019-10-08 12:56:49 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.has_thread_id = true;
|
2020-03-03 22:56:58 +03:00
|
|
|
ms->possible_cpus->cpus[i].props.thread_id = topo_ids.smt_id;
|
2019-10-08 12:56:49 +03:00
|
|
|
}
|
|
|
|
return ms->possible_cpus;
|
|
|
|
}
|
|
|
|
|
2019-10-22 10:39:50 +03:00
|
|
|
static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
|
|
|
|
{
|
|
|
|
/* cpu index isn't used */
|
|
|
|
CPUState *cs;
|
|
|
|
|
|
|
|
CPU_FOREACH(cs) {
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
2024-01-06 16:25:45 +03:00
|
|
|
if (cpu_is_apic_enabled(cpu->apic_state)) {
|
2019-10-22 10:39:50 +03:00
|
|
|
apic_deliver_nmi(cpu->apic_state);
|
2024-01-06 16:25:44 +03:00
|
|
|
} else {
|
|
|
|
cpu_interrupt(cs, CPU_INTERRUPT_NMI);
|
2019-10-22 10:39:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 15:09:01 +03:00
|
|
|
bool x86_machine_is_smm_enabled(const X86MachineState *x86ms)
|
2019-12-12 19:28:01 +03:00
|
|
|
{
|
|
|
|
bool smm_available = false;
|
|
|
|
|
|
|
|
if (x86ms->smm == ON_OFF_AUTO_OFF) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tcg_enabled() || qtest_enabled()) {
|
|
|
|
smm_available = true;
|
|
|
|
} else if (kvm_enabled()) {
|
|
|
|
smm_available = kvm_has_smm();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (smm_available) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x86ms->smm == ON_OFF_AUTO_ON) {
|
|
|
|
error_report("System Management Mode not supported by this hypervisor.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_get_smm(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
OnOffAuto smm = x86ms->smm;
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &smm, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_smm(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &x86ms->smm, errp);
|
|
|
|
}
|
|
|
|
|
2020-09-15 15:09:01 +03:00
|
|
|
bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms)
|
2020-03-20 13:01:36 +03:00
|
|
|
{
|
|
|
|
if (x86ms->acpi == ON_OFF_AUTO_OFF) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_get_acpi(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
OnOffAuto acpi = x86ms->acpi;
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &acpi, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_acpi(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &x86ms->acpi, errp);
|
|
|
|
}
|
|
|
|
|
2022-03-10 15:28:10 +03:00
|
|
|
static void x86_machine_get_pit(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
OnOffAuto pit = x86ms->pit;
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &pit, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_pit(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);;
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &x86ms->pit, errp);
|
|
|
|
}
|
|
|
|
|
2022-03-10 15:28:11 +03:00
|
|
|
static void x86_machine_get_pic(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
OnOffAuto pic = x86ms->pic;
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &pic, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_pic(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &x86ms->pic, errp);
|
|
|
|
}
|
|
|
|
|
2021-02-21 03:17:36 +03:00
|
|
|
static char *x86_machine_get_oem_id(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(x86ms->oem_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_oem_id(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
size_t len = strlen(value);
|
|
|
|
|
|
|
|
if (len > 6) {
|
|
|
|
error_setg(errp,
|
|
|
|
"User specified "X86_MACHINE_OEM_ID" value is bigger than "
|
|
|
|
"6 bytes in size");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(x86ms->oem_id, value, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *x86_machine_get_oem_table_id(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(x86ms->oem_table_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_oem_table_id(Object *obj, const char *value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
size_t len = strlen(value);
|
|
|
|
|
|
|
|
if (len > 8) {
|
|
|
|
error_setg(errp,
|
|
|
|
"User specified "X86_MACHINE_OEM_TABLE_ID
|
|
|
|
" value is bigger than "
|
|
|
|
"8 bytes in size");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
strncpy(x86ms->oem_table_id, value, 8);
|
|
|
|
}
|
|
|
|
|
2021-05-21 07:38:20 +03:00
|
|
|
static void x86_machine_get_bus_lock_ratelimit(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
uint64_t bus_lock_ratelimit = x86ms->bus_lock_ratelimit;
|
|
|
|
|
|
|
|
visit_type_uint64(v, name, &bus_lock_ratelimit, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_set_bus_lock_ratelimit(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
|
|
|
visit_type_uint64(v, name, &x86ms->bus_lock_ratelimit, errp);
|
|
|
|
}
|
|
|
|
|
vl: Add sgx compound properties to expose SGX EPC sections to guest
Because SGX EPC is enumerated through CPUID, EPC "devices" need to be
realized prior to realizing the vCPUs themselves, i.e. long before
generic devices are parsed and realized. From a virtualization
perspective, the CPUID aspect also means that EPC sections cannot be
hotplugged without paravirtualizing the guest kernel (hardware does
not support hotplugging as EPC sections must be locked down during
pre-boot to provide EPC's security properties).
So even though EPC sections could be realized through the generic
-devices command, they need to be created much earlier for them to
actually be usable by the guest. Place all EPC sections in a
contiguous block, somewhat arbitrarily starting after RAM above 4g.
Ensuring EPC is in a contiguous region simplifies calculations, e.g.
device memory base, PCI hole, etc..., allows dynamic calculation of the
total EPC size, e.g. exposing EPC to guests does not require -maxmem,
and last but not least allows all of EPC to be enumerated in a single
ACPI entry, which is expected by some kernels, e.g. Windows 7 and 8.
The new compound properties command for sgx like below:
......
-object memory-backend-epc,id=mem1,size=28M,prealloc=on \
-object memory-backend-epc,id=mem2,size=10M \
-M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20210719112136.57018-6-yang.zhong@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2021-09-28 11:40:58 +03:00
|
|
|
static void machine_get_sgx_epc(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
SgxEPCList *list = x86ms->sgx_epc_list;
|
|
|
|
|
|
|
|
visit_type_SgxEPCList(v, name, &list, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_sgx_epc(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
SgxEPCList *list;
|
|
|
|
|
|
|
|
list = x86ms->sgx_epc_list;
|
|
|
|
visit_type_SgxEPCList(v, name, &x86ms->sgx_epc_list, errp);
|
|
|
|
|
|
|
|
qapi_free_SgxEPCList(list);
|
|
|
|
}
|
|
|
|
|
target/i386: Implement mc->kvm_type() to get VM type
KVM is introducing a new API to create confidential guests, which
will be used by TDX and SEV-SNP but is also available for SEV and
SEV-ES. The API uses the VM type argument to KVM_CREATE_VM to
identify which confidential computing technology to use.
Since there are no other expected uses of VM types, delegate
mc->kvm_type() for x86 boards to the confidential-guest-support
object pointed to by ms->cgs.
For example, if a sev-guest object is specified to confidential-guest-support,
like,
qemu -machine ...,confidential-guest-support=sev0 \
-object sev-guest,id=sev0,...
it will check if a VM type KVM_X86_SEV_VM or KVM_X86_SEV_ES_VM
is supported, and if so use them together with the KVM_SEV_INIT2
function of the KVM_MEMORY_ENCRYPT_OP ioctl. If not, it will fall back to
KVM_SEV_INIT and KVM_SEV_ES_INIT.
This is a preparatory work towards TDX and SEV-SNP support, but it
will also enable support for VMSA features such as DebugSwap, which
are only available via KVM_SEV_INIT2.
Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-19 17:29:33 +03:00
|
|
|
static int x86_kvm_type(MachineState *ms, const char *vm_type)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* No x86 machine has a kvm-type property. If one is added that has
|
|
|
|
* it, it should call kvm_get_vm_type() directly or not use it at all.
|
|
|
|
*/
|
|
|
|
assert(vm_type == NULL);
|
|
|
|
return kvm_enabled() ? kvm_get_vm_type(ms) : 0;
|
|
|
|
}
|
|
|
|
|
2019-10-22 10:39:50 +03:00
|
|
|
static void x86_machine_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
|
|
|
|
2019-12-12 19:28:01 +03:00
|
|
|
x86ms->smm = ON_OFF_AUTO_AUTO;
|
2020-03-20 13:01:36 +03:00
|
|
|
x86ms->acpi = ON_OFF_AUTO_AUTO;
|
2022-03-10 15:28:10 +03:00
|
|
|
x86ms->pit = ON_OFF_AUTO_AUTO;
|
2022-03-10 15:28:11 +03:00
|
|
|
x86ms->pic = ON_OFF_AUTO_AUTO;
|
2020-10-16 14:38:31 +03:00
|
|
|
x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS;
|
2021-02-21 03:17:36 +03:00
|
|
|
x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
|
|
|
|
x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
2021-05-21 07:38:20 +03:00
|
|
|
x86ms->bus_lock_ratelimit = 0;
|
2022-07-19 20:00:04 +03:00
|
|
|
x86ms->above_4g_mem_start = 4 * GiB;
|
2019-10-22 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_machine_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
|
|
|
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
|
|
|
|
NMIClass *nc = NMI_CLASS(oc);
|
|
|
|
|
|
|
|
mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
|
|
|
|
mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
|
|
|
|
mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
|
target/i386: Implement mc->kvm_type() to get VM type
KVM is introducing a new API to create confidential guests, which
will be used by TDX and SEV-SNP but is also available for SEV and
SEV-ES. The API uses the VM type argument to KVM_CREATE_VM to
identify which confidential computing technology to use.
Since there are no other expected uses of VM types, delegate
mc->kvm_type() for x86 boards to the confidential-guest-support
object pointed to by ms->cgs.
For example, if a sev-guest object is specified to confidential-guest-support,
like,
qemu -machine ...,confidential-guest-support=sev0 \
-object sev-guest,id=sev0,...
it will check if a VM type KVM_X86_SEV_VM or KVM_X86_SEV_ES_VM
is supported, and if so use them together with the KVM_SEV_INIT2
function of the KVM_MEMORY_ENCRYPT_OP ioctl. If not, it will fall back to
KVM_SEV_INIT and KVM_SEV_ES_INIT.
This is a preparatory work towards TDX and SEV-SNP support, but it
will also enable support for VMSA features such as DebugSwap, which
are only available via KVM_SEV_INIT2.
Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-19 17:29:33 +03:00
|
|
|
mc->kvm_type = x86_kvm_type;
|
2019-11-18 14:13:25 +03:00
|
|
|
x86mc->save_tsc_khz = true;
|
2021-10-20 15:48:10 +03:00
|
|
|
x86mc->fwcfg_dma_enabled = true;
|
2019-10-22 10:39:50 +03:00
|
|
|
nc->nmi_monitor_handler = x86_nmi;
|
|
|
|
|
2019-12-12 19:28:01 +03:00
|
|
|
object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto",
|
|
|
|
x86_machine_get_smm, x86_machine_set_smm,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
NULL, NULL);
|
2019-12-12 19:28:01 +03:00
|
|
|
object_class_property_set_description(oc, X86_MACHINE_SMM,
|
2020-05-05 18:29:15 +03:00
|
|
|
"Enable SMM");
|
2020-03-20 13:01:36 +03:00
|
|
|
|
|
|
|
object_class_property_add(oc, X86_MACHINE_ACPI, "OnOffAuto",
|
|
|
|
x86_machine_get_acpi, x86_machine_set_acpi,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
NULL, NULL);
|
2020-03-20 13:01:36 +03:00
|
|
|
object_class_property_set_description(oc, X86_MACHINE_ACPI,
|
2020-05-05 18:29:15 +03:00
|
|
|
"Enable ACPI");
|
2021-02-21 03:17:36 +03:00
|
|
|
|
2022-03-10 15:28:10 +03:00
|
|
|
object_class_property_add(oc, X86_MACHINE_PIT, "OnOffAuto",
|
|
|
|
x86_machine_get_pit,
|
|
|
|
x86_machine_set_pit,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, X86_MACHINE_PIT,
|
|
|
|
"Enable i8254 PIT");
|
|
|
|
|
2022-03-10 15:28:11 +03:00
|
|
|
object_class_property_add(oc, X86_MACHINE_PIC, "OnOffAuto",
|
|
|
|
x86_machine_get_pic,
|
|
|
|
x86_machine_set_pic,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, X86_MACHINE_PIC,
|
|
|
|
"Enable i8259 PIC");
|
|
|
|
|
2021-02-21 03:17:36 +03:00
|
|
|
object_class_property_add_str(oc, X86_MACHINE_OEM_ID,
|
|
|
|
x86_machine_get_oem_id,
|
|
|
|
x86_machine_set_oem_id);
|
|
|
|
object_class_property_set_description(oc, X86_MACHINE_OEM_ID,
|
|
|
|
"Override the default value of field OEMID "
|
|
|
|
"in ACPI table header."
|
|
|
|
"The string may be up to 6 bytes in size");
|
|
|
|
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, X86_MACHINE_OEM_TABLE_ID,
|
|
|
|
x86_machine_get_oem_table_id,
|
|
|
|
x86_machine_set_oem_table_id);
|
|
|
|
object_class_property_set_description(oc, X86_MACHINE_OEM_TABLE_ID,
|
|
|
|
"Override the default value of field OEM Table ID "
|
|
|
|
"in ACPI table header."
|
|
|
|
"The string may be up to 8 bytes in size");
|
2021-05-21 07:38:20 +03:00
|
|
|
|
|
|
|
object_class_property_add(oc, X86_MACHINE_BUS_LOCK_RATELIMIT, "uint64_t",
|
|
|
|
x86_machine_get_bus_lock_ratelimit,
|
|
|
|
x86_machine_set_bus_lock_ratelimit, NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, X86_MACHINE_BUS_LOCK_RATELIMIT,
|
|
|
|
"Set the ratelimit for the bus locks acquired in VMs");
|
vl: Add sgx compound properties to expose SGX EPC sections to guest
Because SGX EPC is enumerated through CPUID, EPC "devices" need to be
realized prior to realizing the vCPUs themselves, i.e. long before
generic devices are parsed and realized. From a virtualization
perspective, the CPUID aspect also means that EPC sections cannot be
hotplugged without paravirtualizing the guest kernel (hardware does
not support hotplugging as EPC sections must be locked down during
pre-boot to provide EPC's security properties).
So even though EPC sections could be realized through the generic
-devices command, they need to be created much earlier for them to
actually be usable by the guest. Place all EPC sections in a
contiguous block, somewhat arbitrarily starting after RAM above 4g.
Ensuring EPC is in a contiguous region simplifies calculations, e.g.
device memory base, PCI hole, etc..., allows dynamic calculation of the
total EPC size, e.g. exposing EPC to guests does not require -maxmem,
and last but not least allows all of EPC to be enumerated in a single
ACPI entry, which is expected by some kernels, e.g. Windows 7 and 8.
The new compound properties command for sgx like below:
......
-object memory-backend-epc,id=mem1,size=28M,prealloc=on \
-object memory-backend-epc,id=mem2,size=10M \
-M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20210719112136.57018-6-yang.zhong@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2021-09-28 11:40:58 +03:00
|
|
|
|
|
|
|
object_class_property_add(oc, "sgx-epc", "SgxEPC",
|
|
|
|
machine_get_sgx_epc, machine_set_sgx_epc,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, "sgx-epc",
|
|
|
|
"SGX EPC device");
|
2019-10-22 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo x86_machine_info = {
|
|
|
|
.name = TYPE_X86_MACHINE,
|
|
|
|
.parent = TYPE_MACHINE,
|
|
|
|
.abstract = true,
|
|
|
|
.instance_size = sizeof(X86MachineState),
|
|
|
|
.instance_init = x86_machine_initfn,
|
|
|
|
.class_size = sizeof(X86MachineClass),
|
|
|
|
.class_init = x86_machine_class_init,
|
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_NMI },
|
|
|
|
{ }
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static void x86_machine_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&x86_machine_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(x86_machine_register_types)
|