2010-03-11 16:38:55 +03:00
|
|
|
/*
|
|
|
|
* i386 CPUID helper functions
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2016-02-23 14:58:02 +03:00
|
|
|
#include "qemu/osdep.h"
|
2016-03-20 20:16:19 +03:00
|
|
|
#include "qemu/cutils.h"
|
2010-03-11 16:38:55 +03:00
|
|
|
|
|
|
|
#include "cpu.h"
|
2016-03-15 15:18:37 +03:00
|
|
|
#include "exec/exec-all.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/kvm.h"
|
2013-01-23 00:25:09 +04:00
|
|
|
#include "sysemu/cpus.h"
|
2013-03-20 16:11:56 +04:00
|
|
|
#include "kvm_i386.h"
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2015-03-17 20:29:20 +03:00
|
|
|
#include "qemu/error-report.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qemu/config-file.h"
|
2012-12-17 21:19:43 +04:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2017-02-22 22:00:28 +03:00
|
|
|
#include "qapi/qmp/qstring.h"
|
|
|
|
#include "qapi/qmp/qdict.h"
|
|
|
|
#include "qapi/qmp/qbool.h"
|
|
|
|
#include "qapi/qmp/qint.h"
|
|
|
|
#include "qapi/qmp/qfloat.h"
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2013-05-06 20:20:07 +04:00
|
|
|
#include "qapi-types.h"
|
|
|
|
#include "qapi-visit.h"
|
2012-12-17 21:19:43 +04:00
|
|
|
#include "qapi/visitor.h"
|
2017-02-22 22:00:28 +03:00
|
|
|
#include "qom/qom-qobject.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/arch_init.h"
|
2012-04-17 14:10:29 +04:00
|
|
|
|
2012-08-31 00:28:31 +04:00
|
|
|
#if defined(CONFIG_KVM)
|
2012-08-29 18:32:41 +04:00
|
|
|
#include <linux/kvm_para.h>
|
2012-08-31 00:28:31 +04:00
|
|
|
#endif
|
2012-07-23 17:22:28 +04:00
|
|
|
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/sysemu.h"
|
2013-04-29 21:03:01 +04:00
|
|
|
#include "hw/qdev-properties.h"
|
2016-05-12 20:24:26 +03:00
|
|
|
#include "hw/i386/topology.h"
|
2012-10-14 00:35:39 +04:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2015-03-31 15:11:09 +03:00
|
|
|
#include "exec/address-spaces.h"
|
2014-06-27 10:40:04 +04:00
|
|
|
#include "hw/hw.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/xen/xen.h"
|
|
|
|
#include "hw/i386/apic_internal.h"
|
2012-10-14 00:35:39 +04:00
|
|
|
#endif
|
|
|
|
|
2013-08-27 19:24:37 +04:00
|
|
|
|
|
|
|
/* Cache topology CPUID constants: */
|
|
|
|
|
|
|
|
/* CPUID Leaf 2 Descriptors */
|
|
|
|
|
|
|
|
#define CPUID_2_L1D_32KB_8WAY_64B 0x2c
|
|
|
|
#define CPUID_2_L1I_32KB_8WAY_64B 0x30
|
|
|
|
#define CPUID_2_L2_2MB_8WAY_64B 0x7d
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
#define CPUID_2_L3_16MB_16WAY_64B 0x4d
|
2013-08-27 19:24:37 +04:00
|
|
|
|
|
|
|
|
|
|
|
/* CPUID Leaf 4 constants: */
|
|
|
|
|
|
|
|
/* EAX: */
|
|
|
|
#define CPUID_4_TYPE_DCACHE 1
|
|
|
|
#define CPUID_4_TYPE_ICACHE 2
|
|
|
|
#define CPUID_4_TYPE_UNIFIED 3
|
|
|
|
|
|
|
|
#define CPUID_4_LEVEL(l) ((l) << 5)
|
|
|
|
|
|
|
|
#define CPUID_4_SELF_INIT_LEVEL (1 << 8)
|
|
|
|
#define CPUID_4_FULLY_ASSOC (1 << 9)
|
|
|
|
|
|
|
|
/* EDX: */
|
|
|
|
#define CPUID_4_NO_INVD_SHARING (1 << 0)
|
|
|
|
#define CPUID_4_INCLUSIVE (1 << 1)
|
|
|
|
#define CPUID_4_COMPLEX_IDX (1 << 2)
|
|
|
|
|
|
|
|
#define ASSOC_FULL 0xFF
|
|
|
|
|
|
|
|
/* AMD associativity encoding used on CPUID Leaf 0x80000006: */
|
|
|
|
#define AMD_ENC_ASSOC(a) (a <= 1 ? a : \
|
|
|
|
a == 2 ? 0x2 : \
|
|
|
|
a == 4 ? 0x4 : \
|
|
|
|
a == 8 ? 0x6 : \
|
|
|
|
a == 16 ? 0x8 : \
|
|
|
|
a == 32 ? 0xA : \
|
|
|
|
a == 48 ? 0xB : \
|
|
|
|
a == 64 ? 0xC : \
|
|
|
|
a == 96 ? 0xD : \
|
|
|
|
a == 128 ? 0xE : \
|
|
|
|
a == ASSOC_FULL ? 0xF : \
|
|
|
|
0 /* invalid value */)
|
|
|
|
|
|
|
|
|
|
|
|
/* Definitions of the hardcoded cache entries we expose: */
|
|
|
|
|
|
|
|
/* L1 data cache: */
|
|
|
|
#define L1D_LINE_SIZE 64
|
|
|
|
#define L1D_ASSOCIATIVITY 8
|
|
|
|
#define L1D_SETS 64
|
|
|
|
#define L1D_PARTITIONS 1
|
|
|
|
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
|
|
|
|
#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B
|
|
|
|
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
|
|
|
|
#define L1D_LINES_PER_TAG 1
|
|
|
|
#define L1D_SIZE_KB_AMD 64
|
|
|
|
#define L1D_ASSOCIATIVITY_AMD 2
|
|
|
|
|
|
|
|
/* L1 instruction cache: */
|
|
|
|
#define L1I_LINE_SIZE 64
|
|
|
|
#define L1I_ASSOCIATIVITY 8
|
|
|
|
#define L1I_SETS 64
|
|
|
|
#define L1I_PARTITIONS 1
|
|
|
|
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
|
|
|
|
#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B
|
|
|
|
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
|
|
|
|
#define L1I_LINES_PER_TAG 1
|
|
|
|
#define L1I_SIZE_KB_AMD 64
|
|
|
|
#define L1I_ASSOCIATIVITY_AMD 2
|
|
|
|
|
|
|
|
/* Level 2 unified cache: */
|
|
|
|
#define L2_LINE_SIZE 64
|
|
|
|
#define L2_ASSOCIATIVITY 16
|
|
|
|
#define L2_SETS 4096
|
|
|
|
#define L2_PARTITIONS 1
|
|
|
|
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */
|
|
|
|
/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */
|
|
|
|
#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B
|
|
|
|
/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */
|
|
|
|
#define L2_LINES_PER_TAG 1
|
|
|
|
#define L2_SIZE_KB_AMD 512
|
|
|
|
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
/* Level 3 unified cache: */
|
2013-08-27 19:24:37 +04:00
|
|
|
#define L3_SIZE_KB 0 /* disabled */
|
|
|
|
#define L3_ASSOCIATIVITY 0 /* disabled */
|
|
|
|
#define L3_LINES_PER_TAG 0 /* disabled */
|
|
|
|
#define L3_LINE_SIZE 0 /* disabled */
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
#define L3_N_LINE_SIZE 64
|
|
|
|
#define L3_N_ASSOCIATIVITY 16
|
|
|
|
#define L3_N_SETS 16384
|
|
|
|
#define L3_N_PARTITIONS 1
|
|
|
|
#define L3_N_DESCRIPTOR CPUID_2_L3_16MB_16WAY_64B
|
|
|
|
#define L3_N_LINES_PER_TAG 1
|
|
|
|
#define L3_N_SIZE_KB_AMD 16384
|
2013-08-27 19:24:37 +04:00
|
|
|
|
|
|
|
/* TLB definitions: */
|
|
|
|
|
|
|
|
#define L1_DTLB_2M_ASSOC 1
|
|
|
|
#define L1_DTLB_2M_ENTRIES 255
|
|
|
|
#define L1_DTLB_4K_ASSOC 1
|
|
|
|
#define L1_DTLB_4K_ENTRIES 255
|
|
|
|
|
|
|
|
#define L1_ITLB_2M_ASSOC 1
|
|
|
|
#define L1_ITLB_2M_ENTRIES 255
|
|
|
|
#define L1_ITLB_4K_ASSOC 1
|
|
|
|
#define L1_ITLB_4K_ENTRIES 255
|
|
|
|
|
|
|
|
#define L2_DTLB_2M_ASSOC 0 /* disabled */
|
|
|
|
#define L2_DTLB_2M_ENTRIES 0 /* disabled */
|
|
|
|
#define L2_DTLB_4K_ASSOC 4
|
|
|
|
#define L2_DTLB_4K_ENTRIES 512
|
|
|
|
|
|
|
|
#define L2_ITLB_2M_ASSOC 0 /* disabled */
|
|
|
|
#define L2_ITLB_2M_ENTRIES 0 /* disabled */
|
|
|
|
#define L2_ITLB_4K_ASSOC 4
|
|
|
|
#define L2_ITLB_4K_ENTRIES 512
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-01-21 18:06:36 +04:00
|
|
|
static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
|
|
|
|
uint32_t vendor2, uint32_t vendor3)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
dst[i] = vendor1 >> (8 * i);
|
|
|
|
dst[i + 4] = vendor2 >> (8 * i);
|
|
|
|
dst[i + 8] = vendor3 >> (8 * i);
|
|
|
|
}
|
|
|
|
dst[CPUID_VENDOR_SZ] = '\0';
|
|
|
|
}
|
|
|
|
|
2014-04-30 20:48:36 +04:00
|
|
|
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
|
|
|
|
#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
|
|
|
|
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
|
|
|
|
#define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \
|
|
|
|
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
|
|
|
|
CPUID_PSE36 | CPUID_FXSR)
|
|
|
|
#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE)
|
|
|
|
#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
|
|
|
|
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
|
|
|
|
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
|
|
|
|
CPUID_PAE | CPUID_SEP | CPUID_APIC)
|
|
|
|
|
|
|
|
#define TCG_FEATURES (CPUID_FP87 | CPUID_PSE | CPUID_TSC | CPUID_MSR | \
|
|
|
|
CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
|
|
|
|
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
|
|
|
|
CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
|
2015-10-07 22:39:43 +03:00
|
|
|
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE)
|
2014-04-30 20:48:36 +04:00
|
|
|
/* partly implemented:
|
|
|
|
CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */
|
|
|
|
/* missing:
|
|
|
|
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
|
|
|
#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | \
|
|
|
|
CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | \
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
|
2015-07-02 16:53:40 +03:00
|
|
|
CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \
|
2014-04-30 20:48:36 +04:00
|
|
|
CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR)
|
|
|
|
/* missing:
|
|
|
|
CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX,
|
|
|
|
CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA,
|
|
|
|
CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA,
|
2015-07-02 16:53:40 +03:00
|
|
|
CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AVX,
|
|
|
|
CPUID_EXT_F16C, CPUID_EXT_RDRAND */
|
2014-04-30 20:48:36 +04:00
|
|
|
|
|
|
|
#ifdef TARGET_X86_64
|
|
|
|
#define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM)
|
|
|
|
#else
|
|
|
|
#define TCG_EXT2_X86_64_FEATURES 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \
|
|
|
|
CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
|
|
|
|
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \
|
|
|
|
TCG_EXT2_X86_64_FEATURES)
|
|
|
|
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
|
|
|
|
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
|
|
|
|
#define TCG_EXT4_FEATURES 0
|
|
|
|
#define TCG_SVM_FEATURES 0
|
|
|
|
#define TCG_KVM_FEATURES 0
|
|
|
|
#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \
|
2015-10-29 10:31:39 +03:00
|
|
|
CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
|
|
|
|
CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \
|
2016-06-17 18:47:13 +03:00
|
|
|
CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \
|
|
|
|
CPUID_7_0_EBX_ERMS)
|
2014-04-30 20:48:36 +04:00
|
|
|
/* missing:
|
2015-11-18 14:55:47 +03:00
|
|
|
CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
|
2016-06-17 18:47:13 +03:00
|
|
|
CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
|
2014-04-30 20:48:36 +04:00
|
|
|
CPUID_7_0_EBX_RDSEED */
|
2016-12-15 03:13:05 +03:00
|
|
|
#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE | \
|
|
|
|
CPUID_7_0_ECX_LA57)
|
2016-10-31 11:27:26 +03:00
|
|
|
#define TCG_7_0_EDX_FEATURES 0
|
2014-04-30 20:48:45 +04:00
|
|
|
#define TCG_APM_FEATURES 0
|
2015-06-07 12:15:08 +03:00
|
|
|
#define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
|
2015-07-02 17:21:23 +03:00
|
|
|
#define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1)
|
|
|
|
/* missing:
|
|
|
|
CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
|
2014-04-30 20:48:36 +04:00
|
|
|
|
2013-01-07 22:20:45 +04:00
|
|
|
typedef struct FeatureWordInfo {
|
2016-05-12 17:24:04 +03:00
|
|
|
/* feature flags names are taken from "Intel Processor Identification and
|
|
|
|
* the CPUID Instruction" and AMD's "CPUID Specification".
|
|
|
|
* In cases of disagreement between feature naming conventions,
|
|
|
|
* aliases may be added.
|
|
|
|
*/
|
|
|
|
const char *feat_names[32];
|
2013-04-22 23:00:16 +04:00
|
|
|
uint32_t cpuid_eax; /* Input EAX for CPUID */
|
|
|
|
bool cpuid_needs_ecx; /* CPUID instruction uses ECX as input */
|
|
|
|
uint32_t cpuid_ecx; /* Input ECX value for CPUID */
|
|
|
|
int cpuid_reg; /* output register (R_* constant) */
|
2014-04-30 20:48:38 +04:00
|
|
|
uint32_t tcg_features; /* Feature flags supported by TCG */
|
2014-04-30 20:48:41 +04:00
|
|
|
uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */
|
2016-09-28 18:00:29 +03:00
|
|
|
uint32_t migratable_flags; /* Feature flags known to be migratable */
|
2013-01-07 22:20:45 +04:00
|
|
|
} FeatureWordInfo;
|
|
|
|
|
|
|
|
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
2013-01-07 22:20:46 +04:00
|
|
|
[FEAT_1_EDX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
"fpu", "vme", "de", "pse",
|
|
|
|
"tsc", "msr", "pae", "mce",
|
|
|
|
"cx8", "apic", NULL, "sep",
|
|
|
|
"mtrr", "pge", "mca", "cmov",
|
|
|
|
"pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
|
|
|
|
NULL, "ds" /* Intel dts */, "acpi", "mmx",
|
|
|
|
"fxsr", "sse", "sse2", "ss",
|
|
|
|
"ht" /* Intel htt */, "tm", "ia64", "pbe",
|
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
.cpuid_eax = 1, .cpuid_reg = R_EDX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
|
|
|
[FEAT_1_ECX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
2016-09-30 21:49:41 +03:00
|
|
|
"pni" /* Intel,AMD sse3 */, "pclmulqdq", "dtes64", "monitor",
|
2016-09-30 21:49:40 +03:00
|
|
|
"ds-cpl", "vmx", "smx", "est",
|
2016-05-12 17:24:04 +03:00
|
|
|
"tm2", "ssse3", "cid", NULL,
|
|
|
|
"fma", "cx16", "xtpr", "pdcm",
|
2016-09-30 21:49:41 +03:00
|
|
|
NULL, "pcid", "dca", "sse4.1",
|
|
|
|
"sse4.2", "x2apic", "movbe", "popcnt",
|
2016-05-12 17:24:04 +03:00
|
|
|
"tsc-deadline", "aes", "xsave", "osxsave",
|
|
|
|
"avx", "f16c", "rdrand", "hypervisor",
|
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
.cpuid_eax = 1, .cpuid_reg = R_ECX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_EXT_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
2016-05-12 17:24:04 +03:00
|
|
|
/* Feature names that are already defined on feature_name[] but
|
|
|
|
* are set on CPUID[8000_0001].EDX on AMD CPUs don't have their
|
|
|
|
* names on feat_names below. They are copied automatically
|
|
|
|
* to features[FEAT_8000_0001_EDX] if and only if CPU vendor is AMD.
|
|
|
|
*/
|
2013-01-07 22:20:46 +04:00
|
|
|
[FEAT_8000_0001_EDX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL /* fpu */, NULL /* vme */, NULL /* de */, NULL /* pse */,
|
|
|
|
NULL /* tsc */, NULL /* msr */, NULL /* pae */, NULL /* mce */,
|
|
|
|
NULL /* cx8 */, NULL /* apic */, NULL, "syscall",
|
|
|
|
NULL /* mtrr */, NULL /* pge */, NULL /* mca */, NULL /* cmov */,
|
|
|
|
NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */,
|
2016-09-30 21:49:41 +03:00
|
|
|
"nx", NULL, "mmxext", NULL /* mmx */,
|
|
|
|
NULL /* fxsr */, "fxsr-opt", "pdpe1gb", "rdtscp",
|
|
|
|
NULL, "lm", "3dnowext", "3dnow",
|
2016-05-12 17:24:04 +03:00
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
.cpuid_eax = 0x80000001, .cpuid_reg = R_EDX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_EXT2_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
|
|
|
[FEAT_8000_0001_ECX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
2016-09-30 21:49:40 +03:00
|
|
|
"lahf-lm", "cmp-legacy", "svm", "extapic",
|
2016-05-12 17:24:04 +03:00
|
|
|
"cr8legacy", "abm", "sse4a", "misalignsse",
|
|
|
|
"3dnowprefetch", "osvw", "ibs", "xop",
|
|
|
|
"skinit", "wdt", NULL, "lwp",
|
2016-09-30 21:49:40 +03:00
|
|
|
"fma4", "tce", NULL, "nodeid-msr",
|
|
|
|
NULL, "tbm", "topoext", "perfctr-core",
|
|
|
|
"perfctr-nb", NULL, NULL, NULL,
|
2016-05-12 17:24:04 +03:00
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
.cpuid_eax = 0x80000001, .cpuid_reg = R_ECX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_EXT3_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
2013-01-07 22:20:47 +04:00
|
|
|
[FEAT_C000_0001_EDX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL, NULL, "xstore", "xstore-en",
|
|
|
|
NULL, NULL, "xcrypt", "xcrypt-en",
|
|
|
|
"ace2", "ace2-en", "phe", "phe-en",
|
|
|
|
"pmm", "pmm-en", NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2013-01-07 22:20:47 +04:00
|
|
|
.cpuid_eax = 0xC0000001, .cpuid_reg = R_EDX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_EXT4_FEATURES,
|
2013-01-07 22:20:47 +04:00
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
[FEAT_KVM] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
2016-09-30 21:49:40 +03:00
|
|
|
"kvmclock", "kvm-nopiodelay", "kvm-mmu", "kvmclock",
|
|
|
|
"kvm-asyncpf", "kvm-steal-time", "kvm-pv-eoi", "kvm-pv-unhalt",
|
2016-05-12 17:24:04 +03:00
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
"kvmclock-stable-bit", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
.cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_KVM_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
2016-06-24 13:49:36 +03:00
|
|
|
[FEAT_HYPERV_EAX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */,
|
|
|
|
NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */,
|
|
|
|
NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */,
|
|
|
|
NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */,
|
|
|
|
NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */,
|
|
|
|
NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2016-06-24 13:49:36 +03:00
|
|
|
.cpuid_eax = 0x40000003, .cpuid_reg = R_EAX,
|
|
|
|
},
|
|
|
|
[FEAT_HYPERV_EBX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */,
|
|
|
|
NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */,
|
|
|
|
NULL /* hv_post_messages */, NULL /* hv_signal_events */,
|
|
|
|
NULL /* hv_create_port */, NULL /* hv_connect_port */,
|
|
|
|
NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */,
|
|
|
|
NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */,
|
|
|
|
NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2016-06-24 13:49:36 +03:00
|
|
|
.cpuid_eax = 0x40000003, .cpuid_reg = R_EBX,
|
|
|
|
},
|
|
|
|
[FEAT_HYPERV_EDX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL /* hv_mwait */, NULL /* hv_guest_debugging */,
|
|
|
|
NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */,
|
|
|
|
NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */,
|
|
|
|
NULL, NULL,
|
|
|
|
NULL, NULL, NULL /* hv_guest_crash_msr */, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2016-06-24 13:49:36 +03:00
|
|
|
.cpuid_eax = 0x40000003, .cpuid_reg = R_EDX,
|
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
[FEAT_SVM] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
2016-09-30 21:49:40 +03:00
|
|
|
"npt", "lbrv", "svm-lock", "nrip-save",
|
|
|
|
"tsc-scale", "vmcb-clean", "flushbyasid", "decodeassists",
|
|
|
|
NULL, NULL, "pause-filter", NULL,
|
2016-05-12 17:24:04 +03:00
|
|
|
"pfthreshold", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2013-01-07 22:20:46 +04:00
|
|
|
.cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_SVM_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
|
|
|
[FEAT_7_0_EBX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
2016-09-30 21:49:40 +03:00
|
|
|
"fsgsbase", "tsc-adjust", NULL, "bmi1",
|
2016-05-12 17:24:04 +03:00
|
|
|
"hle", "avx2", NULL, "smep",
|
|
|
|
"bmi2", "erms", "invpcid", "rtm",
|
|
|
|
NULL, NULL, "mpx", NULL,
|
|
|
|
"avx512f", "avx512dq", "rdseed", "adx",
|
|
|
|
"smap", "avx512ifma", "pcommit", "clflushopt",
|
|
|
|
"clwb", NULL, "avx512pf", "avx512er",
|
2016-12-14 05:50:03 +03:00
|
|
|
"avx512cd", "sha-ni", "avx512bw", "avx512vl",
|
2016-05-12 17:24:04 +03:00
|
|
|
},
|
2013-04-22 23:00:16 +04:00
|
|
|
.cpuid_eax = 7,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
|
|
|
.cpuid_reg = R_EBX,
|
2014-04-30 20:48:38 +04:00
|
|
|
.tcg_features = TCG_7_0_EBX_FEATURES,
|
2013-01-07 22:20:46 +04:00
|
|
|
},
|
2015-11-18 05:20:15 +03:00
|
|
|
[FEAT_7_0_ECX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL, "avx512vbmi", "umip", "pku",
|
|
|
|
"ospke", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
2017-01-13 04:53:31 +03:00
|
|
|
NULL, NULL, "avx512-vpopcntdq", NULL,
|
2016-12-15 03:13:05 +03:00
|
|
|
"la57", NULL, NULL, NULL,
|
2016-05-12 17:24:04 +03:00
|
|
|
NULL, NULL, "rdpid", NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2015-11-18 05:20:15 +03:00
|
|
|
.cpuid_eax = 7,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
|
|
|
.cpuid_reg = R_ECX,
|
|
|
|
.tcg_features = TCG_7_0_ECX_FEATURES,
|
|
|
|
},
|
2016-10-31 11:27:26 +03:00
|
|
|
[FEAT_7_0_EDX] = {
|
|
|
|
.feat_names = {
|
|
|
|
NULL, NULL, "avx512-4vnniw", "avx512-4fmaps",
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
|
|
|
.cpuid_eax = 7,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
|
|
|
.cpuid_reg = R_EDX,
|
|
|
|
.tcg_features = TCG_7_0_EDX_FEATURES,
|
|
|
|
},
|
2014-04-30 20:48:45 +04:00
|
|
|
[FEAT_8000_0007_EDX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
"invtsc", NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2014-04-30 20:48:45 +04:00
|
|
|
.cpuid_eax = 0x80000007,
|
|
|
|
.cpuid_reg = R_EDX,
|
|
|
|
.tcg_features = TCG_APM_FEATURES,
|
|
|
|
.unmigratable_flags = CPUID_APM_INVTSC,
|
|
|
|
},
|
2014-11-24 17:54:43 +03:00
|
|
|
[FEAT_XSAVE] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
"xsaveopt", "xsavec", "xgetbv1", "xsaves",
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2014-11-24 17:54:43 +03:00
|
|
|
.cpuid_eax = 0xd,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 1,
|
|
|
|
.cpuid_reg = R_EAX,
|
2015-07-02 17:21:23 +03:00
|
|
|
.tcg_features = TCG_XSAVE_FEATURES,
|
2014-11-24 17:54:43 +03:00
|
|
|
},
|
2015-06-07 12:15:08 +03:00
|
|
|
[FEAT_6_EAX] = {
|
2016-05-12 17:24:04 +03:00
|
|
|
.feat_names = {
|
|
|
|
NULL, NULL, "arat", NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
},
|
2015-06-07 12:15:08 +03:00
|
|
|
.cpuid_eax = 6, .cpuid_reg = R_EAX,
|
|
|
|
.tcg_features = TCG_6_EAX_FEATURES,
|
|
|
|
},
|
2016-09-22 23:41:35 +03:00
|
|
|
[FEAT_XSAVE_COMP_LO] = {
|
|
|
|
.cpuid_eax = 0xD,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
|
|
|
.cpuid_reg = R_EAX,
|
|
|
|
.tcg_features = ~0U,
|
2016-09-28 18:00:29 +03:00
|
|
|
.migratable_flags = XSTATE_FP_MASK | XSTATE_SSE_MASK |
|
|
|
|
XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
|
|
|
|
XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK |
|
|
|
|
XSTATE_PKRU_MASK,
|
2016-09-22 23:41:35 +03:00
|
|
|
},
|
|
|
|
[FEAT_XSAVE_COMP_HI] = {
|
|
|
|
.cpuid_eax = 0xD,
|
|
|
|
.cpuid_needs_ecx = true, .cpuid_ecx = 0,
|
|
|
|
.cpuid_reg = R_EDX,
|
|
|
|
.tcg_features = ~0U,
|
|
|
|
},
|
2013-01-07 22:20:45 +04:00
|
|
|
};
|
|
|
|
|
2013-05-06 20:20:07 +04:00
|
|
|
typedef struct X86RegisterInfo32 {
|
|
|
|
/* Name of register */
|
|
|
|
const char *name;
|
|
|
|
/* QAPI enum value register */
|
|
|
|
X86CPURegister32 qapi_enum;
|
|
|
|
} X86RegisterInfo32;
|
|
|
|
|
|
|
|
#define REGISTER(reg) \
|
2014-03-05 06:44:40 +04:00
|
|
|
[R_##reg] = { .name = #reg, .qapi_enum = X86_CPU_REGISTER32_##reg }
|
2014-03-16 18:03:41 +04:00
|
|
|
static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
|
2013-05-06 20:20:07 +04:00
|
|
|
REGISTER(EAX),
|
|
|
|
REGISTER(ECX),
|
|
|
|
REGISTER(EDX),
|
|
|
|
REGISTER(EBX),
|
|
|
|
REGISTER(ESP),
|
|
|
|
REGISTER(EBP),
|
|
|
|
REGISTER(ESI),
|
|
|
|
REGISTER(EDI),
|
|
|
|
};
|
|
|
|
#undef REGISTER
|
|
|
|
|
2016-07-06 23:35:00 +03:00
|
|
|
typedef struct ExtSaveArea {
|
|
|
|
uint32_t feature, bits;
|
|
|
|
uint32_t offset, size;
|
|
|
|
} ExtSaveArea;
|
|
|
|
|
|
|
|
static const ExtSaveArea x86_ext_save_areas[] = {
|
2016-09-30 21:49:42 +03:00
|
|
|
[XSTATE_FP_BIT] = {
|
|
|
|
/* x87 FP state component is always enabled if XSAVE is supported */
|
|
|
|
.feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE,
|
|
|
|
/* x87 state is in the legacy region of the XSAVE area */
|
|
|
|
.offset = 0,
|
|
|
|
.size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader),
|
|
|
|
},
|
|
|
|
[XSTATE_SSE_BIT] = {
|
|
|
|
/* SSE state component is always enabled if XSAVE is supported */
|
|
|
|
.feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE,
|
|
|
|
/* SSE state is in the legacy region of the XSAVE area */
|
|
|
|
.offset = 0,
|
|
|
|
.size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader),
|
|
|
|
},
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_YMM_BIT] =
|
|
|
|
{ .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, avx_state),
|
|
|
|
.size = sizeof(XSaveAVX) },
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_BNDREGS_BIT] =
|
|
|
|
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, bndreg_state),
|
|
|
|
.size = sizeof(XSaveBNDREG) },
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_BNDCSR_BIT] =
|
|
|
|
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, bndcsr_state),
|
|
|
|
.size = sizeof(XSaveBNDCSR) },
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_OPMASK_BIT] =
|
|
|
|
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, opmask_state),
|
|
|
|
.size = sizeof(XSaveOpmask) },
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_ZMM_Hi256_BIT] =
|
|
|
|
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, zmm_hi256_state),
|
|
|
|
.size = sizeof(XSaveZMM_Hi256) },
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_Hi16_ZMM_BIT] =
|
|
|
|
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, hi16_zmm_state),
|
|
|
|
.size = sizeof(XSaveHi16_ZMM) },
|
2016-02-17 12:54:53 +03:00
|
|
|
[XSTATE_PKRU_BIT] =
|
|
|
|
{ .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU,
|
2015-11-28 19:32:26 +03:00
|
|
|
.offset = offsetof(X86XSaveArea, pkru_state),
|
|
|
|
.size = sizeof(XSavePKRU) },
|
2013-10-02 19:54:57 +04:00
|
|
|
};
|
2013-05-06 20:20:07 +04:00
|
|
|
|
2016-09-22 23:14:07 +03:00
|
|
|
static uint32_t xsave_area_size(uint64_t mask)
|
|
|
|
{
|
|
|
|
int i;
|
2016-09-30 21:49:42 +03:00
|
|
|
uint64_t ret = 0;
|
2016-09-22 23:14:07 +03:00
|
|
|
|
2016-09-30 21:49:42 +03:00
|
|
|
for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
|
2016-09-22 23:14:07 +03:00
|
|
|
const ExtSaveArea *esa = &x86_ext_save_areas[i];
|
|
|
|
if ((mask >> i) & 1) {
|
|
|
|
ret = MAX(ret, esa->offset + esa->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-09-22 23:41:35 +03:00
|
|
|
static inline uint64_t x86_cpu_xsave_components(X86CPU *cpu)
|
|
|
|
{
|
|
|
|
return ((uint64_t)cpu->env.features[FEAT_XSAVE_COMP_HI]) << 32 |
|
|
|
|
cpu->env.features[FEAT_XSAVE_COMP_LO];
|
|
|
|
}
|
|
|
|
|
2013-01-05 02:01:06 +04:00
|
|
|
const char *get_register_name_32(unsigned int reg)
|
|
|
|
{
|
2013-06-03 20:23:27 +04:00
|
|
|
if (reg >= CPU_NB_REGS32) {
|
2013-01-05 02:01:06 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-05-06 20:20:07 +04:00
|
|
|
return x86_reg_info_32[reg].name;
|
2013-01-05 02:01:06 +04:00
|
|
|
}
|
|
|
|
|
2014-04-30 20:48:41 +04:00
|
|
|
/*
|
|
|
|
* Returns the set of feature flags that are supported and migratable by
|
|
|
|
* QEMU, for a given FeatureWord.
|
|
|
|
*/
|
|
|
|
static uint32_t x86_cpu_get_migratable_flags(FeatureWord w)
|
|
|
|
{
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
|
uint32_t r = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
uint32_t f = 1U << i;
|
2016-09-28 18:00:29 +03:00
|
|
|
|
|
|
|
/* If the feature name is known, it is implicitly considered migratable,
|
|
|
|
* unless it is explicitly set in unmigratable_flags */
|
|
|
|
if ((wi->migratable_flags & f) ||
|
|
|
|
(wi->feat_names[i] && !(wi->unmigratable_flags & f))) {
|
|
|
|
r |= f;
|
2014-04-30 20:48:41 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-01-21 23:48:07 +03:00
|
|
|
void host_cpuid(uint32_t function, uint32_t count,
|
|
|
|
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
|
2010-03-11 16:38:58 +03:00
|
|
|
{
|
2011-11-27 21:13:01 +04:00
|
|
|
uint32_t vec[4];
|
|
|
|
|
|
|
|
#ifdef __x86_64__
|
|
|
|
asm volatile("cpuid"
|
|
|
|
: "=a"(vec[0]), "=b"(vec[1]),
|
|
|
|
"=c"(vec[2]), "=d"(vec[3])
|
|
|
|
: "0"(function), "c"(count) : "cc");
|
2014-01-30 23:48:53 +04:00
|
|
|
#elif defined(__i386__)
|
2011-11-27 21:13:01 +04:00
|
|
|
asm volatile("pusha \n\t"
|
|
|
|
"cpuid \n\t"
|
|
|
|
"mov %%eax, 0(%2) \n\t"
|
|
|
|
"mov %%ebx, 4(%2) \n\t"
|
|
|
|
"mov %%ecx, 8(%2) \n\t"
|
|
|
|
"mov %%edx, 12(%2) \n\t"
|
|
|
|
"popa"
|
|
|
|
: : "a"(function), "c"(count), "S"(vec)
|
|
|
|
: "memory", "cc");
|
2014-01-30 23:48:53 +04:00
|
|
|
#else
|
|
|
|
abort();
|
2011-11-27 21:13:01 +04:00
|
|
|
#endif
|
|
|
|
|
2010-03-11 16:38:58 +03:00
|
|
|
if (eax)
|
2011-11-27 21:13:01 +04:00
|
|
|
*eax = vec[0];
|
2010-03-11 16:38:58 +03:00
|
|
|
if (ebx)
|
2011-11-27 21:13:01 +04:00
|
|
|
*ebx = vec[1];
|
2010-03-11 16:38:58 +03:00
|
|
|
if (ecx)
|
2011-11-27 21:13:01 +04:00
|
|
|
*ecx = vec[2];
|
2010-03-11 16:38:58 +03:00
|
|
|
if (edx)
|
2011-11-27 21:13:01 +04:00
|
|
|
*edx = vec[3];
|
2010-03-11 16:38:58 +03:00
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2017-03-09 21:12:10 +03:00
|
|
|
void host_vendor_fms(char *vendor, int *family, int *model, int *stepping)
|
|
|
|
{
|
|
|
|
uint32_t eax, ebx, ecx, edx;
|
|
|
|
|
|
|
|
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
|
|
|
|
x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
|
|
|
|
|
|
|
|
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
|
|
|
|
if (family) {
|
|
|
|
*family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
|
|
|
|
}
|
|
|
|
if (model) {
|
|
|
|
*model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
|
|
|
|
}
|
|
|
|
if (stepping) {
|
|
|
|
*stepping = eax & 0x0F;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
/* CPU class name definitions: */
|
|
|
|
|
|
|
|
#define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
|
|
|
|
#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
|
|
|
|
|
|
|
|
/* Return type name for a given CPU model name
|
|
|
|
* Caller is responsible for freeing the returned string.
|
|
|
|
*/
|
|
|
|
static char *x86_cpu_type_name(const char *model_name)
|
|
|
|
{
|
|
|
|
return g_strdup_printf(X86_CPU_TYPE_NAME("%s"), model_name);
|
|
|
|
}
|
|
|
|
|
2014-02-11 01:02:44 +04:00
|
|
|
static ObjectClass *x86_cpu_class_by_name(const char *cpu_model)
|
|
|
|
{
|
2014-02-10 14:21:30 +04:00
|
|
|
ObjectClass *oc;
|
|
|
|
char *typename;
|
|
|
|
|
2014-02-11 01:02:44 +04:00
|
|
|
if (cpu_model == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
typename = x86_cpu_type_name(cpu_model);
|
|
|
|
oc = object_class_by_name(typename);
|
|
|
|
g_free(typename);
|
|
|
|
return oc;
|
2014-02-11 01:02:44 +04:00
|
|
|
}
|
|
|
|
|
2016-06-06 18:16:45 +03:00
|
|
|
static char *x86_cpu_class_get_model_name(X86CPUClass *cc)
|
|
|
|
{
|
|
|
|
const char *class_name = object_class_get_name(OBJECT_CLASS(cc));
|
|
|
|
assert(g_str_has_suffix(class_name, X86_CPU_TYPE_SUFFIX));
|
|
|
|
return g_strndup(class_name,
|
|
|
|
strlen(class_name) - strlen(X86_CPU_TYPE_SUFFIX));
|
|
|
|
}
|
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
struct X86CPUDefinition {
|
2010-03-11 16:38:55 +03:00
|
|
|
const char *name;
|
|
|
|
uint32_t level;
|
2013-04-22 23:00:12 +04:00
|
|
|
uint32_t xlevel;
|
2013-01-21 18:06:36 +04:00
|
|
|
/* vendor is zero-terminated, 12 character ASCII string */
|
|
|
|
char vendor[CPUID_VENDOR_SZ + 1];
|
2010-03-11 16:38:55 +03:00
|
|
|
int family;
|
|
|
|
int model;
|
|
|
|
int stepping;
|
2013-04-22 23:00:15 +04:00
|
|
|
FeatureWordArray features;
|
2010-03-11 16:38:55 +03:00
|
|
|
char model_id[48];
|
2014-02-10 14:21:30 +04:00
|
|
|
};
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2014-01-30 23:48:58 +04:00
|
|
|
static X86CPUDefinition builtin_x86_defs[] = {
|
2010-03-11 16:38:55 +03:00
|
|
|
{
|
|
|
|
.name = "qemu64",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 0xd,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
2013-09-11 00:48:59 +04:00
|
|
|
.model = 6,
|
2010-03-11 16:38:55 +03:00
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES |
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
|
|
|
CPUID_PSE36,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2015-11-03 22:24:18 +03:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_CX16,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2015-11-03 22:24:18 +03:00
|
|
|
CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0x8000000A,
|
2016-04-09 22:44:20 +03:00
|
|
|
.model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
|
2010-03-11 16:38:55 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "phenom",
|
|
|
|
.level = 5,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 16,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 3,
|
2014-10-03 23:39:49 +04:00
|
|
|
/* Missing: CPUID_HT */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES |
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
2014-10-03 23:39:49 +04:00
|
|
|
CPUID_PSE36 | CPUID_VME,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_EXT_POPCNT,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
|
2010-03-13 18:43:15 +03:00
|
|
|
CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
|
2010-03-11 16:38:55 +03:00
|
|
|
/* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
|
|
|
|
CPUID_EXT3_CR8LEG,
|
|
|
|
CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
|
|
|
|
CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
|
2014-10-03 23:39:49 +04:00
|
|
|
/* Missing: CPUID_SVM_LBRV */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_SVM] =
|
2014-10-03 23:39:49 +04:00
|
|
|
CPUID_SVM_NPT,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0x8000001A,
|
|
|
|
.model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "core2duo",
|
|
|
|
.level = 10,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
|
|
|
.model = 15,
|
|
|
|
.stepping = 11,
|
2014-10-03 23:39:49 +04:00
|
|
|
/* Missing: CPUID_DTS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES |
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
2014-10-03 23:39:49 +04:00
|
|
|
CPUID_PSE36 | CPUID_VME | CPUID_ACPI | CPUID_SS,
|
|
|
|
/* Missing: CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_EST,
|
2014-10-03 23:39:50 +04:00
|
|
|
* CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_VMX */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
|
2014-10-03 23:39:50 +04:00
|
|
|
CPUID_EXT_CX16,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "kvm64",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 0xd,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2014-12-10 19:12:41 +03:00
|
|
|
/* Missing: CPUID_HT */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
PPRO_FEATURES | CPUID_VME |
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
|
|
|
CPUID_PSE36,
|
|
|
|
/* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_CX16,
|
2010-03-11 16:38:55 +03:00
|
|
|
/* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2010-03-11 16:38:55 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
|
|
|
/* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
|
|
|
|
CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
|
|
|
|
CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
|
|
|
|
CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
0,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Common KVM processor"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "qemu32",
|
|
|
|
.level = 4,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
2013-09-11 00:48:59 +04:00
|
|
|
.model = 6,
|
2010-03-11 16:38:55 +03:00
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2015-11-03 22:24:18 +03:00
|
|
|
CPUID_EXT_SSE3,
|
2010-03-11 16:39:06 +03:00
|
|
|
.xlevel = 0x80000004,
|
2016-04-09 22:44:20 +03:00
|
|
|
.model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
|
2010-03-11 16:38:55 +03:00
|
|
|
},
|
2010-05-21 11:50:51 +04:00
|
|
|
{
|
|
|
|
.name = "kvm32",
|
|
|
|
.level = 5,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-05-21 11:50:51 +04:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
PPRO_FEATURES | CPUID_VME |
|
2010-05-21 11:50:51 +04:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
0,
|
2010-05-21 11:50:51 +04:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Common 32-bit KVM processor"
|
|
|
|
},
|
2010-03-11 16:38:55 +03:00
|
|
|
{
|
|
|
|
.name = "coreduo",
|
|
|
|
.level = 10,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
|
|
|
.model = 14,
|
|
|
|
.stepping = 8,
|
2014-10-03 23:39:49 +04:00
|
|
|
/* Missing: CPUID_DTS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES | CPUID_VME |
|
2014-10-03 23:39:49 +04:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_ACPI |
|
|
|
|
CPUID_SS,
|
|
|
|
/* Missing: CPUID_EXT_EST, CPUID_EXT_TM2 , CPUID_EXT_XTPR,
|
2014-10-03 23:39:50 +04:00
|
|
|
* CPUID_EXT_PDCM, CPUID_EXT_VMX */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2014-10-03 23:39:50 +04:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_NX,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "486",
|
2010-03-11 16:39:06 +03:00
|
|
|
.level = 1,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 4,
|
2013-05-01 19:30:51 +04:00
|
|
|
.model = 8,
|
2010-03-11 16:38:55 +03:00
|
|
|
.stepping = 0,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
I486_FEATURES,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "pentium",
|
|
|
|
.level = 1,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 5,
|
|
|
|
.model = 4,
|
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PENTIUM_FEATURES,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "pentium2",
|
|
|
|
.level = 2,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
|
|
|
.model = 5,
|
|
|
|
.stepping = 2,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PENTIUM2_FEATURES,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "pentium3",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 3,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
|
|
|
.model = 7,
|
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PENTIUM3_FEATURES,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "athlon",
|
|
|
|
.level = 2,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR |
|
2012-09-06 14:05:37 +04:00
|
|
|
CPUID_MCA,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2012-09-06 14:05:37 +04:00
|
|
|
CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
|
2010-03-11 16:38:55 +03:00
|
|
|
.xlevel = 0x80000008,
|
2016-04-09 22:44:20 +03:00
|
|
|
.model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
|
2010-03-11 16:38:55 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "n270",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 10,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2010-03-11 16:38:55 +03:00
|
|
|
.family = 6,
|
|
|
|
.model = 28,
|
|
|
|
.stepping = 2,
|
2014-10-03 23:39:49 +04:00
|
|
|
/* Missing: CPUID_DTS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
PPRO_FEATURES |
|
2014-10-03 23:39:49 +04:00
|
|
|
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME |
|
|
|
|
CPUID_ACPI | CPUID_SS,
|
2010-03-11 16:38:55 +03:00
|
|
|
/* Some CPUs got no CPUID_SEP */
|
2014-10-03 23:39:49 +04:00
|
|
|
/* Missing: CPUID_EXT_DSCPL, CPUID_EXT_EST, CPUID_EXT_TM2,
|
|
|
|
* CPUID_EXT_XTPR */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
|
2013-04-25 22:43:04 +04:00
|
|
|
CPUID_EXT_MOVBE,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2012-09-06 14:05:37 +04:00
|
|
|
CPUID_EXT2_NX,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2010-03-11 16:38:55 +03:00
|
|
|
.model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz",
|
|
|
|
},
|
2012-09-06 00:41:10 +04:00
|
|
|
{
|
|
|
|
.name = "Conroe",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 10,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 6,
|
2013-05-28 00:23:54 +04:00
|
|
|
.model = 15,
|
2012-09-06 00:41:10 +04:00
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2012-09-06 00:41:10 +04:00
|
|
|
.model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Penryn",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 10,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 6,
|
2013-05-28 00:23:54 +04:00
|
|
|
.model = 23,
|
2012-09-06 00:41:10 +04:00
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2012-09-06 00:41:10 +04:00
|
|
|
.model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Nehalem",
|
2015-07-09 22:07:39 +03:00
|
|
|
.level = 11,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 6,
|
2013-05-28 00:23:54 +04:00
|
|
|
.model = 26,
|
2012-09-06 00:41:10 +04:00
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2012-09-06 00:41:10 +04:00
|
|
|
.model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Westmere",
|
|
|
|
.level = 11,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 6,
|
|
|
|
.model = 44,
|
|
|
|
.stepping = 1,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2012-09-06 00:41:10 +04:00
|
|
|
.model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SandyBridge",
|
|
|
|
.level = 0xd,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 6,
|
|
|
|
.model = 42,
|
|
|
|
.stepping = 1,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
|
|
|
|
CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_LAHF_LM,
|
2014-11-24 17:54:43 +03:00
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2012-09-06 00:41:10 +04:00
|
|
|
.model_id = "Intel Xeon E312xx (Sandy Bridge)",
|
|
|
|
},
|
2014-12-05 12:55:23 +03:00
|
|
|
{
|
|
|
|
.name = "IvyBridge",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 58,
|
|
|
|
.stepping = 9,
|
|
|
|
.features[FEAT_1_EDX] =
|
|
|
|
CPUID_VME | 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_FP87,
|
|
|
|
.features[FEAT_1_ECX] =
|
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
|
|
|
|
CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
|
|
|
CPUID_EXT_SSE3 | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
|
|
|
.features[FEAT_7_0_EBX] =
|
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP |
|
|
|
|
CPUID_7_0_EBX_ERMS,
|
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
|
|
|
CPUID_EXT3_LAHF_LM,
|
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2014-12-05 12:55:23 +03:00
|
|
|
.model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)",
|
|
|
|
},
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 22:28:54 +04:00
|
|
|
{
|
2015-03-13 21:58:09 +03:00
|
|
|
.name = "Haswell-noTSX",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 60,
|
|
|
|
.stepping = 1,
|
|
|
|
.features[FEAT_1_EDX] =
|
|
|
|
CPUID_VME | 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_FP87,
|
|
|
|
.features[FEAT_1_ECX] =
|
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2015-09-28 15:00:18 +03:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
|
2015-03-13 21:58:09 +03:00
|
|
|
.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,
|
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2015-03-13 21:58:09 +03:00
|
|
|
.model_id = "Intel Core Processor (Haswell, no TSX)",
|
|
|
|
}, {
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 22:28:54 +04:00
|
|
|
.name = "Haswell",
|
|
|
|
.level = 0xd,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 22:28:54 +04:00
|
|
|
.family = 6,
|
|
|
|
.model = 60,
|
2017-03-09 21:12:12 +03:00
|
|
|
.stepping = 4,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
2014-12-05 12:52:46 +03:00
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2015-09-28 15:00:18 +03:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_7_0_EBX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
2015-03-13 21:39:43 +03:00
|
|
|
CPUID_7_0_EBX_HLE | 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_RTM,
|
2014-11-24 17:54:43 +03:00
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
target-i386: Add Haswell CPU model
Features added to the model, in relation to SandyBridge:
fma CPUID[1].ECX[12]
pcid CPUID[1].ECX[17]
movbe CPUID[1].ECX[22]
fsgsbase CPUID[EAX=7,ECX=0].EBX[0]
bmi1 CPUID[EAX=7,ECX=0].EBX[3]
hle CPUID[EAX=7,ECX=0].EBX[4]
avx2 CPUID[EAX=7,ECX=0].EBX[5]
smep CPUID[EAX=7,ECX=0].EBX[7]
bmi2 CPUID[EAX=7,ECX=0].EBX[8]
erms CPUID[EAX=7,ECX=0].EBX[9]
invpcid CPUID[EAX=7,ECX=0].EBX[10]
rtm CPUID[EAX=7,ECX=0].EBX[11]
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2012-11-14 22:28:54 +04:00
|
|
|
.model_id = "Intel Core Processor (Haswell)",
|
|
|
|
},
|
2015-03-13 21:58:09 +03:00
|
|
|
{
|
|
|
|
.name = "Broadwell-noTSX",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 61,
|
|
|
|
.stepping = 2,
|
|
|
|
.features[FEAT_1_EDX] =
|
|
|
|
CPUID_VME | 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_FP87,
|
|
|
|
.features[FEAT_1_ECX] =
|
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2015-09-28 15:00:18 +03:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
2015-03-13 21:58:09 +03:00
|
|
|
.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_RDSEED | CPUID_7_0_EBX_ADX |
|
|
|
|
CPUID_7_0_EBX_SMAP,
|
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2015-03-13 21:58:09 +03:00
|
|
|
.model_id = "Intel Core Processor (Broadwell, no TSX)",
|
|
|
|
},
|
2014-06-18 00:11:40 +04:00
|
|
|
{
|
|
|
|
.name = "Broadwell",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 61,
|
|
|
|
.stepping = 2,
|
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 00:11:40 +04:00
|
|
|
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_FP87,
|
|
|
|
.features[FEAT_1_ECX] =
|
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
2014-12-05 12:52:46 +03:00
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
2014-06-18 00:11:40 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2015-09-28 15:00:18 +03:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
2014-06-18 00:11:40 +04:00
|
|
|
.features[FEAT_7_0_EBX] =
|
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
2015-03-13 21:39:43 +03:00
|
|
|
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
2014-06-18 00:11:40 +04:00
|
|
|
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
2015-03-13 21:39:43 +03:00
|
|
|
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
2014-06-18 00:11:40 +04:00
|
|
|
CPUID_7_0_EBX_SMAP,
|
2014-11-24 17:54:43 +03:00
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT,
|
2015-06-07 12:15:08 +03:00
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
2015-07-09 22:07:39 +03:00
|
|
|
.xlevel = 0x80000008,
|
2014-06-18 00:11:40 +04:00
|
|
|
.model_id = "Intel Core Processor (Broadwell)",
|
|
|
|
},
|
2016-04-27 11:13:06 +03:00
|
|
|
{
|
|
|
|
.name = "Skylake-Client",
|
|
|
|
.level = 0xd,
|
|
|
|
.vendor = CPUID_VENDOR_INTEL,
|
|
|
|
.family = 6,
|
|
|
|
.model = 94,
|
|
|
|
.stepping = 3,
|
|
|
|
.features[FEAT_1_EDX] =
|
|
|
|
CPUID_VME | 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_FP87,
|
|
|
|
.features[FEAT_1_ECX] =
|
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
|
|
|
|
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
|
|
|
|
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
|
|
|
|
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
|
|
|
|
.features[FEAT_8000_0001_EDX] =
|
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
|
|
|
.features[FEAT_8000_0001_ECX] =
|
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
|
|
|
.features[FEAT_7_0_EBX] =
|
|
|
|
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
|
|
|
CPUID_7_0_EBX_HLE | 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_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
|
|
|
CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
|
|
|
|
/* Missing: XSAVES (not supported by some Linux versions,
|
|
|
|
* including v4.1 to v4.6).
|
|
|
|
* KVM doesn't yet expose any XSAVES state save component,
|
|
|
|
* and the only one defined in Skylake (processor tracing)
|
|
|
|
* probably will block migration anyway.
|
|
|
|
*/
|
|
|
|
.features[FEAT_XSAVE] =
|
|
|
|
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
|
|
|
|
CPUID_XSAVE_XGETBV1,
|
|
|
|
.features[FEAT_6_EAX] =
|
|
|
|
CPUID_6_EAX_ARAT,
|
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "Intel Core Processor (Skylake)",
|
|
|
|
},
|
2012-09-06 00:41:10 +04:00
|
|
|
{
|
|
|
|
.name = "Opteron_G1",
|
|
|
|
.level = 5,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_SSE3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2017-01-13 22:00:57 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2012-09-06 00:41:10 +04:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "AMD Opteron 240 (Gen 1 Class Opteron)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Opteron_G2",
|
|
|
|
.level = 5,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 15,
|
|
|
|
.model = 6,
|
|
|
|
.stepping = 1,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSE3,
|
2015-11-13 22:07:13 +03:00
|
|
|
/* Missing: CPUID_EXT2_RDTSCP */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2017-01-13 22:00:57 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
|
2012-09-06 00:41:10 +04:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Opteron_G3",
|
|
|
|
.level = 5,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2016-10-03 14:50:02 +03:00
|
|
|
.family = 16,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 3,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_CX16 | CPUID_EXT_MONITOR |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_SSE3,
|
2015-11-13 22:07:13 +03:00
|
|
|
/* Missing: CPUID_EXT2_RDTSCP */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2017-01-13 22:00:57 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
|
2012-09-06 00:41:10 +04:00
|
|
|
.xlevel = 0x80000008,
|
|
|
|
.model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Opteron_G4",
|
|
|
|
.level = 0xd,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-09-06 00:41:10 +04:00
|
|
|
.family = 21,
|
|
|
|
.model = 1,
|
|
|
|
.stepping = 2,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
|
|
|
|
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
|
|
|
|
CPUID_EXT_SSE3,
|
2015-11-13 22:07:13 +03:00
|
|
|
/* Missing: CPUID_EXT2_RDTSCP */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2017-01-13 22:00:57 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
|
|
|
|
CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
|
|
|
|
CPUID_EXT3_LAHF_LM,
|
2014-11-24 17:54:43 +03:00
|
|
|
/* no xsaveopt! */
|
2012-09-06 00:41:10 +04:00
|
|
|
.xlevel = 0x8000001A,
|
|
|
|
.model_id = "AMD Opteron 62xx class CPU",
|
|
|
|
},
|
2012-11-14 22:28:53 +04:00
|
|
|
{
|
|
|
|
.name = "Opteron_G5",
|
|
|
|
.level = 0xd,
|
2013-01-21 18:06:36 +04:00
|
|
|
.vendor = CPUID_VENDOR_AMD,
|
2012-11-14 22:28:53 +04:00
|
|
|
.family = 21,
|
|
|
|
.model = 2,
|
|
|
|
.stepping = 0,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_EDX] =
|
2014-12-10 19:12:41 +03:00
|
|
|
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
|
2014-06-18 03:05:29 +04:00
|
|
|
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_FP87,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_1_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT_F16C | CPUID_EXT_AVX | CPUID_EXT_XSAVE |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
|
|
|
|
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA |
|
|
|
|
CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
|
2015-11-13 22:07:13 +03:00
|
|
|
/* Missing: CPUID_EXT2_RDTSCP */
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_EDX] =
|
2017-01-13 22:00:57 +03:00
|
|
|
CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_NX |
|
|
|
|
CPUID_EXT2_SYSCALL,
|
2013-04-22 23:00:15 +04:00
|
|
|
.features[FEAT_8000_0001_ECX] =
|
2013-04-22 23:00:14 +04:00
|
|
|
CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
|
2014-06-18 03:05:29 +04:00
|
|
|
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
|
|
|
|
CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
|
|
|
|
CPUID_EXT3_LAHF_LM,
|
2014-11-24 17:54:43 +03:00
|
|
|
/* no xsaveopt! */
|
2012-11-14 22:28:53 +04:00
|
|
|
.xlevel = 0x8000001A,
|
|
|
|
.model_id = "AMD Opteron 63xx class CPU",
|
|
|
|
},
|
2010-03-11 16:38:55 +03:00
|
|
|
};
|
|
|
|
|
2015-09-11 18:40:27 +03:00
|
|
|
typedef struct PropValue {
|
|
|
|
const char *prop, *value;
|
|
|
|
} PropValue;
|
|
|
|
|
|
|
|
/* KVM-specific features that are automatically added/removed
|
|
|
|
* from all CPU models when KVM is enabled.
|
|
|
|
*/
|
|
|
|
static PropValue kvm_default_props[] = {
|
|
|
|
{ "kvmclock", "on" },
|
|
|
|
{ "kvm-nopiodelay", "on" },
|
|
|
|
{ "kvm-asyncpf", "on" },
|
|
|
|
{ "kvm-steal-time", "on" },
|
|
|
|
{ "kvm-pv-eoi", "on" },
|
|
|
|
{ "kvmclock-stable-bit", "on" },
|
|
|
|
{ "x2apic", "on" },
|
|
|
|
{ "acpi", "off" },
|
|
|
|
{ "monitor", "off" },
|
|
|
|
{ "svm", "off" },
|
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
|
2016-09-30 21:49:37 +03:00
|
|
|
/* TCG-specific defaults that override all CPU models when using TCG
|
|
|
|
*/
|
|
|
|
static PropValue tcg_default_props[] = {
|
|
|
|
{ "vme", "off" },
|
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-09-11 18:40:27 +03:00
|
|
|
void x86_cpu_change_kvm_default(const char *prop, const char *value)
|
|
|
|
{
|
|
|
|
PropValue *pv;
|
|
|
|
for (pv = kvm_default_props; pv->prop; pv++) {
|
|
|
|
if (!strcmp(pv->prop, prop)) {
|
|
|
|
pv->value = value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It is valid to call this function only for properties that
|
|
|
|
* are already present in the kvm_default_props table.
|
|
|
|
*/
|
|
|
|
assert(pv->prop);
|
|
|
|
}
|
|
|
|
|
2014-08-21 00:30:12 +04:00
|
|
|
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
|
bool migratable_only);
|
|
|
|
|
2016-06-22 09:56:23 +03:00
|
|
|
static bool lmce_supported(void)
|
|
|
|
{
|
2017-02-22 21:39:17 +03:00
|
|
|
uint64_t mce_cap = 0;
|
2016-06-22 09:56:23 +03:00
|
|
|
|
2017-02-22 21:39:17 +03:00
|
|
|
#ifdef CONFIG_KVM
|
2016-06-22 09:56:23 +03:00
|
|
|
if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-02-22 21:39:17 +03:00
|
|
|
#endif
|
2016-06-22 09:56:23 +03:00
|
|
|
|
|
|
|
return !!(mce_cap & MCG_LMCE_P);
|
|
|
|
}
|
|
|
|
|
2010-03-11 16:38:55 +03:00
|
|
|
static int cpu_x86_fill_model_id(char *str)
|
|
|
|
{
|
|
|
|
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
|
|
|
|
memcpy(str + i * 16 + 0, &eax, 4);
|
|
|
|
memcpy(str + i * 16 + 4, &ebx, 4);
|
|
|
|
memcpy(str + i * 16 + 8, &ecx, 4);
|
|
|
|
memcpy(str + i * 16 + 12, &edx, 4);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-22 21:39:17 +03:00
|
|
|
static Property max_x86_cpu_properties[] = {
|
2014-06-18 00:31:53 +04:00
|
|
|
DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true),
|
2015-09-02 17:19:11 +03:00
|
|
|
DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false),
|
2014-04-30 20:48:41 +04:00
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2017-02-22 21:39:17 +03:00
|
|
|
static void max_x86_cpu_class_init(ObjectClass *oc, void *data)
|
2010-03-11 16:38:55 +03:00
|
|
|
{
|
2014-04-30 20:48:41 +04:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
2014-02-10 14:21:30 +04:00
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2017-01-20 00:04:45 +03:00
|
|
|
xcc->ordering = 9;
|
2012-10-25 01:44:06 +04:00
|
|
|
|
2016-09-30 21:49:36 +03:00
|
|
|
xcc->model_description =
|
2017-02-22 21:39:17 +03:00
|
|
|
"Enables all features supported by the accelerator in the current host";
|
2014-02-10 14:21:30 +04:00
|
|
|
|
2017-02-22 21:39:17 +03:00
|
|
|
dc->props = max_x86_cpu_properties;
|
2014-02-10 14:21:30 +04:00
|
|
|
}
|
|
|
|
|
2017-02-22 21:39:19 +03:00
|
|
|
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp);
|
|
|
|
|
2017-02-22 21:39:17 +03:00
|
|
|
static void max_x86_cpu_initfn(Object *obj)
|
2014-02-10 14:21:30 +04:00
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
KVMState *s = kvm_state;
|
|
|
|
|
2014-08-21 00:30:12 +04:00
|
|
|
/* We can't fill the features array here because we don't know yet if
|
|
|
|
* "migratable" is true or false.
|
|
|
|
*/
|
2017-01-20 00:04:46 +03:00
|
|
|
cpu->max_features = true;
|
2014-08-21 00:30:12 +04:00
|
|
|
|
2016-06-10 14:42:08 +03:00
|
|
|
if (kvm_enabled()) {
|
2017-02-22 21:39:19 +03:00
|
|
|
X86CPUDefinition host_cpudef = { };
|
|
|
|
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
|
|
|
|
|
|
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
|
|
|
|
x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
|
|
|
|
|
|
|
|
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
|
|
|
|
host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
|
|
|
|
host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
|
|
|
|
host_cpudef.stepping = eax & 0x0F;
|
|
|
|
|
|
|
|
cpu_x86_fill_model_id(host_cpudef.model_id);
|
|
|
|
|
|
|
|
x86_cpu_load_def(cpu, &host_cpudef, &error_abort);
|
|
|
|
|
2016-09-21 19:30:12 +03:00
|
|
|
env->cpuid_min_level =
|
|
|
|
kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
|
|
|
|
env->cpuid_min_xlevel =
|
|
|
|
kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
|
|
|
|
env->cpuid_min_xlevel2 =
|
|
|
|
kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
|
2016-06-22 09:56:23 +03:00
|
|
|
|
|
|
|
if (lmce_supported()) {
|
|
|
|
object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort);
|
|
|
|
}
|
2017-02-22 21:39:18 +03:00
|
|
|
} else {
|
|
|
|
object_property_set_str(OBJECT(cpu), CPUID_VENDOR_AMD,
|
|
|
|
"vendor", &error_abort);
|
|
|
|
object_property_set_int(OBJECT(cpu), 6, "family", &error_abort);
|
|
|
|
object_property_set_int(OBJECT(cpu), 6, "model", &error_abort);
|
|
|
|
object_property_set_int(OBJECT(cpu), 3, "stepping", &error_abort);
|
|
|
|
object_property_set_str(OBJECT(cpu),
|
|
|
|
"QEMU TCG CPU version " QEMU_HW_VERSION,
|
|
|
|
"model-id", &error_abort);
|
2016-06-10 14:42:08 +03:00
|
|
|
}
|
2014-01-20 20:41:12 +04:00
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
2017-02-22 21:39:17 +03:00
|
|
|
static const TypeInfo max_x86_cpu_type_info = {
|
|
|
|
.name = X86_CPU_TYPE_NAME("max"),
|
|
|
|
.parent = TYPE_X86_CPU,
|
|
|
|
.instance_init = max_x86_cpu_initfn,
|
|
|
|
.class_init = max_x86_cpu_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
|
|
|
|
static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
|
|
|
|
|
|
|
xcc->kvm_required = true;
|
|
|
|
xcc->ordering = 8;
|
|
|
|
|
|
|
|
xcc->model_description =
|
|
|
|
"KVM processor with all supported host features "
|
|
|
|
"(only available in KVM mode)";
|
|
|
|
}
|
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
static const TypeInfo host_x86_cpu_type_info = {
|
|
|
|
.name = X86_CPU_TYPE_NAME("host"),
|
2017-02-22 21:39:17 +03:00
|
|
|
.parent = X86_CPU_TYPE_NAME("max"),
|
2014-02-10 14:21:30 +04:00
|
|
|
.class_init = host_x86_cpu_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2014-04-30 20:48:31 +04:00
|
|
|
static void report_unavailable_features(FeatureWord w, uint32_t mask)
|
2010-03-11 16:38:55 +03:00
|
|
|
{
|
2014-04-30 20:48:31 +04:00
|
|
|
FeatureWordInfo *f = &feature_word_info[w];
|
2010-03-11 16:38:55 +03:00
|
|
|
int i;
|
|
|
|
|
2014-04-30 20:48:29 +04:00
|
|
|
for (i = 0; i < 32; ++i) {
|
2015-09-29 23:34:22 +03:00
|
|
|
if ((1UL << i) & mask) {
|
2013-01-07 22:20:46 +04:00
|
|
|
const char *reg = get_register_name_32(f->cpuid_reg);
|
2013-01-05 02:01:06 +04:00
|
|
|
assert(reg);
|
2014-04-30 20:48:39 +04:00
|
|
|
fprintf(stderr, "warning: %s doesn't support requested feature: "
|
2013-01-05 02:01:06 +04:00
|
|
|
"CPUID.%02XH:%s%s%s [bit %d]\n",
|
2014-04-30 20:48:39 +04:00
|
|
|
kvm_enabled() ? "host" : "TCG",
|
2013-01-07 22:20:46 +04:00
|
|
|
f->cpuid_eax, reg,
|
|
|
|
f->feat_names[i] ? "." : "",
|
|
|
|
f->feat_names[i] ? f->feat_names[i] : "", i);
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
2014-04-30 20:48:29 +04:00
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpuid_version_get_family(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2012-04-17 16:42:22 +04:00
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = (env->cpuid_version >> 8) & 0xf;
|
|
|
|
if (value == 0xf) {
|
|
|
|
value += (env->cpuid_version >> 20) & 0xff;
|
|
|
|
}
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, errp);
|
2012-04-17 16:42:22 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpuid_version_set_family(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2012-02-17 20:46:01 +04:00
|
|
|
{
|
2012-04-17 14:10:29 +04:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = 0xff + 0xf;
|
2014-04-25 14:44:22 +04:00
|
|
|
Error *local_err = NULL;
|
2012-04-17 14:10:29 +04:00
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, &local_err);
|
2014-04-25 14:44:22 +04:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-17 14:10:29 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
2012-04-17 14:10:29 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 20:46:01 +04:00
|
|
|
env->cpuid_version &= ~0xff00f00;
|
2012-04-17 14:10:29 +04:00
|
|
|
if (value > 0x0f) {
|
|
|
|
env->cpuid_version |= 0xf00 | ((value - 0x0f) << 20);
|
2012-02-17 20:46:01 +04:00
|
|
|
} else {
|
2012-04-17 14:10:29 +04:00
|
|
|
env->cpuid_version |= value << 8;
|
2012-02-17 20:46:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpuid_version_get_model(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2012-04-17 16:48:14 +04:00
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = (env->cpuid_version >> 4) & 0xf;
|
|
|
|
value |= ((env->cpuid_version >> 16) & 0xf) << 4;
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, errp);
|
2012-04-17 16:48:14 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpuid_version_set_model(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2012-02-17 20:46:02 +04:00
|
|
|
{
|
2012-04-17 14:16:39 +04:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = 0xff;
|
2014-04-25 14:44:22 +04:00
|
|
|
Error *local_err = NULL;
|
2012-04-17 14:16:39 +04:00
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, &local_err);
|
2014-04-25 14:44:22 +04:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-17 14:16:39 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
2012-04-17 14:16:39 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 20:46:02 +04:00
|
|
|
env->cpuid_version &= ~0xf00f0;
|
2012-04-17 14:16:39 +04:00
|
|
|
env->cpuid_version |= ((value & 0xf) << 4) | ((value >> 4) << 16);
|
2012-02-17 20:46:02 +04:00
|
|
|
}
|
|
|
|
|
2012-04-17 16:50:53 +04:00
|
|
|
static void x86_cpuid_version_get_stepping(Object *obj, Visitor *v,
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
const char *name, void *opaque,
|
2012-04-17 16:50:53 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = env->cpuid_version & 0xf;
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, errp);
|
2012-04-17 16:50:53 +04:00
|
|
|
}
|
|
|
|
|
2012-04-17 16:14:18 +04:00
|
|
|
static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
const char *name, void *opaque,
|
2012-04-17 16:14:18 +04:00
|
|
|
Error **errp)
|
2012-02-17 20:46:03 +04:00
|
|
|
{
|
2012-04-17 16:14:18 +04:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
const int64_t min = 0;
|
|
|
|
const int64_t max = 0xf;
|
2014-04-25 14:44:22 +04:00
|
|
|
Error *local_err = NULL;
|
2012-04-17 16:14:18 +04:00
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, &local_err);
|
2014-04-25 14:44:22 +04:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-17 16:14:18 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
2012-04-17 16:14:18 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 20:46:03 +04:00
|
|
|
env->cpuid_version &= ~0xf;
|
2012-04-17 16:14:18 +04:00
|
|
|
env->cpuid_version |= value & 0xf;
|
2012-02-17 20:46:03 +04:00
|
|
|
}
|
|
|
|
|
2012-04-17 21:22:58 +04:00
|
|
|
static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
char *value;
|
|
|
|
|
2014-12-04 16:46:46 +03:00
|
|
|
value = g_malloc(CPUID_VENDOR_SZ + 1);
|
2013-01-21 18:06:36 +04:00
|
|
|
x86_cpu_vendor_words2str(value, env->cpuid_vendor1, env->cpuid_vendor2,
|
|
|
|
env->cpuid_vendor3);
|
2012-04-17 21:22:58 +04:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpuid_set_vendor(Object *obj, const char *value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
2012-10-22 19:03:10 +04:00
|
|
|
if (strlen(value) != CPUID_VENDOR_SZ) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_PROPERTY_VALUE_BAD, "", "vendor", value);
|
2012-04-17 21:22:58 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
env->cpuid_vendor1 = 0;
|
|
|
|
env->cpuid_vendor2 = 0;
|
|
|
|
env->cpuid_vendor3 = 0;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
env->cpuid_vendor1 |= ((uint8_t)value[i ]) << (8 * i);
|
|
|
|
env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i);
|
|
|
|
env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-18 01:02:26 +04:00
|
|
|
static char *x86_cpuid_get_model_id(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
char *value;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
value = g_malloc(48 + 1);
|
|
|
|
for (i = 0; i < 48; i++) {
|
|
|
|
value[i] = env->cpuid_model[i >> 2] >> (8 * (i & 3));
|
|
|
|
}
|
|
|
|
value[48] = '\0';
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2012-04-17 17:17:27 +04:00
|
|
|
static void x86_cpuid_set_model_id(Object *obj, const char *model_id,
|
|
|
|
Error **errp)
|
2012-02-17 20:46:04 +04:00
|
|
|
{
|
2012-04-17 17:17:27 +04:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
CPUX86State *env = &cpu->env;
|
2012-02-17 20:46:04 +04:00
|
|
|
int c, len, i;
|
|
|
|
|
|
|
|
if (model_id == NULL) {
|
|
|
|
model_id = "";
|
|
|
|
}
|
|
|
|
len = strlen(model_id);
|
2012-04-17 20:21:52 +04:00
|
|
|
memset(env->cpuid_model, 0, 48);
|
2012-02-17 20:46:04 +04:00
|
|
|
for (i = 0; i < 48; i++) {
|
|
|
|
if (i >= len) {
|
|
|
|
c = '\0';
|
|
|
|
} else {
|
|
|
|
c = (uint8_t)model_id[i];
|
|
|
|
}
|
|
|
|
env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpuid_get_tsc_freq(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2012-04-18 02:12:23 +04:00
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
value = cpu->env.tsc_khz * 1000;
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, errp);
|
2012-04-18 02:12:23 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2012-04-18 02:12:23 +04:00
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
const int64_t min = 0;
|
2012-09-22 04:13:13 +04:00
|
|
|
const int64_t max = INT64_MAX;
|
2014-04-25 14:44:22 +04:00
|
|
|
Error *local_err = NULL;
|
2012-04-18 02:12:23 +04:00
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, &local_err);
|
2014-04-25 14:44:22 +04:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2012-04-18 02:12:23 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value < min || value > max) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
|
|
|
|
name ? name : "null", value, min, max);
|
2012-04-18 02:12:23 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-24 06:33:57 +03:00
|
|
|
cpu->env.tsc_khz = cpu->env.user_tsc_khz = value / 1000;
|
2012-04-18 02:12:23 +04:00
|
|
|
}
|
|
|
|
|
2013-05-06 20:20:09 +04:00
|
|
|
/* Generic getter for "feature-words" and "filtered-features" properties */
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2013-05-06 20:20:07 +04:00
|
|
|
{
|
2013-05-06 20:20:09 +04:00
|
|
|
uint32_t *array = (uint32_t *)opaque;
|
2013-05-06 20:20:07 +04:00
|
|
|
FeatureWord w;
|
|
|
|
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
|
|
|
|
X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
|
|
|
|
X86CPUFeatureWordInfoList *list = NULL;
|
|
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
|
|
|
X86CPUFeatureWordInfo *qwi = &word_infos[w];
|
|
|
|
qwi->cpuid_input_eax = wi->cpuid_eax;
|
|
|
|
qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx;
|
|
|
|
qwi->cpuid_input_ecx = wi->cpuid_ecx;
|
|
|
|
qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum;
|
2013-05-06 20:20:09 +04:00
|
|
|
qwi->features = array[w];
|
2013-05-06 20:20:07 +04:00
|
|
|
|
|
|
|
/* List will be in reverse order, but order shouldn't matter */
|
|
|
|
list_entries[w].next = list;
|
|
|
|
list_entries[w].value = &word_infos[w];
|
|
|
|
list = &list_entries[w];
|
|
|
|
}
|
|
|
|
|
2016-06-14 00:57:57 +03:00
|
|
|
visit_type_X86CPUFeatureWordInfoList(v, "feature-words", &list, errp);
|
2013-05-06 20:20:07 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_get_hv_spinlocks(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2013-06-04 17:05:25 +04:00
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
int64_t value = cpu->hyperv_spinlock_attempts;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, errp);
|
2013-06-04 17:05:25 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_set_hv_spinlocks(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2013-06-04 17:05:25 +04:00
|
|
|
{
|
|
|
|
const int64_t min = 0xFFF;
|
|
|
|
const int64_t max = UINT_MAX;
|
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
|
|
|
Error *err = NULL;
|
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, &err);
|
2013-06-04 17:05:25 +04:00
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < min || value > max) {
|
|
|
|
error_setg(errp, "Property %s.%s doesn't take value %" PRId64
|
2014-07-28 11:13:06 +04:00
|
|
|
" (minimum: %" PRId64 ", maximum: %" PRId64 ")",
|
|
|
|
object_get_typename(obj), name ? name : "null",
|
|
|
|
value, min, max);
|
2013-06-04 17:05:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
cpu->hyperv_spinlock_attempts = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PropertyInfo qdev_prop_spinlocks = {
|
|
|
|
.name = "int",
|
|
|
|
.get = x86_get_hv_spinlocks,
|
|
|
|
.set = x86_set_hv_spinlocks,
|
|
|
|
};
|
|
|
|
|
2013-04-26 20:04:32 +04:00
|
|
|
/* Convert all '_' in a feature string option name to '-', to make feature
|
|
|
|
* name conform to QOM property naming rule, which uses '-' instead of '_'.
|
|
|
|
*/
|
|
|
|
static inline void feat2prop(char *s)
|
|
|
|
{
|
|
|
|
while ((s = strchr(s, '_'))) {
|
|
|
|
*s = '-';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-03 19:48:13 +03:00
|
|
|
/* Return the feature property name for a feature flag bit */
|
|
|
|
static const char *x86_cpu_feature_name(FeatureWord w, int bitnr)
|
|
|
|
{
|
|
|
|
/* XSAVE components are automatically enabled by other features,
|
|
|
|
* so return the original feature name instead
|
|
|
|
*/
|
|
|
|
if (w == FEAT_XSAVE_COMP_LO || w == FEAT_XSAVE_COMP_HI) {
|
|
|
|
int comp = (w == FEAT_XSAVE_COMP_HI) ? bitnr + 32 : bitnr;
|
|
|
|
|
|
|
|
if (comp < ARRAY_SIZE(x86_ext_save_areas) &&
|
|
|
|
x86_ext_save_areas[comp].bits) {
|
|
|
|
w = x86_ext_save_areas[comp].feature;
|
|
|
|
bitnr = ctz32(x86_ext_save_areas[comp].bits);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(bitnr < 32);
|
|
|
|
assert(w < FEATURE_WORDS);
|
|
|
|
return feature_word_info[w].feat_names[bitnr];
|
|
|
|
}
|
|
|
|
|
2016-06-06 18:16:44 +03:00
|
|
|
/* Compatibily hack to maintain legacy +-feat semantic,
|
|
|
|
* where +-feat overwrites any feature set by
|
|
|
|
* feat=on|feat even if the later is parsed after +-feat
|
|
|
|
* (i.e. "-x2apic,x2apic=on" will result in x2apic disabled)
|
|
|
|
*/
|
2016-09-30 21:49:39 +03:00
|
|
|
static GList *plus_features, *minus_features;
|
2016-06-06 18:16:44 +03:00
|
|
|
|
2016-10-24 22:53:52 +03:00
|
|
|
static gint compare_string(gconstpointer a, gconstpointer b)
|
|
|
|
{
|
|
|
|
return g_strcmp0(a, b);
|
|
|
|
}
|
|
|
|
|
2012-12-04 23:34:39 +04:00
|
|
|
/* Parse "+feature,-feature,feature=foo" CPU feature string
|
|
|
|
*/
|
2016-06-09 20:11:01 +03:00
|
|
|
static void x86_cpu_parse_featurestr(const char *typename, char *features,
|
2014-03-04 02:19:19 +04:00
|
|
|
Error **errp)
|
2012-12-04 23:34:39 +04:00
|
|
|
{
|
|
|
|
char *featurestr; /* Single 'key=value" string being parsed */
|
2016-06-09 20:11:01 +03:00
|
|
|
static bool cpu_globals_initialized;
|
2016-10-24 22:53:52 +03:00
|
|
|
bool ambiguous = false;
|
2016-06-09 20:11:01 +03:00
|
|
|
|
|
|
|
if (cpu_globals_initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cpu_globals_initialized = true;
|
2012-12-04 23:34:39 +04:00
|
|
|
|
2016-06-09 20:10:58 +03:00
|
|
|
if (!features) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (featurestr = strtok(features, ",");
|
2016-11-25 18:21:53 +03:00
|
|
|
featurestr;
|
2016-06-09 20:10:58 +03:00
|
|
|
featurestr = strtok(NULL, ",")) {
|
|
|
|
const char *name;
|
|
|
|
const char *val = NULL;
|
|
|
|
char *eq = NULL;
|
2016-06-21 15:04:40 +03:00
|
|
|
char num[32];
|
2016-06-09 20:11:01 +03:00
|
|
|
GlobalProperty *prop;
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2016-06-09 20:10:58 +03:00
|
|
|
/* Compatibility syntax: */
|
2010-03-11 16:38:55 +03:00
|
|
|
if (featurestr[0] == '+') {
|
2016-09-30 21:49:39 +03:00
|
|
|
plus_features = g_list_append(plus_features,
|
|
|
|
g_strdup(featurestr + 1));
|
2016-06-09 20:10:58 +03:00
|
|
|
continue;
|
2010-03-11 16:38:55 +03:00
|
|
|
} else if (featurestr[0] == '-') {
|
2016-09-30 21:49:39 +03:00
|
|
|
minus_features = g_list_append(minus_features,
|
|
|
|
g_strdup(featurestr + 1));
|
2016-06-09 20:10:58 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
eq = strchr(featurestr, '=');
|
|
|
|
if (eq) {
|
|
|
|
*eq++ = 0;
|
|
|
|
val = eq;
|
2010-03-11 16:38:55 +03:00
|
|
|
} else {
|
2016-06-09 20:10:58 +03:00
|
|
|
val = "on";
|
2013-01-21 18:06:38 +04:00
|
|
|
}
|
2016-06-09 20:10:58 +03:00
|
|
|
|
|
|
|
feat2prop(featurestr);
|
|
|
|
name = featurestr;
|
|
|
|
|
2016-10-24 22:53:52 +03:00
|
|
|
if (g_list_find_custom(plus_features, name, compare_string)) {
|
|
|
|
error_report("warning: Ambiguous CPU model string. "
|
|
|
|
"Don't mix both \"+%s\" and \"%s=%s\"",
|
|
|
|
name, name, val);
|
|
|
|
ambiguous = true;
|
|
|
|
}
|
|
|
|
if (g_list_find_custom(minus_features, name, compare_string)) {
|
|
|
|
error_report("warning: Ambiguous CPU model string. "
|
|
|
|
"Don't mix both \"-%s\" and \"%s=%s\"",
|
|
|
|
name, name, val);
|
|
|
|
ambiguous = true;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:10:58 +03:00
|
|
|
/* Special case: */
|
|
|
|
if (!strcmp(name, "tsc-freq")) {
|
2017-02-21 23:14:06 +03:00
|
|
|
int ret;
|
2017-02-21 23:14:07 +03:00
|
|
|
uint64_t tsc_freq;
|
2016-06-09 20:10:58 +03:00
|
|
|
|
2017-02-21 23:14:06 +03:00
|
|
|
ret = qemu_strtosz_metric(val, NULL, &tsc_freq);
|
2017-02-21 23:14:07 +03:00
|
|
|
if (ret < 0 || tsc_freq > INT64_MAX) {
|
2016-06-09 20:10:58 +03:00
|
|
|
error_setg(errp, "bad numerical value %s", val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
|
|
|
|
val = num;
|
|
|
|
name = "tsc-frequency";
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
2016-06-09 20:10:58 +03:00
|
|
|
|
2016-06-09 20:11:01 +03:00
|
|
|
prop = g_new0(typeof(*prop), 1);
|
|
|
|
prop->driver = typename;
|
|
|
|
prop->property = g_strdup(name);
|
|
|
|
prop->value = g_strdup(val);
|
|
|
|
prop->errp = &error_fatal;
|
|
|
|
qdev_prop_register_global(prop);
|
2016-06-09 20:10:58 +03:00
|
|
|
}
|
|
|
|
|
2016-10-24 22:53:52 +03:00
|
|
|
if (ambiguous) {
|
|
|
|
error_report("warning: Compatibility of ambiguous CPU model "
|
|
|
|
"strings won't be kept on future QEMU versions");
|
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
2017-01-17 00:11:21 +03:00
|
|
|
static void x86_cpu_expand_features(X86CPU *cpu, Error **errp);
|
2016-05-03 19:48:13 +03:00
|
|
|
static int x86_cpu_filter_features(X86CPU *cpu);
|
|
|
|
|
|
|
|
/* Check for missing features that may prevent the CPU class from
|
|
|
|
* running using the current machine and accelerator.
|
|
|
|
*/
|
|
|
|
static void x86_cpu_class_check_missing_features(X86CPUClass *xcc,
|
|
|
|
strList **missing_feats)
|
|
|
|
{
|
|
|
|
X86CPU *xc;
|
|
|
|
FeatureWord w;
|
|
|
|
Error *err = NULL;
|
|
|
|
strList **next = missing_feats;
|
|
|
|
|
|
|
|
if (xcc->kvm_required && !kvm_enabled()) {
|
|
|
|
strList *new = g_new0(strList, 1);
|
|
|
|
new->value = g_strdup("kvm");;
|
|
|
|
*missing_feats = new;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xc = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(xcc))));
|
|
|
|
|
2017-01-17 00:11:21 +03:00
|
|
|
x86_cpu_expand_features(xc, &err);
|
2016-05-03 19:48:13 +03:00
|
|
|
if (err) {
|
2017-01-17 00:11:21 +03:00
|
|
|
/* Errors at x86_cpu_expand_features should never happen,
|
2016-05-03 19:48:13 +03:00
|
|
|
* but in case it does, just report the model as not
|
|
|
|
* runnable at all using the "type" property.
|
|
|
|
*/
|
|
|
|
strList *new = g_new0(strList, 1);
|
|
|
|
new->value = g_strdup("type");
|
|
|
|
*next = new;
|
|
|
|
next = &new->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
x86_cpu_filter_features(xc);
|
|
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
uint32_t filtered = xc->filtered_features[w];
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
if (filtered & (1UL << i)) {
|
|
|
|
strList *new = g_new0(strList, 1);
|
|
|
|
new->value = g_strdup(x86_cpu_feature_name(w, i));
|
|
|
|
*next = new;
|
|
|
|
next = &new->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object_unref(OBJECT(xc));
|
|
|
|
}
|
|
|
|
|
2015-02-03 20:48:55 +03:00
|
|
|
/* Print all cpuid feature names in featureset
|
2010-03-11 16:38:55 +03:00
|
|
|
*/
|
2015-02-03 20:48:55 +03:00
|
|
|
static void listflags(FILE *f, fprintf_function print, const char **featureset)
|
2015-03-03 03:29:17 +03:00
|
|
|
{
|
2015-02-03 20:48:55 +03:00
|
|
|
int bit;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
for (bit = 0; bit < 32; bit++) {
|
|
|
|
if (featureset[bit]) {
|
|
|
|
print(f, "%s%s", first ? "" : " ", featureset[bit]);
|
|
|
|
first = false;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
2015-02-03 20:48:55 +03:00
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
2017-01-20 00:04:45 +03:00
|
|
|
/* Sort alphabetically by type name, respecting X86CPUClass::ordering. */
|
2016-09-30 21:49:36 +03:00
|
|
|
static gint x86_cpu_list_compare(gconstpointer a, gconstpointer b)
|
|
|
|
{
|
|
|
|
ObjectClass *class_a = (ObjectClass *)a;
|
|
|
|
ObjectClass *class_b = (ObjectClass *)b;
|
|
|
|
X86CPUClass *cc_a = X86_CPU_CLASS(class_a);
|
|
|
|
X86CPUClass *cc_b = X86_CPU_CLASS(class_b);
|
|
|
|
const char *name_a, *name_b;
|
|
|
|
|
2017-01-20 00:04:45 +03:00
|
|
|
if (cc_a->ordering != cc_b->ordering) {
|
|
|
|
return cc_a->ordering - cc_b->ordering;
|
2016-09-30 21:49:36 +03:00
|
|
|
} else {
|
|
|
|
name_a = object_class_get_name(class_a);
|
|
|
|
name_b = object_class_get_name(class_b);
|
|
|
|
return strcmp(name_a, name_b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSList *get_sorted_cpu_model_list(void)
|
|
|
|
{
|
|
|
|
GSList *list = object_class_get_list(TYPE_X86_CPU, false);
|
|
|
|
list = g_slist_sort(list, x86_cpu_list_compare);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpu_list_entry(gpointer data, gpointer user_data)
|
|
|
|
{
|
|
|
|
ObjectClass *oc = data;
|
|
|
|
X86CPUClass *cc = X86_CPU_CLASS(oc);
|
|
|
|
CPUListState *s = user_data;
|
|
|
|
char *name = x86_cpu_class_get_model_name(cc);
|
|
|
|
const char *desc = cc->model_description;
|
2017-02-22 21:39:19 +03:00
|
|
|
if (!desc && cc->cpu_def) {
|
2016-09-30 21:49:36 +03:00
|
|
|
desc = cc->cpu_def->model_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*s->cpu_fprintf)(s->file, "x86 %16s %-48s\n",
|
|
|
|
name, desc);
|
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* list available CPU models and flags */
|
2012-09-06 00:41:08 +04:00
|
|
|
void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
|
2010-03-11 16:38:55 +03:00
|
|
|
{
|
2013-01-21 04:02:28 +04:00
|
|
|
int i;
|
2016-09-30 21:49:36 +03:00
|
|
|
CPUListState s = {
|
|
|
|
.file = f,
|
|
|
|
.cpu_fprintf = cpu_fprintf,
|
|
|
|
};
|
|
|
|
GSList *list;
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2016-09-30 21:49:36 +03:00
|
|
|
(*cpu_fprintf)(f, "Available CPUs:\n");
|
|
|
|
list = get_sorted_cpu_model_list();
|
|
|
|
g_slist_foreach(list, x86_cpu_list_entry, &s);
|
|
|
|
g_slist_free(list);
|
2013-03-24 20:01:02 +04:00
|
|
|
|
2012-09-06 00:41:07 +04:00
|
|
|
(*cpu_fprintf)(f, "\nRecognized CPUID flags:\n");
|
2013-02-27 13:15:51 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) {
|
|
|
|
FeatureWordInfo *fw = &feature_word_info[i];
|
|
|
|
|
2015-02-03 20:48:55 +03:00
|
|
|
(*cpu_fprintf)(f, " ");
|
|
|
|
listflags(f, cpu_fprintf, fw->feat_names);
|
|
|
|
(*cpu_fprintf)(f, "\n");
|
2013-02-27 13:15:51 +04:00
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
2016-09-30 21:49:36 +03:00
|
|
|
static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
|
|
|
|
{
|
|
|
|
ObjectClass *oc = data;
|
|
|
|
X86CPUClass *cc = X86_CPU_CLASS(oc);
|
|
|
|
CpuDefinitionInfoList **cpu_list = user_data;
|
|
|
|
CpuDefinitionInfoList *entry;
|
|
|
|
CpuDefinitionInfo *info;
|
|
|
|
|
|
|
|
info = g_malloc0(sizeof(*info));
|
|
|
|
info->name = x86_cpu_class_get_model_name(cc);
|
2016-05-03 19:48:13 +03:00
|
|
|
x86_cpu_class_check_missing_features(cc, &info->unavailable_features);
|
|
|
|
info->has_unavailable_features = true;
|
2016-11-16 21:21:39 +03:00
|
|
|
info->q_typename = g_strdup(object_class_get_name(oc));
|
2017-01-16 21:12:12 +03:00
|
|
|
info->migration_safe = cc->migration_safe;
|
|
|
|
info->has_migration_safe = true;
|
i386: Define static "base" CPU model
The query-cpu-model-expand QMP command needs at least one static
model, to allow the "static" expansion mode to be implemented.
Instead of defining static versions of every CPU model, define a
"base" CPU model that has absolutely no feature flag enabled.
Despite having no CPUID data set at all, "-cpu base" is even a
functional CPU:
* It can boot a Slackware Linux 1.01 image with a Linux 0.99.12
kernel[1].
* It is even possible to boot[2] a modern Fedora x86_64 guest by
manually enabling the following CPU features:
-cpu base,+lm,+msr,+pae,+fpu,+cx8,+cmov,+sse,+sse2,+fxsr
[1] http://www.qemu-advent-calendar.org/2014/#day-1
[2] This is what can be seen in the guest:
[root@localhost ~]# cat /proc/cpuinfo
processor : 0
vendor_id : unknown
cpu family : 0
model : 0
model name : 00/00
stepping : 0
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu msr pae cx8 cmov fxsr sse sse2 lm nopl
bugs :
bogomips : 5832.70
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
[root@localhost ~]# x86info -v -a
x86info v1.30. Dave Jones 2001-2011
Feedback to <davej@redhat.com>.
No TSC, MHz calculation cannot be performed.
Unknown vendor (0)
MP Table:
Family: 0 Model: 0 Stepping: 0
CPU Model (x86info's best guess):
eax in: 0x00000000, eax = 00000001 ebx = 00000000 ecx = 00000000 edx = 00000000
eax in: 0x00000001, eax = 00000000 ebx = 00000800 ecx = 00000000 edx = 07008161
eax in: 0x80000000, eax = 80000001 ebx = 00000000 ecx = 00000000 edx = 00000000
eax in: 0x80000001, eax = 00000000 ebx = 00000000 ecx = 00000000 edx = 20000000
Feature flags:
fpu Onboard FPU
msr Model-Specific Registers
pae Physical Address Extensions
cx8 CMPXCHG8 instruction
cmov CMOV instruction
fxsr FXSAVE and FXRSTOR instructions
sse SSE support
sse2 SSE2 support
Long NOPs supported: yes
Address sizes : 0 bits physical, 0 bits virtual
0MHz processor (estimate).
running at an estimated 0MHz
[root@localhost ~]#
Message-Id: <20170222190029.17243-2-ehabkost@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-02-22 22:00:27 +03:00
|
|
|
info->q_static = cc->static_model;
|
2016-09-30 21:49:36 +03:00
|
|
|
|
|
|
|
entry = g_malloc0(sizeof(*entry));
|
|
|
|
entry->value = info;
|
|
|
|
entry->next = *cpu_list;
|
|
|
|
*cpu_list = entry;
|
|
|
|
}
|
|
|
|
|
2012-08-15 07:17:36 +04:00
|
|
|
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
|
2012-08-10 20:04:14 +04:00
|
|
|
{
|
|
|
|
CpuDefinitionInfoList *cpu_list = NULL;
|
2016-09-30 21:49:36 +03:00
|
|
|
GSList *list = get_sorted_cpu_model_list();
|
|
|
|
g_slist_foreach(list, x86_cpu_definition_entry, &cpu_list);
|
|
|
|
g_slist_free(list);
|
2012-08-10 20:04:14 +04:00
|
|
|
return cpu_list;
|
|
|
|
}
|
|
|
|
|
2014-04-30 20:48:41 +04:00
|
|
|
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
|
|
|
bool migratable_only)
|
2014-04-30 20:48:32 +04:00
|
|
|
{
|
|
|
|
FeatureWordInfo *wi = &feature_word_info[w];
|
2014-04-30 20:48:41 +04:00
|
|
|
uint32_t r;
|
2014-04-30 20:48:32 +04:00
|
|
|
|
2014-04-30 20:48:39 +04:00
|
|
|
if (kvm_enabled()) {
|
2014-04-30 20:48:41 +04:00
|
|
|
r = kvm_arch_get_supported_cpuid(kvm_state, wi->cpuid_eax,
|
|
|
|
wi->cpuid_ecx,
|
|
|
|
wi->cpuid_reg);
|
2014-04-30 20:48:39 +04:00
|
|
|
} else if (tcg_enabled()) {
|
2014-04-30 20:48:41 +04:00
|
|
|
r = wi->tcg_features;
|
2014-04-30 20:48:39 +04:00
|
|
|
} else {
|
|
|
|
return ~0;
|
|
|
|
}
|
2014-04-30 20:48:41 +04:00
|
|
|
if (migratable_only) {
|
|
|
|
r &= x86_cpu_get_migratable_flags(w);
|
|
|
|
}
|
|
|
|
return r;
|
2014-04-30 20:48:32 +04:00
|
|
|
}
|
|
|
|
|
2016-05-04 20:50:46 +03:00
|
|
|
static void x86_cpu_report_filtered_features(X86CPU *cpu)
|
|
|
|
{
|
|
|
|
FeatureWord w;
|
|
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
report_unavailable_features(w, cpu->filtered_features[w]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 18:40:27 +03:00
|
|
|
static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
|
|
|
|
{
|
|
|
|
PropValue *pv;
|
|
|
|
for (pv = props; pv->prop; pv++) {
|
|
|
|
if (!pv->value) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
object_property_parse(OBJECT(cpu), pv->value, pv->prop,
|
|
|
|
&error_abort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-22 22:00:28 +03:00
|
|
|
/* Load data from X86CPUDefinition into a X86CPU object
|
2014-01-30 23:48:56 +04:00
|
|
|
*/
|
2014-02-10 14:21:30 +04:00
|
|
|
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
|
2010-03-11 16:38:55 +03:00
|
|
|
{
|
2012-04-17 14:00:51 +04:00
|
|
|
CPUX86State *env = &cpu->env;
|
2014-02-19 23:39:21 +04:00
|
|
|
const char *vendor;
|
|
|
|
char host_vendor[CPUID_VENDOR_SZ + 1];
|
2014-04-30 20:48:37 +04:00
|
|
|
FeatureWord w;
|
2010-03-11 16:38:55 +03:00
|
|
|
|
2017-02-22 22:00:28 +03:00
|
|
|
/*NOTE: any property set by this function should be returned by
|
|
|
|
* x86_cpu_static_props(), so static expansion of
|
|
|
|
* query-cpu-model-expansion is always complete.
|
|
|
|
*/
|
|
|
|
|
2016-09-21 19:30:12 +03:00
|
|
|
/* CPU models only set _minimum_ values for level/xlevel: */
|
|
|
|
object_property_set_int(OBJECT(cpu), def->level, "min-level", errp);
|
|
|
|
object_property_set_int(OBJECT(cpu), def->xlevel, "min-xlevel", errp);
|
|
|
|
|
2013-02-15 17:06:56 +04:00
|
|
|
object_property_set_int(OBJECT(cpu), def->family, "family", errp);
|
|
|
|
object_property_set_int(OBJECT(cpu), def->model, "model", errp);
|
|
|
|
object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp);
|
|
|
|
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
|
2014-04-30 20:48:37 +04:00
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
env->features[w] = def->features[w];
|
|
|
|
}
|
2014-01-30 23:48:54 +04:00
|
|
|
|
2014-01-30 23:48:58 +04:00
|
|
|
/* Special cases not set in the X86CPUDefinition structs: */
|
2014-01-30 23:48:54 +04:00
|
|
|
if (kvm_enabled()) {
|
2016-02-25 18:15:12 +03:00
|
|
|
if (!kvm_irqchip_in_kernel()) {
|
|
|
|
x86_cpu_change_kvm_default("x2apic", "off");
|
|
|
|
}
|
|
|
|
|
2015-09-11 18:40:27 +03:00
|
|
|
x86_cpu_apply_props(cpu, kvm_default_props);
|
2016-09-30 21:49:37 +03:00
|
|
|
} else if (tcg_enabled()) {
|
|
|
|
x86_cpu_apply_props(cpu, tcg_default_props);
|
2014-01-30 23:48:54 +04:00
|
|
|
}
|
2014-02-19 18:58:10 +04:00
|
|
|
|
2014-01-30 23:48:54 +04:00
|
|
|
env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
|
2014-01-30 23:48:55 +04:00
|
|
|
|
|
|
|
/* sysenter isn't supported in compatibility mode on AMD,
|
|
|
|
* syscall isn't supported in compatibility mode on Intel.
|
|
|
|
* Normally we advertise the actual CPU vendor, but you can
|
|
|
|
* override this using the 'vendor' property if you want to use
|
|
|
|
* KVM's sysenter/syscall emulation in compatibility mode and
|
|
|
|
* when doing cross vendor migration
|
|
|
|
*/
|
2014-02-19 23:39:21 +04:00
|
|
|
vendor = def->vendor;
|
2014-01-30 23:48:55 +04:00
|
|
|
if (kvm_enabled()) {
|
|
|
|
uint32_t ebx = 0, ecx = 0, edx = 0;
|
|
|
|
host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
|
|
|
|
x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx);
|
|
|
|
vendor = host_vendor;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_property_set_str(OBJECT(cpu), vendor, "vendor", errp);
|
|
|
|
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
2017-02-22 22:00:28 +03:00
|
|
|
/* Return a QDict containing keys for all properties that can be included
|
|
|
|
* in static expansion of CPU models. All properties set by x86_cpu_load_def()
|
|
|
|
* must be included in the dictionary.
|
|
|
|
*/
|
|
|
|
static QDict *x86_cpu_static_props(void)
|
|
|
|
{
|
|
|
|
FeatureWord w;
|
|
|
|
int i;
|
|
|
|
static const char *props[] = {
|
|
|
|
"min-level",
|
|
|
|
"min-xlevel",
|
|
|
|
"family",
|
|
|
|
"model",
|
|
|
|
"stepping",
|
|
|
|
"model-id",
|
|
|
|
"vendor",
|
|
|
|
"lmce",
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
static QDict *d;
|
|
|
|
|
|
|
|
if (d) {
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
d = qdict_new();
|
|
|
|
for (i = 0; props[i]; i++) {
|
|
|
|
qdict_put_obj(d, props[i], qnull());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
FeatureWordInfo *fi = &feature_word_info[w];
|
|
|
|
int bit;
|
|
|
|
for (bit = 0; bit < 32; bit++) {
|
|
|
|
if (!fi->feat_names[bit]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
qdict_put_obj(d, fi->feat_names[bit], qnull());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add an entry to @props dict, with the value for property. */
|
|
|
|
static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop)
|
|
|
|
{
|
|
|
|
QObject *value = object_property_get_qobject(OBJECT(cpu), prop,
|
|
|
|
&error_abort);
|
|
|
|
|
|
|
|
qdict_put_obj(props, prop, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert CPU model data from X86CPU object to a property dictionary
|
|
|
|
* that can recreate exactly the same CPU model.
|
|
|
|
*/
|
|
|
|
static void x86_cpu_to_dict(X86CPU *cpu, QDict *props)
|
|
|
|
{
|
|
|
|
QDict *sprops = x86_cpu_static_props();
|
|
|
|
const QDictEntry *e;
|
|
|
|
|
|
|
|
for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) {
|
|
|
|
const char *prop = qdict_entry_key(e);
|
|
|
|
x86_cpu_expand_prop(cpu, props, prop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-22 22:00:29 +03:00
|
|
|
/* Convert CPU model data from X86CPU object to a property dictionary
|
|
|
|
* that can recreate exactly the same CPU model, including every
|
|
|
|
* writeable QOM property.
|
|
|
|
*/
|
|
|
|
static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
|
|
|
|
{
|
|
|
|
ObjectPropertyIterator iter;
|
|
|
|
ObjectProperty *prop;
|
|
|
|
|
|
|
|
object_property_iter_init(&iter, OBJECT(cpu));
|
|
|
|
while ((prop = object_property_iter_next(&iter))) {
|
|
|
|
/* skip read-only or write-only properties */
|
|
|
|
if (!prop->get || !prop->set) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "hotplugged" is the only property that is configurable
|
|
|
|
* on the command-line but will be set differently on CPUs
|
|
|
|
* created using "-cpu ... -smp ..." and by CPUs created
|
|
|
|
* on the fly by x86_cpu_from_model() for querying. Skip it.
|
|
|
|
*/
|
|
|
|
if (!strcmp(prop->name, "hotplugged")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
x86_cpu_expand_prop(cpu, props, prop->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-22 22:00:28 +03:00
|
|
|
static void object_apply_props(Object *obj, QDict *props, Error **errp)
|
|
|
|
{
|
|
|
|
const QDictEntry *prop;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) {
|
|
|
|
object_property_set_qobject(obj, qdict_entry_value(prop),
|
|
|
|
qdict_entry_key(prop), &err);
|
|
|
|
if (err) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
error_propagate(errp, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create X86CPU object according to model+props specification */
|
|
|
|
static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *xc = NULL;
|
|
|
|
X86CPUClass *xcc;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model));
|
|
|
|
if (xcc == NULL) {
|
|
|
|
error_setg(&err, "CPU model '%s' not found", model);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
xc = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(xcc))));
|
|
|
|
if (props) {
|
|
|
|
object_apply_props(OBJECT(xc), props, &err);
|
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x86_cpu_expand_features(xc, &err);
|
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
object_unref(OBJECT(xc));
|
|
|
|
xc = NULL;
|
|
|
|
}
|
|
|
|
return xc;
|
|
|
|
}
|
|
|
|
|
|
|
|
CpuModelExpansionInfo *
|
|
|
|
arch_query_cpu_model_expansion(CpuModelExpansionType type,
|
|
|
|
CpuModelInfo *model,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *xc = NULL;
|
|
|
|
Error *err = NULL;
|
|
|
|
CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1);
|
|
|
|
QDict *props = NULL;
|
|
|
|
const char *base_name;
|
|
|
|
|
|
|
|
xc = x86_cpu_from_model(model->name,
|
|
|
|
model->has_props ?
|
|
|
|
qobject_to_qdict(model->props) :
|
|
|
|
NULL, &err);
|
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-02-22 22:00:29 +03:00
|
|
|
props = qdict_new();
|
2017-02-22 22:00:28 +03:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case CPU_MODEL_EXPANSION_TYPE_STATIC:
|
|
|
|
/* Static expansion will be based on "base" only */
|
|
|
|
base_name = "base";
|
2017-02-22 22:00:29 +03:00
|
|
|
x86_cpu_to_dict(xc, props);
|
2017-02-22 22:00:28 +03:00
|
|
|
break;
|
|
|
|
case CPU_MODEL_EXPANSION_TYPE_FULL:
|
|
|
|
/* As we don't return every single property, full expansion needs
|
|
|
|
* to keep the original model name+props, and add extra
|
|
|
|
* properties on top of that.
|
|
|
|
*/
|
|
|
|
base_name = model->name;
|
2017-02-22 22:00:29 +03:00
|
|
|
x86_cpu_to_dict_full(xc, props);
|
2017-02-22 22:00:28 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error_setg(&err, "Unsupportted expansion type");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!props) {
|
|
|
|
props = qdict_new();
|
|
|
|
}
|
|
|
|
x86_cpu_to_dict(xc, props);
|
|
|
|
|
|
|
|
ret->model = g_new0(CpuModelInfo, 1);
|
|
|
|
ret->model->name = g_strdup(base_name);
|
|
|
|
ret->model->props = QOBJECT(props);
|
|
|
|
ret->model->has_props = true;
|
|
|
|
|
|
|
|
out:
|
|
|
|
object_unref(OBJECT(xc));
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
qapi_free_CpuModelExpansionInfo(ret);
|
|
|
|
ret = NULL;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-12-28 19:34:02 +03:00
|
|
|
static gchar *x86_gdb_arch_name(CPUState *cs)
|
|
|
|
{
|
|
|
|
#ifdef TARGET_X86_64
|
|
|
|
return g_strdup("i386:x86-64");
|
|
|
|
#else
|
|
|
|
return g_strdup("i386");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-03-03 03:29:17 +03:00
|
|
|
X86CPU *cpu_x86_init(const char *cpu_model)
|
2013-04-11 18:51:40 +04:00
|
|
|
{
|
2016-06-06 18:16:46 +03:00
|
|
|
return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model));
|
2013-02-01 18:12:13 +04:00
|
|
|
}
|
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
X86CPUDefinition *cpudef = data;
|
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
|
|
|
|
|
|
|
xcc->cpu_def = cpudef;
|
2017-01-16 21:12:12 +03:00
|
|
|
xcc->migration_safe = true;
|
2014-02-10 14:21:30 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_register_cpudef_type(X86CPUDefinition *def)
|
|
|
|
{
|
|
|
|
char *typename = x86_cpu_type_name(def->name);
|
|
|
|
TypeInfo ti = {
|
|
|
|
.name = typename,
|
|
|
|
.parent = TYPE_X86_CPU,
|
|
|
|
.class_init = x86_cpu_cpudef_class_init,
|
|
|
|
.class_data = def,
|
|
|
|
};
|
|
|
|
|
2017-01-13 22:00:57 +03:00
|
|
|
/* AMD aliases are handled at runtime based on CPUID vendor, so
|
|
|
|
* they shouldn't be set on the CPU model table.
|
|
|
|
*/
|
|
|
|
assert(!(def->features[FEAT_8000_0001_EDX] & CPUID_EXT2_AMD_ALIASES));
|
|
|
|
|
2014-02-10 14:21:30 +04:00
|
|
|
type_register(&ti);
|
|
|
|
g_free(typename);
|
|
|
|
}
|
|
|
|
|
2010-03-11 16:38:55 +03:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
|
2010-06-19 11:42:34 +04:00
|
|
|
void cpu_clear_apic_feature(CPUX86State *env)
|
|
|
|
{
|
2013-04-22 23:00:15 +04:00
|
|
|
env->features[FEAT_1_EDX] &= ~CPUID_APIC;
|
2010-06-19 11:42:34 +04:00
|
|
|
}
|
|
|
|
|
2010-03-11 16:38:55 +03:00
|
|
|
#endif /* !CONFIG_USER_ONLY */
|
|
|
|
|
|
|
|
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|
|
|
uint32_t *eax, uint32_t *ebx,
|
|
|
|
uint32_t *ecx, uint32_t *edx)
|
|
|
|
{
|
2012-12-01 08:35:08 +04:00
|
|
|
X86CPU *cpu = x86_env_get_cpu(env);
|
|
|
|
CPUState *cs = CPU(cpu);
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
uint32_t pkg_offset;
|
2017-05-09 16:27:35 +03:00
|
|
|
uint32_t limit;
|
2012-12-01 08:35:08 +04:00
|
|
|
|
2017-05-09 16:27:35 +03:00
|
|
|
/* Calculate & apply limits for different index ranges */
|
|
|
|
if (index >= 0xC0000000) {
|
|
|
|
limit = env->cpuid_xlevel2;
|
|
|
|
} else if (index >= 0x80000000) {
|
|
|
|
limit = env->cpuid_xlevel;
|
2010-03-11 16:38:55 +03:00
|
|
|
} else {
|
2017-05-09 16:27:35 +03:00
|
|
|
limit = env->cpuid_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index > limit) {
|
|
|
|
/* Intel documentation states that invalid EAX input will
|
|
|
|
* return the same information as EAX=cpuid_level
|
|
|
|
* (Intel SDM Vol. 2A - Instruction Set Reference - CPUID)
|
|
|
|
*/
|
|
|
|
index = env->cpuid_level;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch(index) {
|
|
|
|
case 0:
|
|
|
|
*eax = env->cpuid_level;
|
2015-02-03 20:57:50 +03:00
|
|
|
*ebx = env->cpuid_vendor1;
|
|
|
|
*edx = env->cpuid_vendor2;
|
|
|
|
*ecx = env->cpuid_vendor3;
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*eax = env->cpuid_version;
|
2014-12-19 04:20:10 +03:00
|
|
|
*ebx = (cpu->apic_id << 24) |
|
|
|
|
8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
|
2013-04-22 23:00:15 +04:00
|
|
|
*ecx = env->features[FEAT_1_ECX];
|
2015-07-02 16:53:40 +03:00
|
|
|
if ((*ecx & CPUID_EXT_XSAVE) && (env->cr[4] & CR4_OSXSAVE_MASK)) {
|
|
|
|
*ecx |= CPUID_EXT_OSXSAVE;
|
|
|
|
}
|
2013-04-22 23:00:15 +04:00
|
|
|
*edx = env->features[FEAT_1_EDX];
|
2012-12-17 06:27:07 +04:00
|
|
|
if (cs->nr_cores * cs->nr_threads > 1) {
|
|
|
|
*ebx |= (cs->nr_cores * cs->nr_threads) << 16;
|
2015-07-02 16:53:40 +03:00
|
|
|
*edx |= CPUID_HT;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
/* cache info: needed for Pentium Pro compatibility */
|
2013-09-02 19:06:37 +04:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-27 19:24:37 +04:00
|
|
|
*eax = 1; /* Number of CPUID[EAX=2] calls required */
|
2010-03-11 16:38:55 +03:00
|
|
|
*ebx = 0;
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
if (!cpu->enable_l3_cache) {
|
|
|
|
*ecx = 0;
|
|
|
|
} else {
|
|
|
|
*ecx = L3_N_DESCRIPTOR;
|
|
|
|
}
|
2013-08-27 19:24:37 +04:00
|
|
|
*edx = (L1D_DESCRIPTOR << 16) | \
|
|
|
|
(L1I_DESCRIPTOR << 8) | \
|
|
|
|
(L2_DESCRIPTOR);
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
/* cache info: needed for Core compatibility */
|
2013-09-02 19:06:37 +04:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, count, eax, ebx, ecx, edx);
|
2013-11-19 20:49:46 +04:00
|
|
|
*eax &= ~0xFC000000;
|
2010-03-11 16:38:55 +03:00
|
|
|
} else {
|
2010-03-13 18:46:33 +03:00
|
|
|
*eax = 0;
|
2013-11-19 20:49:46 +04:00
|
|
|
switch (count) {
|
2010-03-11 16:38:55 +03:00
|
|
|
case 0: /* L1 dcache info */
|
2013-08-27 19:24:37 +04:00
|
|
|
*eax |= CPUID_4_TYPE_DCACHE | \
|
|
|
|
CPUID_4_LEVEL(1) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
|
|
|
*ebx = (L1D_LINE_SIZE - 1) | \
|
|
|
|
((L1D_PARTITIONS - 1) << 12) | \
|
|
|
|
((L1D_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L1D_SETS - 1;
|
|
|
|
*edx = CPUID_4_NO_INVD_SHARING;
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
|
|
|
case 1: /* L1 icache info */
|
2013-08-27 19:24:37 +04:00
|
|
|
*eax |= CPUID_4_TYPE_ICACHE | \
|
|
|
|
CPUID_4_LEVEL(1) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
|
|
|
*ebx = (L1I_LINE_SIZE - 1) | \
|
|
|
|
((L1I_PARTITIONS - 1) << 12) | \
|
|
|
|
((L1I_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L1I_SETS - 1;
|
|
|
|
*edx = CPUID_4_NO_INVD_SHARING;
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
|
|
|
case 2: /* L2 cache info */
|
2013-08-27 19:24:37 +04:00
|
|
|
*eax |= CPUID_4_TYPE_UNIFIED | \
|
|
|
|
CPUID_4_LEVEL(2) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
2012-12-17 06:27:07 +04:00
|
|
|
if (cs->nr_threads > 1) {
|
|
|
|
*eax |= (cs->nr_threads - 1) << 14;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
2013-08-27 19:24:37 +04:00
|
|
|
*ebx = (L2_LINE_SIZE - 1) | \
|
|
|
|
((L2_PARTITIONS - 1) << 12) | \
|
|
|
|
((L2_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L2_SETS - 1;
|
|
|
|
*edx = CPUID_4_NO_INVD_SHARING;
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
case 3: /* L3 cache info */
|
|
|
|
if (!cpu->enable_l3_cache) {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*eax |= CPUID_4_TYPE_UNIFIED | \
|
|
|
|
CPUID_4_LEVEL(3) | \
|
|
|
|
CPUID_4_SELF_INIT_LEVEL;
|
|
|
|
pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads);
|
|
|
|
*eax |= ((1 << pkg_offset) - 1) << 14;
|
|
|
|
*ebx = (L3_N_LINE_SIZE - 1) | \
|
|
|
|
((L3_N_PARTITIONS - 1) << 12) | \
|
|
|
|
((L3_N_ASSOCIATIVITY - 1) << 22);
|
|
|
|
*ecx = L3_N_SETS - 1;
|
|
|
|
*edx = CPUID_4_INCLUSIVE | CPUID_4_COMPLEX_IDX;
|
|
|
|
break;
|
2010-03-11 16:38:55 +03:00
|
|
|
default: /* end of info */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
2013-11-19 20:49:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* QEMU gives out its own APIC IDs, never pass down bits 31..26. */
|
|
|
|
if ((*eax & 31) && cs->nr_cores > 1) {
|
|
|
|
*eax |= (cs->nr_cores - 1) << 26;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
/* mwait info: needed for Core compatibility */
|
|
|
|
*eax = 0; /* Smallest monitor-line size in bytes */
|
|
|
|
*ebx = 0; /* Largest monitor-line size in bytes */
|
|
|
|
*ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
/* Thermal and Power Leaf */
|
2015-06-07 12:15:08 +03:00
|
|
|
*eax = env->features[FEAT_6_EAX];
|
2010-03-11 16:38:55 +03:00
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
2011-05-30 19:17:42 +04:00
|
|
|
case 7:
|
Expose CPUID leaf 7 only for -cpu host
Changes v2 -> v3;
- Check for kvm_enabled() before setting cpuid_7_0_ebx_features
Changes v1 -> v2:
- Use kvm_arch_get_supported_cpuid() instead of host_cpuid() on
cpu_x86_fill_host().
We should use GET_SUPPORTED_CPUID for all bits on "-cpu host"
eventually, but I am not changing all the other CPUID leaves because
we may not be able to test such an intrusive change in time for 1.1.
Description of the bug:
Since QEMU 0.15, the CPUID information on CPUID[EAX=7,ECX=0] is being
returned unfiltered to the guest, directly from the GET_SUPPORTED_CPUID
return value.
The problem is that this makes the resulting CPU feature flags
unpredictable and dependent on the host CPU and kernel version. This
breaks live-migration badly if migrating from a host CPU that supports
some features on that CPUID leaf (running a recent kernel) to a kernel
or host CPU that doesn't support it.
Migration also is incorrect (the virtual CPU changes under the guest's
feet) if you migrate in the opposite direction (from an old CPU/kernel
to a new CPU/kernel), but with less serious consequences (guests
normally query CPUID information only once on boot).
Fortunately, the bug affects only users using cpudefs with level >= 7.
The right behavior should be to explicitly enable those features on
[cpudef] config sections or on the "-cpu" command-line arguments. Right
now there is no predefined CPU model on QEMU that has those features:
the latest Intel model we have is Sandy Bridge.
I would like to get this fixed on 1.1, so I am submitting this patch,
that enables those features only if "-cpu host" is being used (as we
don't have any pre-defined CPU model that actually have those features).
After 1.1 is released, we can make those features properly configurable
on [cpudef] and -cpu configuration.
One problem is: with this patch, users with the following setup:
- Running QEMU 1.0;
- Using a cpudef having level >= 7;
- Running a kernel that supports the features on CPUID leaf 7; and
- Running on a CPU that supports some features on CPUID leaf 7
won't be able to live-migrate to QEMU 1.1. But for these users
live-migration is already broken (they can't live-migrate to hosts with
older CPUs or older kernels, already), I don't see how to avoid this
problem.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2012-05-21 18:27:02 +04:00
|
|
|
/* Structured Extended Feature Flags Enumeration Leaf */
|
|
|
|
if (count == 0) {
|
|
|
|
*eax = 0; /* Maximum ECX value for sub-leaves */
|
2013-04-22 23:00:15 +04:00
|
|
|
*ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */
|
2015-11-18 05:20:15 +03:00
|
|
|
*ecx = env->features[FEAT_7_0_ECX]; /* Feature flags */
|
2016-02-09 16:14:28 +03:00
|
|
|
if ((*ecx & CPUID_7_0_ECX_PKU) && env->cr[4] & CR4_PKE_MASK) {
|
|
|
|
*ecx |= CPUID_7_0_ECX_OSPKE;
|
|
|
|
}
|
2016-10-31 11:27:26 +03:00
|
|
|
*edx = env->features[FEAT_7_0_EDX]; /* Feature flags */
|
2011-05-30 19:17:42 +04:00
|
|
|
} else {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
}
|
|
|
|
break;
|
2010-03-11 16:38:55 +03:00
|
|
|
case 9:
|
|
|
|
/* Direct Cache Access Information Leaf */
|
|
|
|
*eax = 0; /* Bits 0-31 in DCA_CAP MSR */
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
case 0xA:
|
|
|
|
/* Architectural Performance Monitoring Leaf */
|
2013-07-27 00:09:36 +04:00
|
|
|
if (kvm_enabled() && cpu->enable_pmu) {
|
2012-12-01 08:35:08 +04:00
|
|
|
KVMState *s = cs->kvm_state;
|
2011-12-15 14:44:05 +04:00
|
|
|
|
|
|
|
*eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX);
|
|
|
|
*ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX);
|
|
|
|
*ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX);
|
|
|
|
*edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX);
|
|
|
|
} else {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
2016-05-12 20:24:26 +03:00
|
|
|
case 0xB:
|
|
|
|
/* Extended Topology Enumeration Leaf */
|
|
|
|
if (!cpu->enable_cpuid_0xb) {
|
|
|
|
*eax = *ebx = *ecx = *edx = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ecx = count & 0xff;
|
|
|
|
*edx = cpu->apic_id;
|
|
|
|
|
|
|
|
switch (count) {
|
|
|
|
case 0:
|
2016-09-16 18:50:24 +03:00
|
|
|
*eax = apicid_core_offset(cs->nr_cores, cs->nr_threads);
|
|
|
|
*ebx = cs->nr_threads;
|
2016-05-12 20:24:26 +03:00
|
|
|
*ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
|
|
|
|
break;
|
|
|
|
case 1:
|
2016-09-16 18:50:24 +03:00
|
|
|
*eax = apicid_pkg_offset(cs->nr_cores, cs->nr_threads);
|
|
|
|
*ebx = cs->nr_cores * cs->nr_threads;
|
2016-05-12 20:24:26 +03:00
|
|
|
*ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx |= CPUID_TOPOLOGY_LEVEL_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!(*eax & ~0x1f));
|
|
|
|
*ebx &= 0xffff; /* The count doesn't need to be reliable. */
|
|
|
|
break;
|
2013-10-02 19:54:57 +04:00
|
|
|
case 0xD: {
|
2010-06-17 11:18:14 +04:00
|
|
|
/* Processor Extended State */
|
2013-10-02 19:54:57 +04:00
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
2015-07-02 16:53:40 +03:00
|
|
|
if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
|
2010-06-17 11:18:14 +04:00
|
|
|
break;
|
|
|
|
}
|
2016-09-22 20:33:01 +03:00
|
|
|
|
2013-10-02 19:54:57 +04:00
|
|
|
if (count == 0) {
|
2016-09-22 23:41:35 +03:00
|
|
|
*ecx = xsave_area_size(x86_cpu_xsave_components(cpu));
|
|
|
|
*eax = env->features[FEAT_XSAVE_COMP_LO];
|
|
|
|
*edx = env->features[FEAT_XSAVE_COMP_HI];
|
2013-10-02 19:54:57 +04:00
|
|
|
*ebx = *ecx;
|
|
|
|
} else if (count == 1) {
|
2014-11-24 17:54:43 +03:00
|
|
|
*eax = env->features[FEAT_XSAVE];
|
2015-07-02 17:57:14 +03:00
|
|
|
} else if (count < ARRAY_SIZE(x86_ext_save_areas)) {
|
2016-09-22 23:41:35 +03:00
|
|
|
if ((x86_cpu_xsave_components(cpu) >> count) & 1) {
|
|
|
|
const ExtSaveArea *esa = &x86_ext_save_areas[count];
|
2013-12-03 00:17:50 +04:00
|
|
|
*eax = esa->size;
|
|
|
|
*ebx = esa->offset;
|
2013-10-02 19:54:57 +04:00
|
|
|
}
|
2010-06-17 11:18:14 +04:00
|
|
|
}
|
|
|
|
break;
|
2013-10-02 19:54:57 +04:00
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
case 0x80000000:
|
|
|
|
*eax = env->cpuid_xlevel;
|
|
|
|
*ebx = env->cpuid_vendor1;
|
|
|
|
*edx = env->cpuid_vendor2;
|
|
|
|
*ecx = env->cpuid_vendor3;
|
|
|
|
break;
|
|
|
|
case 0x80000001:
|
|
|
|
*eax = env->cpuid_version;
|
|
|
|
*ebx = 0;
|
2013-04-22 23:00:15 +04:00
|
|
|
*ecx = env->features[FEAT_8000_0001_ECX];
|
|
|
|
*edx = env->features[FEAT_8000_0001_EDX];
|
2010-03-11 16:38:55 +03:00
|
|
|
|
|
|
|
/* The Linux kernel checks for the CMPLegacy bit and
|
|
|
|
* discards multiple thread information if it is set.
|
2016-03-23 17:59:57 +03:00
|
|
|
* So don't set it here for Intel to make Linux guests happy.
|
2010-03-11 16:38:55 +03:00
|
|
|
*/
|
2012-12-17 06:27:07 +04:00
|
|
|
if (cs->nr_cores * cs->nr_threads > 1) {
|
2015-02-03 20:57:50 +03:00
|
|
|
if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 ||
|
|
|
|
env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 ||
|
|
|
|
env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) {
|
2010-03-11 16:38:55 +03:00
|
|
|
*ecx |= 1 << 1; /* CmpLegacy bit */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x80000002:
|
|
|
|
case 0x80000003:
|
|
|
|
case 0x80000004:
|
|
|
|
*eax = env->cpuid_model[(index - 0x80000002) * 4 + 0];
|
|
|
|
*ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1];
|
|
|
|
*ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2];
|
|
|
|
*edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
|
|
|
|
break;
|
|
|
|
case 0x80000005:
|
|
|
|
/* cache info (L1 cache) */
|
2013-09-02 19:06:37 +04:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-27 19:24:37 +04:00
|
|
|
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \
|
|
|
|
(L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES);
|
|
|
|
*ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \
|
|
|
|
(L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES);
|
|
|
|
*ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \
|
|
|
|
(L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE);
|
|
|
|
*edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \
|
|
|
|
(L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE);
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
|
|
|
case 0x80000006:
|
|
|
|
/* cache info (L2 cache) */
|
2013-09-02 19:06:37 +04:00
|
|
|
if (cpu->cache_info_passthrough) {
|
|
|
|
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-27 19:24:37 +04:00
|
|
|
*eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \
|
|
|
|
(L2_DTLB_2M_ENTRIES << 16) | \
|
|
|
|
(AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \
|
|
|
|
(L2_ITLB_2M_ENTRIES);
|
|
|
|
*ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | \
|
|
|
|
(L2_DTLB_4K_ENTRIES << 16) | \
|
|
|
|
(AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \
|
|
|
|
(L2_ITLB_4K_ENTRIES);
|
|
|
|
*ecx = (L2_SIZE_KB_AMD << 16) | \
|
|
|
|
(AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \
|
|
|
|
(L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE);
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
if (!cpu->enable_l3_cache) {
|
|
|
|
*edx = ((L3_SIZE_KB / 512) << 18) | \
|
|
|
|
(AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \
|
|
|
|
(L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE);
|
|
|
|
} else {
|
|
|
|
*edx = ((L3_N_SIZE_KB_AMD / 512) << 18) | \
|
|
|
|
(AMD_ENC_ASSOC(L3_N_ASSOCIATIVITY) << 12) | \
|
|
|
|
(L3_N_LINES_PER_TAG << 8) | (L3_N_LINE_SIZE);
|
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
2014-04-30 20:48:45 +04:00
|
|
|
case 0x80000007:
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = env->features[FEAT_8000_0007_EDX];
|
|
|
|
break;
|
2010-03-11 16:38:55 +03:00
|
|
|
case 0x80000008:
|
|
|
|
/* virtual & phys address size in low 2 bytes. */
|
2013-04-22 23:00:15 +04:00
|
|
|
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
2016-12-15 03:13:05 +03:00
|
|
|
/* 64 bit processor */
|
|
|
|
*eax = cpu->phys_bits; /* configurable physical bits */
|
|
|
|
if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57) {
|
|
|
|
*eax |= 0x00003900; /* 57 bits virtual */
|
|
|
|
} else {
|
|
|
|
*eax |= 0x00003000; /* 48 bits virtual */
|
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
} else {
|
2016-07-08 18:01:36 +03:00
|
|
|
*eax = cpu->phys_bits;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
2012-12-17 06:27:07 +04:00
|
|
|
if (cs->nr_cores * cs->nr_threads > 1) {
|
|
|
|
*ecx |= (cs->nr_cores * cs->nr_threads) - 1;
|
2010-03-11 16:38:55 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x8000000A:
|
2013-04-22 23:00:15 +04:00
|
|
|
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
|
2012-12-04 23:34:38 +04:00
|
|
|
*eax = 0x00000001; /* SVM Revision */
|
|
|
|
*ebx = 0x00000010; /* nr of ASIDs */
|
|
|
|
*ecx = 0;
|
2013-04-22 23:00:15 +04:00
|
|
|
*edx = env->features[FEAT_SVM]; /* optional features */
|
2012-12-04 23:34:38 +04:00
|
|
|
} else {
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
}
|
2010-03-11 16:38:55 +03:00
|
|
|
break;
|
2011-06-01 05:59:52 +04:00
|
|
|
case 0xC0000000:
|
|
|
|
*eax = env->cpuid_xlevel2;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
case 0xC0000001:
|
|
|
|
/* Support for VIA CPU's CPUID instruction */
|
|
|
|
*eax = env->cpuid_version;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
2013-04-22 23:00:15 +04:00
|
|
|
*edx = env->features[FEAT_C000_0001_EDX];
|
2011-06-01 05:59:52 +04:00
|
|
|
break;
|
|
|
|
case 0xC0000002:
|
|
|
|
case 0xC0000003:
|
|
|
|
case 0xC0000004:
|
|
|
|
/* Reserved for the future, and now filled with zero */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
2010-03-11 16:38:55 +03:00
|
|
|
default:
|
|
|
|
/* reserved values: zero */
|
|
|
|
*eax = 0;
|
|
|
|
*ebx = 0;
|
|
|
|
*ecx = 0;
|
|
|
|
*edx = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-04-03 01:20:08 +04:00
|
|
|
|
|
|
|
/* CPUClass::reset() */
|
|
|
|
static void x86_cpu_reset(CPUState *s)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(s);
|
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
|
|
|
|
CPUX86State *env = &cpu->env;
|
2015-07-07 18:13:10 +03:00
|
|
|
target_ulong cr4;
|
|
|
|
uint64_t xcr0;
|
2012-04-03 02:16:24 +04:00
|
|
|
int i;
|
|
|
|
|
2012-04-03 01:20:08 +04:00
|
|
|
xcc->parent_reset(s);
|
|
|
|
|
2015-04-24 21:49:15 +03:00
|
|
|
memset(env, 0, offsetof(CPUX86State, end_reset_fields));
|
2012-04-03 02:16:24 +04:00
|
|
|
|
|
|
|
env->old_exception = -1;
|
|
|
|
|
|
|
|
/* init to reset state */
|
|
|
|
|
|
|
|
env->hflags2 |= HF2_GIF_MASK;
|
|
|
|
|
|
|
|
cpu_x86_update_cr0(env, 0x60000010);
|
|
|
|
env->a20_mask = ~0x0;
|
|
|
|
env->smbase = 0x30000;
|
|
|
|
|
|
|
|
env->idt.limit = 0xffff;
|
|
|
|
env->gdt.limit = 0xffff;
|
|
|
|
env->ldt.limit = 0xffff;
|
|
|
|
env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
|
|
|
|
env->tr.limit = 0xffff;
|
|
|
|
env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
|
|
|
|
|
|
|
|
cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
|
|
|
|
DESC_R_MASK | DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
|
|
|
|
DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
|
|
|
|
DESC_A_MASK);
|
|
|
|
|
|
|
|
env->eip = 0xfff0;
|
|
|
|
env->regs[R_EDX] = env->cpuid_version;
|
|
|
|
|
|
|
|
env->eflags = 0x2;
|
|
|
|
|
|
|
|
/* FPU init */
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
env->fptags[i] = 1;
|
|
|
|
}
|
2014-09-17 12:05:19 +04:00
|
|
|
cpu_set_fpuc(env, 0x37f);
|
2012-04-03 02:16:24 +04:00
|
|
|
|
|
|
|
env->mxcsr = 0x1f80;
|
2015-07-07 18:13:10 +03:00
|
|
|
/* All units are in INIT state. */
|
|
|
|
env->xstate_bv = 0;
|
2012-04-03 02:16:24 +04:00
|
|
|
|
|
|
|
env->pat = 0x0007040600070406ULL;
|
|
|
|
env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
|
|
|
|
|
|
|
|
memset(env->dr, 0, sizeof(env->dr));
|
|
|
|
env->dr[6] = DR6_FIXED_1;
|
|
|
|
env->dr[7] = DR7_FIXED_1;
|
2013-09-02 19:26:20 +04:00
|
|
|
cpu_breakpoint_remove_all(s, BP_CPU);
|
2013-09-02 18:57:02 +04:00
|
|
|
cpu_watchpoint_remove_all(s, BP_CPU);
|
2012-07-23 17:22:27 +04:00
|
|
|
|
2015-07-07 18:13:10 +03:00
|
|
|
cr4 = 0;
|
2016-02-17 12:54:53 +03:00
|
|
|
xcr0 = XSTATE_FP_MASK;
|
2015-07-07 18:13:10 +03:00
|
|
|
|
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
|
|
/* Enable all the features for user-mode. */
|
|
|
|
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
|
2016-02-17 12:54:53 +03:00
|
|
|
xcr0 |= XSTATE_SSE_MASK;
|
2015-07-07 18:13:10 +03:00
|
|
|
}
|
2016-02-09 16:14:28 +03:00
|
|
|
for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
|
|
|
|
const ExtSaveArea *esa = &x86_ext_save_areas[i];
|
2016-09-23 00:58:39 +03:00
|
|
|
if (env->features[esa->feature] & esa->bits) {
|
2016-02-09 16:14:28 +03:00
|
|
|
xcr0 |= 1ull << i;
|
|
|
|
}
|
2015-07-07 18:13:10 +03:00
|
|
|
}
|
2016-02-09 16:14:28 +03:00
|
|
|
|
2015-07-07 18:13:10 +03:00
|
|
|
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
|
|
|
|
cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK;
|
|
|
|
}
|
2015-11-18 14:55:47 +03:00
|
|
|
if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_FSGSBASE) {
|
|
|
|
cr4 |= CR4_FSGSBASE_MASK;
|
|
|
|
}
|
2015-07-07 18:13:10 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
env->xcr0 = xcr0;
|
|
|
|
cpu_x86_update_cr4(env, cr4);
|
2013-12-06 12:33:01 +04:00
|
|
|
|
2014-08-15 01:39:39 +04:00
|
|
|
/*
|
|
|
|
* SDM 11.11.5 requires:
|
|
|
|
* - IA32_MTRR_DEF_TYPE MSR.E = 0
|
|
|
|
* - IA32_MTRR_PHYSMASKn.V = 0
|
|
|
|
* All other bits are undefined. For simplification, zero it all.
|
|
|
|
*/
|
|
|
|
env->mtrr_deftype = 0;
|
|
|
|
memset(env->mtrr_var, 0, sizeof(env->mtrr_var));
|
|
|
|
memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed));
|
|
|
|
|
2012-07-23 17:22:27 +04:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
/* We hard-wire the BSP to the first CPU. */
|
2015-04-02 02:58:36 +03:00
|
|
|
apic_designate_bsp(cpu->apic_state, s->cpu_index == 0);
|
2012-07-23 17:22:27 +04:00
|
|
|
|
2013-01-17 21:51:17 +04:00
|
|
|
s->halted = !cpu_is_bsp(cpu);
|
2013-03-20 16:11:56 +04:00
|
|
|
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
kvm_arch_reset_vcpu(cpu);
|
|
|
|
}
|
2012-07-23 17:22:27 +04:00
|
|
|
#endif
|
2012-04-03 01:20:08 +04:00
|
|
|
}
|
|
|
|
|
2012-07-23 17:22:27 +04:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
bool cpu_is_bsp(X86CPU *cpu)
|
|
|
|
{
|
2013-12-23 13:04:02 +04:00
|
|
|
return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
|
2012-07-23 17:22:27 +04:00
|
|
|
}
|
2012-07-23 17:22:28 +04:00
|
|
|
|
|
|
|
/* TODO: remove me, when reset over QOM tree is implemented */
|
|
|
|
static void x86_cpu_machine_reset_cb(void *opaque)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = opaque;
|
|
|
|
cpu_reset(CPU(cpu));
|
|
|
|
}
|
2012-07-23 17:22:27 +04:00
|
|
|
#endif
|
|
|
|
|
2012-04-03 02:00:17 +04:00
|
|
|
static void mce_init(X86CPU *cpu)
|
|
|
|
{
|
|
|
|
CPUX86State *cenv = &cpu->env;
|
|
|
|
unsigned int bank;
|
|
|
|
|
|
|
|
if (((cenv->cpuid_version >> 8) & 0xf) >= 6
|
2013-04-22 23:00:15 +04:00
|
|
|
&& (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
|
2012-04-03 02:00:17 +04:00
|
|
|
(CPUID_MCE | CPUID_MCA)) {
|
2016-06-22 09:56:21 +03:00
|
|
|
cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF |
|
|
|
|
(cpu->enable_lmce ? MCG_LMCE_P : 0);
|
2012-04-03 02:00:17 +04:00
|
|
|
cenv->mcg_ctl = ~(uint64_t)0;
|
|
|
|
for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
|
|
|
|
cenv->mce_banks[bank * 4] = ~(uint64_t)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-14 00:35:39 +04:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2016-10-10 18:28:42 +03:00
|
|
|
APICCommonClass *apic_get_class(void)
|
2012-10-14 00:35:39 +04:00
|
|
|
{
|
|
|
|
const char *apic_type = "apic";
|
|
|
|
|
2015-12-17 19:16:08 +03:00
|
|
|
if (kvm_apic_in_kernel()) {
|
2012-10-14 00:35:39 +04:00
|
|
|
apic_type = "kvm-apic";
|
|
|
|
} else if (xen_enabled()) {
|
|
|
|
apic_type = "xen-apic";
|
|
|
|
}
|
|
|
|
|
2016-10-10 18:28:42 +03:00
|
|
|
return APIC_COMMON_CLASS(object_class_by_name(apic_type));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
|
|
|
|
{
|
|
|
|
APICCommonState *apic;
|
|
|
|
ObjectClass *apic_class = OBJECT_CLASS(apic_get_class());
|
|
|
|
|
|
|
|
cpu->apic_state = DEVICE(object_new(object_class_get_name(apic_class)));
|
2012-10-14 00:35:39 +04:00
|
|
|
|
2016-07-06 09:20:52 +03:00
|
|
|
object_property_add_child(OBJECT(cpu), "lapic",
|
|
|
|
OBJECT(cpu->apic_state), &error_abort);
|
2016-07-06 09:20:53 +03:00
|
|
|
object_unref(OBJECT(cpu->apic_state));
|
2016-07-06 09:20:52 +03:00
|
|
|
|
2016-10-19 15:05:35 +03:00
|
|
|
qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
|
2012-10-14 00:35:39 +04:00
|
|
|
/* TODO: convert to link<> */
|
2013-12-23 13:04:02 +04:00
|
|
|
apic = APIC_COMMON(cpu->apic_state);
|
2012-10-10 16:10:07 +04:00
|
|
|
apic->cpu = cpu;
|
2015-09-16 12:19:11 +03:00
|
|
|
apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
|
2013-04-05 18:36:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
|
|
|
{
|
2015-09-16 12:19:11 +03:00
|
|
|
APICCommonState *apic;
|
|
|
|
static bool apic_mmio_map_once;
|
|
|
|
|
2013-12-23 13:04:02 +04:00
|
|
|
if (cpu->apic_state == NULL) {
|
2013-04-05 18:36:54 +04:00
|
|
|
return;
|
|
|
|
}
|
2015-02-05 12:29:15 +03:00
|
|
|
object_property_set_bool(OBJECT(cpu->apic_state), true, "realized",
|
|
|
|
errp);
|
2015-09-16 12:19:11 +03:00
|
|
|
|
|
|
|
/* Map APIC MMIO area */
|
|
|
|
apic = APIC_COMMON(cpu->apic_state);
|
|
|
|
if (!apic_mmio_map_once) {
|
|
|
|
memory_region_add_subregion_overlap(get_system_memory(),
|
|
|
|
apic->apicbase &
|
|
|
|
MSR_IA32_APICBASE_BASE,
|
|
|
|
&apic->io_memory,
|
|
|
|
0x1000);
|
|
|
|
apic_mmio_map_once = true;
|
|
|
|
}
|
2012-10-14 00:35:39 +04:00
|
|
|
}
|
2015-03-31 15:12:25 +03:00
|
|
|
|
|
|
|
static void x86_cpu_machine_done(Notifier *n, void *unused)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = container_of(n, X86CPU, machine_done);
|
|
|
|
MemoryRegion *smram =
|
|
|
|
(MemoryRegion *) object_resolve_path("/machine/smram", NULL);
|
|
|
|
|
|
|
|
if (smram) {
|
|
|
|
cpu->smram = g_new(MemoryRegion, 1);
|
|
|
|
memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram",
|
|
|
|
smram, 0, 1ull << 32);
|
|
|
|
memory_region_set_enabled(cpu->smram, false);
|
|
|
|
memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1);
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 18:36:54 +04:00
|
|
|
#else
|
|
|
|
static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
|
|
|
{
|
|
|
|
}
|
2012-10-14 00:35:39 +04:00
|
|
|
#endif
|
|
|
|
|
2016-07-11 22:28:46 +03:00
|
|
|
/* Note: Only safe for use on x86(-64) hosts */
|
|
|
|
static uint32_t x86_host_phys_bits(void)
|
|
|
|
{
|
|
|
|
uint32_t eax;
|
|
|
|
uint32_t host_phys_bits;
|
|
|
|
|
|
|
|
host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL);
|
|
|
|
if (eax >= 0x80000008) {
|
|
|
|
host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL);
|
|
|
|
/* Note: According to AMD doc 25481 rev 2.34 they have a field
|
|
|
|
* at 23:16 that can specify a maximum physical address bits for
|
|
|
|
* the guest that can override this value; but I've not seen
|
|
|
|
* anything with that set.
|
|
|
|
*/
|
|
|
|
host_phys_bits = eax & 0xff;
|
|
|
|
} else {
|
|
|
|
/* It's an odd 64 bit machine that doesn't have the leaf for
|
|
|
|
* physical address bits; fall back to 36 that's most older
|
|
|
|
* Intel.
|
|
|
|
*/
|
|
|
|
host_phys_bits = 36;
|
|
|
|
}
|
|
|
|
|
|
|
|
return host_phys_bits;
|
|
|
|
}
|
2014-10-21 19:00:45 +04:00
|
|
|
|
2016-09-21 19:30:12 +03:00
|
|
|
static void x86_cpu_adjust_level(X86CPU *cpu, uint32_t *min, uint32_t value)
|
|
|
|
{
|
|
|
|
if (*min < value) {
|
|
|
|
*min = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Increase cpuid_min_{level,xlevel,xlevel2} automatically, if appropriate */
|
|
|
|
static void x86_cpu_adjust_feat_level(X86CPU *cpu, FeatureWord w)
|
|
|
|
{
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
FeatureWordInfo *fi = &feature_word_info[w];
|
|
|
|
uint32_t eax = fi->cpuid_eax;
|
|
|
|
uint32_t region = eax & 0xF0000000;
|
|
|
|
|
|
|
|
if (!env->features[w]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (region) {
|
|
|
|
case 0x00000000:
|
|
|
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, eax);
|
|
|
|
break;
|
|
|
|
case 0x80000000:
|
|
|
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, eax);
|
|
|
|
break;
|
|
|
|
case 0xC0000000:
|
|
|
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel2, eax);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 23:27:56 +03:00
|
|
|
/* Calculate XSAVE components based on the configured CPU feature flags */
|
|
|
|
static void x86_cpu_enable_xsave_components(X86CPU *cpu)
|
|
|
|
{
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
int i;
|
2016-09-22 23:41:35 +03:00
|
|
|
uint64_t mask;
|
2016-09-22 23:27:56 +03:00
|
|
|
|
|
|
|
if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-30 21:49:42 +03:00
|
|
|
mask = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
|
2016-09-22 23:27:56 +03:00
|
|
|
const ExtSaveArea *esa = &x86_ext_save_areas[i];
|
|
|
|
if (env->features[esa->feature] & esa->bits) {
|
2016-09-22 23:41:35 +03:00
|
|
|
mask |= (1ULL << i);
|
2016-09-22 23:27:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 23:41:35 +03:00
|
|
|
env->features[FEAT_XSAVE_COMP_LO] = mask;
|
|
|
|
env->features[FEAT_XSAVE_COMP_HI] = mask >> 32;
|
2016-09-22 23:27:56 +03:00
|
|
|
}
|
|
|
|
|
2017-01-17 00:11:21 +03:00
|
|
|
/***** Steps involved on loading and filtering CPUID data
|
|
|
|
*
|
|
|
|
* When initializing and realizing a CPU object, the steps
|
|
|
|
* involved in setting up CPUID data are:
|
|
|
|
*
|
|
|
|
* 1) Loading CPU model definition (X86CPUDefinition). This is
|
|
|
|
* implemented by x86_cpu_load_def() and should be completely
|
|
|
|
* transparent, as it is done automatically by instance_init.
|
|
|
|
* No code should need to look at X86CPUDefinition structs
|
|
|
|
* outside instance_init.
|
|
|
|
*
|
|
|
|
* 2) CPU expansion. This is done by realize before CPUID
|
|
|
|
* filtering, and will make sure host/accelerator data is
|
|
|
|
* loaded for CPU models that depend on host capabilities
|
|
|
|
* (e.g. "host"). Done by x86_cpu_expand_features().
|
|
|
|
*
|
|
|
|
* 3) CPUID filtering. This initializes extra data related to
|
|
|
|
* CPUID, and checks if the host supports all capabilities
|
|
|
|
* required by the CPU. Runnability of a CPU model is
|
|
|
|
* determined at this step. Done by x86_cpu_filter_features().
|
|
|
|
*
|
|
|
|
* Some operations don't require all steps to be performed.
|
|
|
|
* More precisely:
|
|
|
|
*
|
|
|
|
* - CPU instance creation (instance_init) will run only CPU
|
|
|
|
* model loading. CPU expansion can't run at instance_init-time
|
|
|
|
* because host/accelerator data may be not available yet.
|
|
|
|
* - CPU realization will perform both CPU model expansion and CPUID
|
|
|
|
* filtering, and return an error in case one of them fails.
|
|
|
|
* - query-cpu-definitions needs to run all 3 steps. It needs
|
|
|
|
* to run CPUID filtering, as the 'unavailable-features'
|
|
|
|
* field is set based on the filtering results.
|
|
|
|
* - The query-cpu-model-expansion QMP command only needs to run
|
|
|
|
* CPU model loading and CPU expansion. It should not filter
|
|
|
|
* any CPUID data based on host capabilities.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Expand CPU configuration data, based on configured features
|
|
|
|
* and host/accelerator capabilities when appropriate.
|
|
|
|
*/
|
|
|
|
static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
2012-05-10 01:15:32 +04:00
|
|
|
{
|
2012-10-22 19:03:00 +04:00
|
|
|
CPUX86State *env = &cpu->env;
|
2016-06-06 18:16:44 +03:00
|
|
|
FeatureWord w;
|
2016-09-30 21:49:39 +03:00
|
|
|
GList *l;
|
2016-09-28 21:03:26 +03:00
|
|
|
Error *local_err = NULL;
|
2014-12-19 04:31:11 +03:00
|
|
|
|
2017-03-27 17:48:15 +03:00
|
|
|
/*TODO: Now cpu->max_features doesn't overwrite features
|
|
|
|
* set using QOM properties, and we can convert
|
2016-06-06 18:16:44 +03:00
|
|
|
* plus_features & minus_features to global properties
|
|
|
|
* inside x86_cpu_parse_featurestr() too.
|
|
|
|
*/
|
2017-01-20 00:04:46 +03:00
|
|
|
if (cpu->max_features) {
|
2016-06-06 18:16:44 +03:00
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
2017-03-27 17:48:15 +03:00
|
|
|
/* Override only features that weren't set explicitly
|
|
|
|
* by the user.
|
|
|
|
*/
|
|
|
|
env->features[w] |=
|
|
|
|
x86_cpu_get_supported_feature_word(w, cpu->migratable) &
|
|
|
|
~env->user_features[w];
|
2016-06-06 18:16:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 21:49:39 +03:00
|
|
|
for (l = plus_features; l; l = l->next) {
|
|
|
|
const char *prop = l->data;
|
|
|
|
object_property_set_bool(OBJECT(cpu), true, prop, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (l = minus_features; l; l = l->next) {
|
|
|
|
const char *prop = l->data;
|
|
|
|
object_property_set_bool(OBJECT(cpu), false, prop, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
2016-06-06 18:16:44 +03:00
|
|
|
}
|
|
|
|
|
2016-09-27 01:11:14 +03:00
|
|
|
if (!kvm_enabled() || !cpu->expose_kvm) {
|
|
|
|
env->features[FEAT_KVM] = 0;
|
|
|
|
}
|
|
|
|
|
2016-09-22 23:27:56 +03:00
|
|
|
x86_cpu_enable_xsave_components(cpu);
|
2016-09-21 19:30:12 +03:00
|
|
|
|
|
|
|
/* CPUID[EAX=7,ECX=0].EBX always increased level automatically: */
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_7_0_EBX);
|
|
|
|
if (cpu->full_cpuid_auto_level) {
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_1_EDX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_1_ECX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_C000_0001_EDX);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_SVM);
|
|
|
|
x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE);
|
2016-09-21 21:01:35 +03:00
|
|
|
/* SVM requires CPUID[0x8000000A] */
|
|
|
|
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
|
|
|
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A);
|
|
|
|
}
|
2016-09-21 19:30:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */
|
|
|
|
if (env->cpuid_level == UINT32_MAX) {
|
|
|
|
env->cpuid_level = env->cpuid_min_level;
|
|
|
|
}
|
|
|
|
if (env->cpuid_xlevel == UINT32_MAX) {
|
|
|
|
env->cpuid_xlevel = env->cpuid_min_xlevel;
|
|
|
|
}
|
|
|
|
if (env->cpuid_xlevel2 == UINT32_MAX) {
|
|
|
|
env->cpuid_xlevel2 = env->cpuid_min_xlevel2;
|
2012-10-22 19:03:00 +04:00
|
|
|
}
|
2012-05-10 01:15:32 +04:00
|
|
|
|
2016-09-28 21:03:26 +03:00
|
|
|
out:
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 00:11:21 +03:00
|
|
|
/*
|
|
|
|
* Finishes initialization of CPUID data, filters CPU feature
|
|
|
|
* words based on host availability of each feature.
|
|
|
|
*
|
|
|
|
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
|
|
|
|
*/
|
|
|
|
static int x86_cpu_filter_features(X86CPU *cpu)
|
|
|
|
{
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
FeatureWord w;
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
uint32_t host_feat =
|
|
|
|
x86_cpu_get_supported_feature_word(w, false);
|
|
|
|
uint32_t requested_features = env->features[w];
|
|
|
|
env->features[w] &= host_feat;
|
|
|
|
cpu->filtered_features[w] = requested_features & ~env->features[w];
|
|
|
|
if (cpu->filtered_features[w]) {
|
|
|
|
rv = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2016-09-28 21:03:26 +03:00
|
|
|
#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
|
|
|
|
(env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
|
|
|
|
(env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3)
|
|
|
|
#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && \
|
|
|
|
(env)->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && \
|
|
|
|
(env)->cpuid_vendor3 == CPUID_VENDOR_AMD_3)
|
|
|
|
static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(dev);
|
|
|
|
X86CPU *cpu = X86_CPU(dev);
|
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
static bool ht_warned;
|
|
|
|
|
|
|
|
if (xcc->kvm_required && !kvm_enabled()) {
|
|
|
|
char *name = x86_cpu_class_get_model_name(xcc);
|
|
|
|
error_setg(&local_err, "CPU model '%s' requires KVM", name);
|
|
|
|
g_free(name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
|
|
|
|
error_setg(errp, "apic-id property was not initialized properly");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-17 00:11:21 +03:00
|
|
|
x86_cpu_expand_features(cpu, &local_err);
|
2016-09-28 21:03:26 +03:00
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-05-04 20:50:46 +03:00
|
|
|
if (x86_cpu_filter_features(cpu) &&
|
|
|
|
(cpu->check_cpuid || cpu->enforce_cpuid)) {
|
|
|
|
x86_cpu_report_filtered_features(cpu);
|
|
|
|
if (cpu->enforce_cpuid) {
|
|
|
|
error_setg(&local_err,
|
|
|
|
kvm_enabled() ?
|
|
|
|
"Host doesn't support requested features" :
|
|
|
|
"TCG doesn't support requested features");
|
|
|
|
goto out;
|
|
|
|
}
|
target-i386: Set AMD alias bits after filtering CPUID data
QEMU complains about -cpu host on an AMD machine:
warning: host doesn't support requested feature: CPUID.80000001H:EDX [bit 0]
For bits 0,1,3,4,5,6,7,8,9,12,13,14,15,16,17,23,24.
KVM_GET_SUPPORTED_CPUID and and x86_cpu_get_migratable_flags()
don't handle the AMD CPUID aliases bits, making
x86_cpu_filter_features() print warnings and clear those CPUID
bits incorrectly.
To avoid hacking x86_cpu_get_migratable_flags() to handle
CPUID_EXT2_AMD_ALIASES (just like the existing hack inside
kvm_arch_get_supported_cpuid()), simply move the
CPUID_EXT2_AMD_ALIASES code in x86_cpu_realizefn() after the
x86_cpu_filter_features() call.
This will probably make the CPUID_EXT2_AMD_ALIASES hack in
kvm_arch_get_supported_cpuid() unnecessary, too. The hack will be
removed in a follow-up patch after v2.6.0.
Reported-by: Radim Krčmář <rkrcmar@redhat.com>
Tested-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2016-04-15 20:54:26 +03:00
|
|
|
}
|
|
|
|
|
2012-12-29 00:01:17 +04:00
|
|
|
/* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
|
|
|
|
* CPUID[1].EDX.
|
|
|
|
*/
|
2014-10-21 19:00:45 +04:00
|
|
|
if (IS_AMD_CPU(env)) {
|
2013-04-22 23:00:15 +04:00
|
|
|
env->features[FEAT_8000_0001_EDX] &= ~CPUID_EXT2_AMD_ALIASES;
|
|
|
|
env->features[FEAT_8000_0001_EDX] |= (env->features[FEAT_1_EDX]
|
2012-12-29 00:01:17 +04:00
|
|
|
& CPUID_EXT2_AMD_ALIASES);
|
|
|
|
}
|
|
|
|
|
2016-07-11 22:28:46 +03:00
|
|
|
/* For 64bit systems think about the number of physical bits to present.
|
|
|
|
* ideally this should be the same as the host; anything other than matching
|
|
|
|
* the host can cause incorrect guest behaviour.
|
|
|
|
* QEMU used to pick the magic value of 40 bits that corresponds to
|
|
|
|
* consumer AMD devices but nothing else.
|
|
|
|
*/
|
2016-07-08 18:01:36 +03:00
|
|
|
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
|
|
|
if (kvm_enabled()) {
|
2016-07-11 22:28:46 +03:00
|
|
|
uint32_t host_phys_bits = x86_host_phys_bits();
|
|
|
|
static bool warned;
|
|
|
|
|
|
|
|
if (cpu->host_phys_bits) {
|
|
|
|
/* The user asked for us to use the host physical bits */
|
|
|
|
cpu->phys_bits = host_phys_bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print a warning if the user set it to a value that's not the
|
|
|
|
* host value.
|
|
|
|
*/
|
|
|
|
if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 &&
|
|
|
|
!warned) {
|
|
|
|
error_report("Warning: Host physical bits (%u)"
|
|
|
|
" does not match phys-bits property (%u)",
|
|
|
|
host_phys_bits, cpu->phys_bits);
|
|
|
|
warned = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cpu->phys_bits &&
|
|
|
|
(cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS ||
|
|
|
|
cpu->phys_bits < 32)) {
|
2016-07-08 18:01:36 +03:00
|
|
|
error_setg(errp, "phys-bits should be between 32 and %u "
|
|
|
|
" (but is %u)",
|
|
|
|
TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2016-07-11 22:28:46 +03:00
|
|
|
if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) {
|
2016-07-08 18:01:36 +03:00
|
|
|
error_setg(errp, "TCG only supports phys-bits=%u",
|
|
|
|
TCG_PHYS_ADDR_BITS);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-07-11 22:28:46 +03:00
|
|
|
/* 0 means it was not explicitly set by the user (or by machine
|
|
|
|
* compat_props or by the host code above). In this case, the default
|
|
|
|
* is the value used by TCG (40).
|
|
|
|
*/
|
|
|
|
if (cpu->phys_bits == 0) {
|
|
|
|
cpu->phys_bits = TCG_PHYS_ADDR_BITS;
|
|
|
|
}
|
2016-07-08 18:01:36 +03:00
|
|
|
} else {
|
|
|
|
/* For 32 bit systems don't use the user set value, but keep
|
|
|
|
* phys_bits consistent with what we tell the guest.
|
|
|
|
*/
|
|
|
|
if (cpu->phys_bits != 0) {
|
|
|
|
error_setg(errp, "phys-bits is not user-configurable in 32 bit");
|
|
|
|
return;
|
|
|
|
}
|
2014-04-30 20:48:39 +04:00
|
|
|
|
2016-07-08 18:01:36 +03:00
|
|
|
if (env->features[FEAT_1_EDX] & CPUID_PSE36) {
|
|
|
|
cpu->phys_bits = 36;
|
|
|
|
} else {
|
|
|
|
cpu->phys_bits = 32;
|
|
|
|
}
|
|
|
|
}
|
2016-10-20 14:26:03 +03:00
|
|
|
cpu_exec_realizefn(cs, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2015-02-13 04:04:50 +03:00
|
|
|
|
2015-02-13 03:57:44 +03:00
|
|
|
if (tcg_enabled()) {
|
|
|
|
tcg_x86_init();
|
|
|
|
}
|
|
|
|
|
2012-07-23 17:22:28 +04:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
|
2012-10-14 00:35:39 +04:00
|
|
|
|
2013-04-22 23:00:15 +04:00
|
|
|
if (cpu->env.features[FEAT_1_EDX] & CPUID_APIC || smp_cpus > 1) {
|
2013-04-05 18:36:54 +04:00
|
|
|
x86_cpu_apic_create(cpu, &local_err);
|
2013-01-16 06:41:47 +04:00
|
|
|
if (local_err != NULL) {
|
2013-04-05 18:36:53 +04:00
|
|
|
goto out;
|
2012-10-14 00:35:39 +04:00
|
|
|
}
|
|
|
|
}
|
2012-07-23 17:22:28 +04:00
|
|
|
#endif
|
|
|
|
|
2012-05-10 01:15:32 +04:00
|
|
|
mce_init(cpu);
|
2015-03-31 15:11:09 +03:00
|
|
|
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
if (tcg_enabled()) {
|
2016-01-21 17:15:04 +03:00
|
|
|
AddressSpace *newas = g_new(AddressSpace, 1);
|
|
|
|
|
2015-03-31 15:12:25 +03:00
|
|
|
cpu->cpu_as_mem = g_new(MemoryRegion, 1);
|
2015-03-31 15:11:09 +03:00
|
|
|
cpu->cpu_as_root = g_new(MemoryRegion, 1);
|
2015-03-31 15:12:25 +03:00
|
|
|
|
|
|
|
/* Outer container... */
|
|
|
|
memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull);
|
2015-03-31 15:11:09 +03:00
|
|
|
memory_region_set_enabled(cpu->cpu_as_root, true);
|
2015-03-31 15:12:25 +03:00
|
|
|
|
|
|
|
/* ... with two regions inside: normal system memory with low
|
|
|
|
* priority, and...
|
|
|
|
*/
|
|
|
|
memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory",
|
|
|
|
get_system_memory(), 0, ~0ull);
|
|
|
|
memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0);
|
|
|
|
memory_region_set_enabled(cpu->cpu_as_mem, true);
|
2016-01-21 17:15:04 +03:00
|
|
|
address_space_init(newas, cpu->cpu_as_root, "CPU");
|
2016-01-21 17:15:04 +03:00
|
|
|
cs->num_ases = 1;
|
2016-01-21 17:15:04 +03:00
|
|
|
cpu_address_space_init(cs, newas, 0);
|
2015-03-31 15:12:25 +03:00
|
|
|
|
|
|
|
/* ... SMRAM with higher priority, linked from /machine/smram. */
|
|
|
|
cpu->machine_done.notify = x86_cpu_machine_done;
|
|
|
|
qemu_add_machine_init_done_notifier(&cpu->machine_done);
|
2015-03-31 15:11:09 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-27 04:53:25 +04:00
|
|
|
qemu_init_vcpu(cs);
|
2013-04-05 18:36:54 +04:00
|
|
|
|
2014-10-21 19:00:45 +04:00
|
|
|
/* Only Intel CPUs support hyperthreading. Even though QEMU fixes this
|
|
|
|
* issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX
|
|
|
|
* based on inputs (sockets,cores,threads), it is still better to gives
|
|
|
|
* users a warning.
|
|
|
|
*
|
|
|
|
* NOTE: the following code has to follow qemu_init_vcpu(). Otherwise
|
|
|
|
* cs->nr_threads hasn't be populated yet and the checking is incorrect.
|
|
|
|
*/
|
|
|
|
if (!IS_INTEL_CPU(env) && cs->nr_threads > 1 && !ht_warned) {
|
|
|
|
error_report("AMD CPU doesn't support hyperthreading. Please configure"
|
|
|
|
" -smp options properly.");
|
|
|
|
ht_warned = true;
|
|
|
|
}
|
|
|
|
|
2013-04-05 18:36:54 +04:00
|
|
|
x86_cpu_apic_realize(cpu, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
goto out;
|
|
|
|
}
|
2013-07-27 04:53:25 +04:00
|
|
|
cpu_reset(cs);
|
2013-01-16 06:41:47 +04:00
|
|
|
|
2013-04-05 18:36:53 +04:00
|
|
|
xcc->parent_realize(dev, &local_err);
|
2015-03-31 15:11:09 +03:00
|
|
|
|
2013-04-05 18:36:53 +04:00
|
|
|
out:
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2012-05-10 01:15:32 +04:00
|
|
|
}
|
|
|
|
|
2016-06-24 17:01:02 +03:00
|
|
|
static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(dev);
|
2016-10-20 14:26:04 +03:00
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
|
|
|
|
Error *local_err = NULL;
|
2016-06-24 17:01:02 +03:00
|
|
|
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
cpu_remove_sync(CPU(dev));
|
|
|
|
qemu_unregister_reset(x86_cpu_machine_reset_cb, dev);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (cpu->apic_state) {
|
|
|
|
object_unparent(OBJECT(cpu->apic_state));
|
|
|
|
cpu->apic_state = NULL;
|
|
|
|
}
|
2016-10-20 14:26:04 +03:00
|
|
|
|
|
|
|
xcc->parent_unrealize(dev, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2016-06-24 17:01:02 +03:00
|
|
|
}
|
|
|
|
|
2015-03-23 23:29:32 +03:00
|
|
|
typedef struct BitProperty {
|
2017-03-27 17:48:14 +03:00
|
|
|
FeatureWord w;
|
2015-03-23 23:29:32 +03:00
|
|
|
uint32_t mask;
|
|
|
|
} BitProperty;
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2015-03-23 23:29:32 +03:00
|
|
|
{
|
2017-03-27 17:48:14 +03:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
2015-03-23 23:29:32 +03:00
|
|
|
BitProperty *fp = opaque;
|
2017-03-27 17:48:14 +03:00
|
|
|
uint32_t f = cpu->env.features[fp->w];
|
|
|
|
bool value = (f & fp->mask) == fp->mask;
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_bool(v, name, &value, errp);
|
2015-03-23 23:29:32 +03:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2015-03-23 23:29:32 +03:00
|
|
|
{
|
|
|
|
DeviceState *dev = DEVICE(obj);
|
2017-03-27 17:48:14 +03:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
2015-03-23 23:29:32 +03:00
|
|
|
BitProperty *fp = opaque;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
bool value;
|
|
|
|
|
|
|
|
if (dev->realized) {
|
|
|
|
qdev_prop_set_after_realize(dev, name, errp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_bool(v, name, &value, &local_err);
|
2015-03-23 23:29:32 +03:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value) {
|
2017-03-27 17:48:14 +03:00
|
|
|
cpu->env.features[fp->w] |= fp->mask;
|
2015-03-23 23:29:32 +03:00
|
|
|
} else {
|
2017-03-27 17:48:14 +03:00
|
|
|
cpu->env.features[fp->w] &= ~fp->mask;
|
2015-03-23 23:29:32 +03:00
|
|
|
}
|
2017-03-27 17:48:15 +03:00
|
|
|
cpu->env.user_features[fp->w] |= fp->mask;
|
2015-03-23 23:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpu_release_bit_prop(Object *obj, const char *name,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
BitProperty *prop = opaque;
|
|
|
|
g_free(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Register a boolean property to get/set a single bit in a uint32_t field.
|
|
|
|
*
|
|
|
|
* The same property name can be registered multiple times to make it affect
|
|
|
|
* multiple bits in the same FeatureWord. In that case, the getter will return
|
|
|
|
* true only if all bits are set.
|
|
|
|
*/
|
|
|
|
static void x86_cpu_register_bit_prop(X86CPU *cpu,
|
|
|
|
const char *prop_name,
|
2017-03-27 17:48:14 +03:00
|
|
|
FeatureWord w,
|
2015-03-23 23:29:32 +03:00
|
|
|
int bitnr)
|
|
|
|
{
|
|
|
|
BitProperty *fp;
|
|
|
|
ObjectProperty *op;
|
|
|
|
uint32_t mask = (1UL << bitnr);
|
|
|
|
|
|
|
|
op = object_property_find(OBJECT(cpu), prop_name, NULL);
|
|
|
|
if (op) {
|
|
|
|
fp = op->opaque;
|
2017-03-27 17:48:14 +03:00
|
|
|
assert(fp->w == w);
|
2015-03-23 23:29:32 +03:00
|
|
|
fp->mask |= mask;
|
|
|
|
} else {
|
|
|
|
fp = g_new0(BitProperty, 1);
|
2017-03-27 17:48:14 +03:00
|
|
|
fp->w = w;
|
2015-03-23 23:29:32 +03:00
|
|
|
fp->mask = mask;
|
|
|
|
object_property_add(OBJECT(cpu), prop_name, "bool",
|
|
|
|
x86_cpu_get_bit_prop,
|
|
|
|
x86_cpu_set_bit_prop,
|
|
|
|
x86_cpu_release_bit_prop, fp, &error_abort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void x86_cpu_register_feature_bit_props(X86CPU *cpu,
|
|
|
|
FeatureWord w,
|
|
|
|
int bitnr)
|
|
|
|
{
|
|
|
|
FeatureWordInfo *fi = &feature_word_info[w];
|
2016-09-30 21:49:41 +03:00
|
|
|
const char *name = fi->feat_names[bitnr];
|
2015-03-23 23:29:32 +03:00
|
|
|
|
2016-09-30 21:49:41 +03:00
|
|
|
if (!name) {
|
2015-03-23 23:29:32 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-30 21:49:40 +03:00
|
|
|
/* Property names should use "-" instead of "_".
|
|
|
|
* Old names containing underscores are registered as aliases
|
|
|
|
* using object_property_add_alias()
|
|
|
|
*/
|
2016-09-30 21:49:41 +03:00
|
|
|
assert(!strchr(name, '_'));
|
|
|
|
/* aliases don't use "|" delimiters anymore, they are registered
|
|
|
|
* manually using object_property_add_alias() */
|
|
|
|
assert(!strchr(name, '|'));
|
2017-03-27 17:48:14 +03:00
|
|
|
x86_cpu_register_bit_prop(cpu, name, w, bitnr);
|
2015-03-23 23:29:32 +03:00
|
|
|
}
|
|
|
|
|
2017-02-14 09:25:22 +03:00
|
|
|
static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
GuestPanicInformation *panic_info = NULL;
|
|
|
|
|
|
|
|
if (env->features[FEAT_HYPERV_EDX] & HV_X64_GUEST_CRASH_MSR_AVAILABLE) {
|
|
|
|
panic_info = g_malloc0(sizeof(GuestPanicInformation));
|
|
|
|
|
2017-02-20 21:21:54 +03:00
|
|
|
panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V;
|
2017-02-14 09:25:22 +03:00
|
|
|
|
|
|
|
assert(HV_X64_MSR_CRASH_PARAMS >= 5);
|
2017-02-20 21:21:54 +03:00
|
|
|
panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0];
|
|
|
|
panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1];
|
|
|
|
panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2];
|
|
|
|
panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3];
|
|
|
|
panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4];
|
2017-02-14 09:25:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return panic_info;
|
|
|
|
}
|
|
|
|
static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(obj);
|
|
|
|
GuestPanicInformation *panic_info;
|
|
|
|
|
|
|
|
if (!cs->crash_occurred) {
|
|
|
|
error_setg(errp, "No crash occured");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
panic_info = x86_cpu_get_crash_info(cs);
|
|
|
|
if (panic_info == NULL) {
|
|
|
|
error_setg(errp, "No crash information");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
|
|
|
|
errp);
|
|
|
|
qapi_free_GuestPanicInformation(panic_info);
|
|
|
|
}
|
|
|
|
|
2012-04-03 02:00:17 +04:00
|
|
|
static void x86_cpu_initfn(Object *obj)
|
|
|
|
{
|
2012-12-17 09:18:02 +04:00
|
|
|
CPUState *cs = CPU(obj);
|
2012-04-03 02:00:17 +04:00
|
|
|
X86CPU *cpu = X86_CPU(obj);
|
2014-02-10 14:21:30 +04:00
|
|
|
X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
|
2012-04-03 02:00:17 +04:00
|
|
|
CPUX86State *env = &cpu->env;
|
2015-03-23 23:29:32 +03:00
|
|
|
FeatureWord w;
|
2012-04-03 02:00:17 +04:00
|
|
|
|
2013-01-17 15:13:41 +04:00
|
|
|
cs->env_ptr = env;
|
2012-04-17 14:10:29 +04:00
|
|
|
|
|
|
|
object_property_add(obj, "family", "int",
|
2012-04-17 16:42:22 +04:00
|
|
|
x86_cpuid_version_get_family,
|
2012-04-17 14:10:29 +04:00
|
|
|
x86_cpuid_version_set_family, NULL, NULL, NULL);
|
2012-04-17 14:16:39 +04:00
|
|
|
object_property_add(obj, "model", "int",
|
2012-04-17 16:48:14 +04:00
|
|
|
x86_cpuid_version_get_model,
|
2012-04-17 14:16:39 +04:00
|
|
|
x86_cpuid_version_set_model, NULL, NULL, NULL);
|
2012-04-17 16:14:18 +04:00
|
|
|
object_property_add(obj, "stepping", "int",
|
2012-04-17 16:50:53 +04:00
|
|
|
x86_cpuid_version_get_stepping,
|
2012-04-17 16:14:18 +04:00
|
|
|
x86_cpuid_version_set_stepping, NULL, NULL, NULL);
|
2012-04-17 21:22:58 +04:00
|
|
|
object_property_add_str(obj, "vendor",
|
|
|
|
x86_cpuid_get_vendor,
|
|
|
|
x86_cpuid_set_vendor, NULL);
|
2012-04-17 17:17:27 +04:00
|
|
|
object_property_add_str(obj, "model-id",
|
2012-04-18 01:02:26 +04:00
|
|
|
x86_cpuid_get_model_id,
|
2012-04-17 17:17:27 +04:00
|
|
|
x86_cpuid_set_model_id, NULL);
|
2012-04-18 02:12:23 +04:00
|
|
|
object_property_add(obj, "tsc-frequency", "int",
|
|
|
|
x86_cpuid_get_tsc_freq,
|
|
|
|
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
|
2013-05-06 20:20:07 +04:00
|
|
|
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
|
|
|
|
x86_cpu_get_feature_words,
|
2013-05-06 20:20:09 +04:00
|
|
|
NULL, NULL, (void *)env->features, NULL);
|
|
|
|
object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo",
|
|
|
|
x86_cpu_get_feature_words,
|
|
|
|
NULL, NULL, (void *)cpu->filtered_features, NULL);
|
2012-04-17 14:10:29 +04:00
|
|
|
|
2017-02-14 09:25:22 +03:00
|
|
|
object_property_add(obj, "crash-information", "GuestPanicInformation",
|
|
|
|
x86_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
|
|
|
|
|
2013-06-05 17:18:40 +04:00
|
|
|
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
|
2012-06-19 17:39:46 +04:00
|
|
|
|
2015-03-23 23:29:32 +03:00
|
|
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
|
|
|
int bitnr;
|
|
|
|
|
|
|
|
for (bitnr = 0; bitnr < 32; bitnr++) {
|
|
|
|
x86_cpu_register_feature_bit_props(cpu, w, bitnr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 21:49:41 +03:00
|
|
|
object_property_add_alias(obj, "sse3", obj, "pni", &error_abort);
|
|
|
|
object_property_add_alias(obj, "pclmuldq", obj, "pclmulqdq", &error_abort);
|
|
|
|
object_property_add_alias(obj, "sse4-1", obj, "sse4.1", &error_abort);
|
|
|
|
object_property_add_alias(obj, "sse4-2", obj, "sse4.2", &error_abort);
|
|
|
|
object_property_add_alias(obj, "xd", obj, "nx", &error_abort);
|
|
|
|
object_property_add_alias(obj, "ffxsr", obj, "fxsr-opt", &error_abort);
|
|
|
|
object_property_add_alias(obj, "i64", obj, "lm", &error_abort);
|
|
|
|
|
2016-09-30 21:49:38 +03:00
|
|
|
object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl", &error_abort);
|
|
|
|
object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust", &error_abort);
|
|
|
|
object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt", &error_abort);
|
|
|
|
object_property_add_alias(obj, "lahf_lm", obj, "lahf-lm", &error_abort);
|
|
|
|
object_property_add_alias(obj, "cmp_legacy", obj, "cmp-legacy", &error_abort);
|
|
|
|
object_property_add_alias(obj, "nodeid_msr", obj, "nodeid-msr", &error_abort);
|
|
|
|
object_property_add_alias(obj, "perfctr_core", obj, "perfctr-core", &error_abort);
|
|
|
|
object_property_add_alias(obj, "perfctr_nb", obj, "perfctr-nb", &error_abort);
|
|
|
|
object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay", &error_abort);
|
|
|
|
object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu", &error_abort);
|
|
|
|
object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf", &error_abort);
|
|
|
|
object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time", &error_abort);
|
|
|
|
object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi", &error_abort);
|
|
|
|
object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt", &error_abort);
|
|
|
|
object_property_add_alias(obj, "svm_lock", obj, "svm-lock", &error_abort);
|
|
|
|
object_property_add_alias(obj, "nrip_save", obj, "nrip-save", &error_abort);
|
|
|
|
object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale", &error_abort);
|
|
|
|
object_property_add_alias(obj, "vmcb_clean", obj, "vmcb-clean", &error_abort);
|
|
|
|
object_property_add_alias(obj, "pause_filter", obj, "pause-filter", &error_abort);
|
|
|
|
object_property_add_alias(obj, "sse4_1", obj, "sse4.1", &error_abort);
|
|
|
|
object_property_add_alias(obj, "sse4_2", obj, "sse4.2", &error_abort);
|
|
|
|
|
2017-02-22 21:39:19 +03:00
|
|
|
if (xcc->cpu_def) {
|
|
|
|
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
|
|
|
|
}
|
2012-04-03 02:00:17 +04:00
|
|
|
}
|
|
|
|
|
2013-04-23 12:29:41 +04:00
|
|
|
static int64_t x86_cpu_get_arch_id(CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
2014-12-19 04:20:10 +03:00
|
|
|
return cpu->apic_id;
|
2013-04-23 12:29:41 +04:00
|
|
|
}
|
|
|
|
|
2013-05-28 15:28:38 +04:00
|
|
|
static bool x86_cpu_get_paging_enabled(const CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
|
|
|
return cpu->env.cr[0] & CR0_PG_MASK;
|
|
|
|
}
|
|
|
|
|
2013-06-21 21:09:18 +04:00
|
|
|
static void x86_cpu_set_pc(CPUState *cs, vaddr value)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
|
|
|
cpu->env.eip = value;
|
|
|
|
}
|
|
|
|
|
2013-06-28 21:31:32 +04:00
|
|
|
static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
|
|
|
|
cpu->env.eip = tb->pc - tb->cs_base;
|
|
|
|
}
|
|
|
|
|
2013-08-25 20:53:55 +04:00
|
|
|
static bool x86_cpu_has_work(CPUState *cs)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(cs);
|
|
|
|
CPUX86State *env = &cpu->env;
|
|
|
|
|
2015-09-17 19:23:31 +03:00
|
|
|
return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
|
|
|
|
CPU_INTERRUPT_POLL)) &&
|
2013-08-25 20:53:55 +04:00
|
|
|
(env->eflags & IF_MASK)) ||
|
|
|
|
(cs->interrupt_request & (CPU_INTERRUPT_NMI |
|
|
|
|
CPU_INTERRUPT_INIT |
|
|
|
|
CPU_INTERRUPT_SIPI |
|
2015-05-19 14:46:47 +03:00
|
|
|
CPU_INTERRUPT_MCE)) ||
|
|
|
|
((cs->interrupt_request & CPU_INTERRUPT_SMI) &&
|
|
|
|
!(env->hflags & HF_SMM_MASK));
|
2013-08-25 20:53:55 +04:00
|
|
|
}
|
|
|
|
|
2013-07-27 00:09:36 +04:00
|
|
|
static Property x86_cpu_properties[] = {
|
2016-07-06 09:20:41 +03:00
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
|
|
/* apic_id = 0 by default for *-user, see commit 9886e834 */
|
|
|
|
DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, 0),
|
2016-07-06 09:20:42 +03:00
|
|
|
DEFINE_PROP_INT32("thread-id", X86CPU, thread_id, 0),
|
|
|
|
DEFINE_PROP_INT32("core-id", X86CPU, core_id, 0),
|
|
|
|
DEFINE_PROP_INT32("socket-id", X86CPU, socket_id, 0),
|
2016-07-06 09:20:41 +03:00
|
|
|
#else
|
|
|
|
DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, UNASSIGNED_APIC_ID),
|
2016-07-06 09:20:42 +03:00
|
|
|
DEFINE_PROP_INT32("thread-id", X86CPU, thread_id, -1),
|
|
|
|
DEFINE_PROP_INT32("core-id", X86CPU, core_id, -1),
|
|
|
|
DEFINE_PROP_INT32("socket-id", X86CPU, socket_id, -1),
|
2016-07-06 09:20:41 +03:00
|
|
|
#endif
|
2017-05-10 14:29:47 +03:00
|
|
|
DEFINE_PROP_INT32("node-id", CPUState, numa_node, CPU_UNSET_NUMA_NODE_ID),
|
2013-07-27 00:09:36 +04:00
|
|
|
DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
|
2013-06-04 17:05:25 +04:00
|
|
|
{ .name = "hv-spinlocks", .info = &qdev_prop_spinlocks },
|
2012-08-08 15:52:51 +04:00
|
|
|
DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
|
2012-08-08 15:54:27 +04:00
|
|
|
DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
|
2014-01-23 17:40:49 +04:00
|
|
|
DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
|
2015-09-09 15:41:30 +03:00
|
|
|
DEFINE_PROP_BOOL("hv-crash", X86CPU, hyperv_crash, false),
|
2015-09-16 12:59:42 +03:00
|
|
|
DEFINE_PROP_BOOL("hv-reset", X86CPU, hyperv_reset, false),
|
2015-09-16 12:59:43 +03:00
|
|
|
DEFINE_PROP_BOOL("hv-vpindex", X86CPU, hyperv_vpindex, false),
|
2015-09-16 12:59:44 +03:00
|
|
|
DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false),
|
2015-11-11 13:18:38 +03:00
|
|
|
DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false),
|
2015-11-25 18:21:25 +03:00
|
|
|
DEFINE_PROP_BOOL("hv-stimer", X86CPU, hyperv_stimer, false),
|
2015-08-26 19:25:44 +03:00
|
|
|
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true),
|
2013-06-04 17:13:14 +04:00
|
|
|
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
|
2014-06-02 21:28:50 +04:00
|
|
|
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
|
2016-07-08 18:01:36 +03:00
|
|
|
DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0),
|
2016-07-11 22:28:46 +03:00
|
|
|
DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false),
|
2016-07-08 18:01:38 +03:00
|
|
|
DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true),
|
2016-09-21 19:30:12 +03:00
|
|
|
DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX),
|
|
|
|
DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, UINT32_MAX),
|
|
|
|
DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, UINT32_MAX),
|
|
|
|
DEFINE_PROP_UINT32("min-level", X86CPU, env.cpuid_min_level, 0),
|
|
|
|
DEFINE_PROP_UINT32("min-xlevel", X86CPU, env.cpuid_min_xlevel, 0),
|
|
|
|
DEFINE_PROP_UINT32("min-xlevel2", X86CPU, env.cpuid_min_xlevel2, 0),
|
|
|
|
DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true),
|
2015-10-16 18:38:22 +03:00
|
|
|
DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id),
|
2016-05-12 20:24:26 +03:00
|
|
|
DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true),
|
2016-06-22 09:56:21 +03:00
|
|
|
DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false),
|
target-i386: present virtual L3 cache info for vcpus
Some software algorithms are based on the hardware's cache info, for example,
for x86 linux kernel, when cpu1 want to wakeup a task on cpu2, cpu1 will trigger
a resched IPI and told cpu2 to do the wakeup if they don't share low level
cache. Oppositely, cpu1 will access cpu2's runqueue directly if they share llc.
The relevant linux-kernel code as bellow:
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
......
if (... && !cpus_share_cache(smp_processor_id(), cpu)) {
......
ttwu_queue_remote(p, cpu); /* will trigger RES IPI */
return;
}
......
ttwu_do_activate(rq, p, 0); /* access target's rq directly */
......
}
In real hardware, the cpus on the same socket share L3 cache, so one won't
trigger a resched IPIs when wakeup a task on others. But QEMU doesn't present a
virtual L3 cache info for VM, then the linux guest will trigger lots of RES IPIs
under some workloads even if the virtual cpus belongs to the same virtual socket.
For KVM, there will be lots of vmexit due to guest send IPIs.
The workload is a SAP HANA's testsuite, we run it one round(about 40 minuates)
and observe the (Suse11sp3)Guest's amounts of RES IPIs which triggering during
the period:
No-L3 With-L3(applied this patch)
cpu0: 363890 44582
cpu1: 373405 43109
cpu2: 340783 43797
cpu3: 333854 43409
cpu4: 327170 40038
cpu5: 325491 39922
cpu6: 319129 42391
cpu7: 306480 41035
cpu8: 161139 32188
cpu9: 164649 31024
cpu10: 149823 30398
cpu11: 149823 32455
cpu12: 164830 35143
cpu13: 172269 35805
cpu14: 179979 33898
cpu15: 194505 32754
avg: 268963.6 40129.8
The VM's topology is "1*socket 8*cores 2*threads".
After present virtual L3 cache info for VM, the amounts of RES IPIs in guest
reduce 85%.
For KVM, vcpus send IPIs will cause vmexit which is expensive, so it can cause
severe performance degradation. We had tested the overall system performance if
vcpus actually run on sparate physical socket. With L3 cache, the performance
improves 7.2%~33.1%(avg:15.7%).
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-07 08:21:13 +03:00
|
|
|
DEFINE_PROP_BOOL("l3-cache", X86CPU, enable_l3_cache, true),
|
2017-02-23 16:34:41 +03:00
|
|
|
DEFINE_PROP_BOOL("kvm-no-smi-migration", X86CPU, kvm_no_smi_migration,
|
|
|
|
false),
|
2017-01-20 17:11:36 +03:00
|
|
|
DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true),
|
2013-07-27 00:09:36 +04:00
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2012-04-03 01:20:08 +04:00
|
|
|
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
|
|
|
CPUClass *cc = CPU_CLASS(oc);
|
2013-01-16 06:41:47 +04:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
|
|
|
|
|
|
xcc->parent_realize = dc->realize;
|
2016-10-20 14:26:04 +03:00
|
|
|
xcc->parent_unrealize = dc->unrealize;
|
2013-01-16 06:41:47 +04:00
|
|
|
dc->realize = x86_cpu_realizefn;
|
2016-06-24 17:01:02 +03:00
|
|
|
dc->unrealize = x86_cpu_unrealizefn;
|
2013-07-27 00:09:36 +04:00
|
|
|
dc->props = x86_cpu_properties;
|
2012-04-03 01:20:08 +04:00
|
|
|
|
|
|
|
xcc->parent_reset = cc->reset;
|
|
|
|
cc->reset = x86_cpu_reset;
|
2013-06-16 09:49:48 +04:00
|
|
|
cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP;
|
2013-02-02 16:38:08 +04:00
|
|
|
|
2014-02-11 01:02:44 +04:00
|
|
|
cc->class_by_name = x86_cpu_class_by_name;
|
2014-03-04 02:19:19 +04:00
|
|
|
cc->parse_features = x86_cpu_parse_featurestr;
|
2013-08-25 20:53:55 +04:00
|
|
|
cc->has_work = x86_cpu_has_work;
|
2013-02-02 13:57:51 +04:00
|
|
|
cc->do_interrupt = x86_cpu_do_interrupt;
|
2014-09-13 20:45:33 +04:00
|
|
|
cc->cpu_exec_interrupt = x86_cpu_exec_interrupt;
|
2013-05-27 03:33:50 +04:00
|
|
|
cc->dump_state = x86_cpu_dump_state;
|
2017-02-14 09:25:23 +03:00
|
|
|
cc->get_crash_info = x86_cpu_get_crash_info;
|
2013-06-21 21:09:18 +04:00
|
|
|
cc->set_pc = x86_cpu_set_pc;
|
2013-06-28 21:31:32 +04:00
|
|
|
cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
|
2013-06-29 06:18:45 +04:00
|
|
|
cc->gdb_read_register = x86_cpu_gdb_read_register;
|
|
|
|
cc->gdb_write_register = x86_cpu_gdb_write_register;
|
2013-05-28 15:28:38 +04:00
|
|
|
cc->get_arch_id = x86_cpu_get_arch_id;
|
|
|
|
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
|
2013-08-26 05:01:33 +04:00
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
|
|
cc->handle_mmu_fault = x86_cpu_handle_mmu_fault;
|
|
|
|
#else
|
2013-05-28 15:52:01 +04:00
|
|
|
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
|
2013-06-29 20:55:54 +04:00
|
|
|
cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
|
2013-04-19 18:45:06 +04:00
|
|
|
cc->write_elf64_note = x86_cpu_write_elf64_note;
|
|
|
|
cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote;
|
|
|
|
cc->write_elf32_note = x86_cpu_write_elf32_note;
|
|
|
|
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
|
2013-06-29 20:55:54 +04:00
|
|
|
cc->vmsd = &vmstate_x86_cpu;
|
2013-04-19 18:45:06 +04:00
|
|
|
#endif
|
2016-12-28 19:34:02 +03:00
|
|
|
cc->gdb_arch_name = x86_gdb_arch_name;
|
|
|
|
#ifdef TARGET_X86_64
|
|
|
|
cc->gdb_core_xml_file = "i386-64bit-core.xml";
|
|
|
|
cc->gdb_num_core_regs = 40;
|
|
|
|
#else
|
|
|
|
cc->gdb_core_xml_file = "i386-32bit-core.xml";
|
|
|
|
cc->gdb_num_core_regs = 32;
|
|
|
|
#endif
|
2014-09-12 17:06:48 +04:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
cc->debug_excp_handler = breakpoint_handler;
|
|
|
|
#endif
|
2014-09-13 20:45:14 +04:00
|
|
|
cc->cpu_exec_enter = x86_cpu_exec_enter;
|
|
|
|
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
qdev: Protect device-list-properties against broken devices
Several devices don't survive object_unref(object_new(T)): they crash
or hang during cleanup, or they leave dangling pointers behind.
This breaks at least device-list-properties, because
qmp_device_list_properties() needs to create a device to find its
properties. Broken in commit f4eb32b "qmp: show QOM properties in
device-list-properties", v2.1. Example reproducer:
$ qemu-system-aarch64 -nodefaults -display none -machine none -S -qmp stdio
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 4, "major": 2}, "package": ""}, "capabilities": []}}
{ "execute": "qmp_capabilities" }
{"return": {}}
{ "execute": "device-list-properties", "arguments": { "typename": "pxa2xx-pcmcia" } }
qemu-system-aarch64: /home/armbru/work/qemu/memory.c:1307: memory_region_finalize: Assertion `((&mr->subregions)->tqh_first == ((void *)0))' failed.
Aborted (core dumped)
[Exit 134 (SIGABRT)]
Unfortunately, I can't fix the problems in these devices right now.
Instead, add DeviceClass member cannot_destroy_with_object_finalize_yet
to mark them:
* Hang during cleanup (didn't debug, so I can't say why):
"realview_pci", "versatile_pci".
* Dangling pointer in cpus: most CPUs, plus "allwinner-a10", "digic",
"fsl,imx25", "fsl,imx31", "xlnx,zynqmp", because they create such
CPUs
* Assert kvm_enabled(): "host-x86_64-cpu", host-i386-cpu",
"host-powerpc64-cpu", "host-embedded-powerpc-cpu",
"host-powerpc-cpu" (the powerpc ones can't currently reach the
assertion, because the CPUs are only registered when KVM is enabled,
but the assertion is arguably in the wrong place all the same)
Make qmp_device_list_properties() fail cleanly when the device is so
marked. This improves device-list-properties from "crashes, hangs or
leaves dangling pointers behind" to "fails". Not a complete fix, just
a better-than-nothing work-around. In the above reproducer,
device-list-properties now fails with "Can't list properties of device
'pxa2xx-pcmcia'".
This also protects -device FOO,help, which uses the same machinery
since commit ef52358 "qdev-monitor: include QOM properties in -device
FOO, help output", v2.2. Example reproducer:
$ qemu-system-aarch64 -machine none -device pxa2xx-pcmcia,help
Before:
qemu-system-aarch64: .../memory.c:1307: memory_region_finalize: Assertion `((&mr->subregions)->tqh_first == ((void *)0))' failed.
After:
Can't list properties of device 'pxa2xx-pcmcia'
Cc: "Andreas Färber" <afaerber@suse.de>
Cc: "Edgar E. Iglesias" <edgar.iglesias@gmail.com>
Cc: Alexander Graf <agraf@suse.de>
Cc: Anthony Green <green@moxielogic.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Cc: Blue Swirl <blauwirbel@gmail.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Guan Xuetao <gxt@mprc.pku.edu.cn>
Cc: Jia Liu <proljc@gmail.com>
Cc: Leon Alrae <leon.alrae@imgtec.com>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Walle <michael@walle.cc>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Richard Henderson <rth@twiddle.net>
Cc: qemu-ppc@nongnu.org
Cc: qemu-stable@nongnu.org
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Message-Id: <1443689999-12182-10-git-send-email-armbru@redhat.com>
2015-10-01 11:59:58 +03:00
|
|
|
|
2017-05-03 23:35:44 +03:00
|
|
|
dc->user_creatable = true;
|
2012-04-03 01:20:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo x86_cpu_type_info = {
|
|
|
|
.name = TYPE_X86_CPU,
|
|
|
|
.parent = TYPE_CPU,
|
|
|
|
.instance_size = sizeof(X86CPU),
|
2012-04-03 02:00:17 +04:00
|
|
|
.instance_init = x86_cpu_initfn,
|
2014-02-10 14:21:30 +04:00
|
|
|
.abstract = true,
|
2012-04-03 01:20:08 +04:00
|
|
|
.class_size = sizeof(X86CPUClass),
|
|
|
|
.class_init = x86_cpu_common_class_init,
|
|
|
|
};
|
|
|
|
|
i386: Define static "base" CPU model
The query-cpu-model-expand QMP command needs at least one static
model, to allow the "static" expansion mode to be implemented.
Instead of defining static versions of every CPU model, define a
"base" CPU model that has absolutely no feature flag enabled.
Despite having no CPUID data set at all, "-cpu base" is even a
functional CPU:
* It can boot a Slackware Linux 1.01 image with a Linux 0.99.12
kernel[1].
* It is even possible to boot[2] a modern Fedora x86_64 guest by
manually enabling the following CPU features:
-cpu base,+lm,+msr,+pae,+fpu,+cx8,+cmov,+sse,+sse2,+fxsr
[1] http://www.qemu-advent-calendar.org/2014/#day-1
[2] This is what can be seen in the guest:
[root@localhost ~]# cat /proc/cpuinfo
processor : 0
vendor_id : unknown
cpu family : 0
model : 0
model name : 00/00
stepping : 0
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu msr pae cx8 cmov fxsr sse sse2 lm nopl
bugs :
bogomips : 5832.70
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
[root@localhost ~]# x86info -v -a
x86info v1.30. Dave Jones 2001-2011
Feedback to <davej@redhat.com>.
No TSC, MHz calculation cannot be performed.
Unknown vendor (0)
MP Table:
Family: 0 Model: 0 Stepping: 0
CPU Model (x86info's best guess):
eax in: 0x00000000, eax = 00000001 ebx = 00000000 ecx = 00000000 edx = 00000000
eax in: 0x00000001, eax = 00000000 ebx = 00000800 ecx = 00000000 edx = 07008161
eax in: 0x80000000, eax = 80000001 ebx = 00000000 ecx = 00000000 edx = 00000000
eax in: 0x80000001, eax = 00000000 ebx = 00000000 ecx = 00000000 edx = 20000000
Feature flags:
fpu Onboard FPU
msr Model-Specific Registers
pae Physical Address Extensions
cx8 CMPXCHG8 instruction
cmov CMOV instruction
fxsr FXSAVE and FXRSTOR instructions
sse SSE support
sse2 SSE2 support
Long NOPs supported: yes
Address sizes : 0 bits physical, 0 bits virtual
0MHz processor (estimate).
running at an estimated 0MHz
[root@localhost ~]#
Message-Id: <20170222190029.17243-2-ehabkost@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-02-22 22:00:27 +03:00
|
|
|
|
|
|
|
/* "base" CPU model, used by query-cpu-model-expansion */
|
|
|
|
static void x86_cpu_base_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
X86CPUClass *xcc = X86_CPU_CLASS(oc);
|
|
|
|
|
|
|
|
xcc->static_model = true;
|
|
|
|
xcc->migration_safe = true;
|
|
|
|
xcc->model_description = "base CPU model type with no features enabled";
|
|
|
|
xcc->ordering = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo x86_base_cpu_type_info = {
|
|
|
|
.name = X86_CPU_TYPE_NAME("base"),
|
|
|
|
.parent = TYPE_X86_CPU,
|
|
|
|
.class_init = x86_cpu_base_class_init,
|
|
|
|
};
|
|
|
|
|
2012-04-03 01:20:08 +04:00
|
|
|
static void x86_cpu_register_types(void)
|
|
|
|
{
|
2014-02-10 14:21:30 +04:00
|
|
|
int i;
|
|
|
|
|
2012-04-03 01:20:08 +04:00
|
|
|
type_register_static(&x86_cpu_type_info);
|
2014-02-10 14:21:30 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
|
|
|
|
x86_register_cpudef_type(&builtin_x86_defs[i]);
|
|
|
|
}
|
2017-02-22 21:39:17 +03:00
|
|
|
type_register_static(&max_x86_cpu_type_info);
|
i386: Define static "base" CPU model
The query-cpu-model-expand QMP command needs at least one static
model, to allow the "static" expansion mode to be implemented.
Instead of defining static versions of every CPU model, define a
"base" CPU model that has absolutely no feature flag enabled.
Despite having no CPUID data set at all, "-cpu base" is even a
functional CPU:
* It can boot a Slackware Linux 1.01 image with a Linux 0.99.12
kernel[1].
* It is even possible to boot[2] a modern Fedora x86_64 guest by
manually enabling the following CPU features:
-cpu base,+lm,+msr,+pae,+fpu,+cx8,+cmov,+sse,+sse2,+fxsr
[1] http://www.qemu-advent-calendar.org/2014/#day-1
[2] This is what can be seen in the guest:
[root@localhost ~]# cat /proc/cpuinfo
processor : 0
vendor_id : unknown
cpu family : 0
model : 0
model name : 00/00
stepping : 0
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu msr pae cx8 cmov fxsr sse sse2 lm nopl
bugs :
bogomips : 5832.70
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
[root@localhost ~]# x86info -v -a
x86info v1.30. Dave Jones 2001-2011
Feedback to <davej@redhat.com>.
No TSC, MHz calculation cannot be performed.
Unknown vendor (0)
MP Table:
Family: 0 Model: 0 Stepping: 0
CPU Model (x86info's best guess):
eax in: 0x00000000, eax = 00000001 ebx = 00000000 ecx = 00000000 edx = 00000000
eax in: 0x00000001, eax = 00000000 ebx = 00000800 ecx = 00000000 edx = 07008161
eax in: 0x80000000, eax = 80000001 ebx = 00000000 ecx = 00000000 edx = 00000000
eax in: 0x80000001, eax = 00000000 ebx = 00000000 ecx = 00000000 edx = 20000000
Feature flags:
fpu Onboard FPU
msr Model-Specific Registers
pae Physical Address Extensions
cx8 CMPXCHG8 instruction
cmov CMOV instruction
fxsr FXSAVE and FXRSTOR instructions
sse SSE support
sse2 SSE2 support
Long NOPs supported: yes
Address sizes : 0 bits physical, 0 bits virtual
0MHz processor (estimate).
running at an estimated 0MHz
[root@localhost ~]#
Message-Id: <20170222190029.17243-2-ehabkost@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-02-22 22:00:27 +03:00
|
|
|
type_register_static(&x86_base_cpu_type_info);
|
2014-02-10 14:21:30 +04:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
type_register_static(&host_x86_cpu_type_info);
|
|
|
|
#endif
|
2012-04-03 01:20:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
type_init(x86_cpu_register_types)
|