mirror of https://gitee.com/openkylin/qemu.git
x86 queue, 2016-07-20
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJXj5O6AAoJECgHk2+YTcWmxR4P/ihirI3Ze+QrL1B5NbslzLR4 BFZ+JJt224GLAXdOFu75cLj4t/sNHXzcOL48xVXYPJtSYztq82BpiRopHbH3uaaA Ta9gyu1cFsg8kSDxC5Ij6229r0hYt989LCPaUSlFgJb8PPmLbPbXH55JBFac7PDD CYSg/ogCth7CUBiDG7CRlZGHETWAMHQkMjQGV+PMMT0sUeNhKmYTfTVNwUBh4Ogh BBvTv0oXO8rFVZHWrlaU1NT9fSsLEsQLLokBwi/+SEa5i4wThEfTPw/dnivsMyIT SYaleap6tkU3FD6MmoMtg/alKjjPX5oBriS+KaZQahGqdel9HviCniMvrH2u5YZJ wNwL1U9iAPuW6DgKTeRaptJcidbaEKv8ji9RxtGE3dtxUnOSXGYAOPKts7W7tFLr KsMs4t18LnAFlJIThpYrk0UYkPG3Si8QKaoXYKEASQcfU+IQyxIWmJufCteQM9rV wxn04sshqdhCMzP1L3L/zWImRL+w3mEk3oDwi03ayzIBg9n5w8RY6cqL/3pwYgQS HEF0xNCAItwqCED36z5o6JYwTM30own/IOuxC5I8+rUf6Fajjnxa0r98bLu829E6 kPuoLH0AX0tRKDU5onz002PS4JgP230Fp+8YCgpiNxj9tmqPxH3eGYOI3UASKLmK PoDnk5Lmy5zP9BpmzERt =hLqT -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ehabkost/tags/x86-pull-request' into staging x86 queue, 2016-07-20 # gpg: Signature made Wed 20 Jul 2016 16:07:38 BST # gpg: using RSA key 0x2807936F984DC5A6 # gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" # Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF D1AA 2807 936F 984D C5A6 * remotes/ehabkost/tags/x86-pull-request: (28 commits) pc: Make device_del CPU work for x86 CPUs target-i386: Add x86_cpu_unrealizefn() apic: Use apic_id as apic's migration instance_id (kvm)apic: Add unrealize callbacks apic: kvm-apic: Fix crash due to access to freed memory region apic: Drop APICCommonState.idx and use APIC ID as index in local_apics[] apic: move MAX_APICS check to 'apic' class pc: Implement query-hotpluggable-cpus callback pc: cpu: Allow device_add to be used with x86 cpu pc: Enforce adding CPUs contiguously and removing them in opposite order pc: Forbid BSP removal pc: Register created initial and hotpluged CPUs in one place pc_cpu_plug() pc: Delay setting number of boot CPUs to machine_done time pc: Set APIC ID based on socket/core/thread ids if it's not been set yet target-i386: Fix apic object leak when CPU is deleted target-i386: cpu: Do not ignore error and fix apic parent target-i386: Add support for UMIP and RDPID CPUID bits target-i386: Add socket/core/thread properties to X86CPU target-i386: Replace custom apic-id setter/getter with static property pc: cpu: Consolidate apic-id validity checks in pc_cpu_pre_plug() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e66b05e9ca
|
@ -184,19 +184,24 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
APICCommonState *s = APIC_COMMON(dev);
|
APICCommonState *s = APIC_COMMON(dev);
|
||||||
|
|
||||||
memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi",
|
memory_region_init_io(&s->io_memory, OBJECT(s), &kvm_apic_io_ops, s,
|
||||||
APIC_SPACE_SIZE);
|
"kvm-apic-msi", APIC_SPACE_SIZE);
|
||||||
|
|
||||||
if (kvm_has_gsi_routing()) {
|
if (kvm_has_gsi_routing()) {
|
||||||
msi_nonbroken = true;
|
msi_nonbroken = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kvm_apic_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static void kvm_apic_class_init(ObjectClass *klass, void *data)
|
static void kvm_apic_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
APICCommonClass *k = APIC_COMMON_CLASS(klass);
|
APICCommonClass *k = APIC_COMMON_CLASS(klass);
|
||||||
|
|
||||||
k->realize = kvm_apic_realize;
|
k->realize = kvm_apic_realize;
|
||||||
|
k->unrealize = kvm_apic_unrealize;
|
||||||
k->reset = kvm_apic_reset;
|
k->reset = kvm_apic_reset;
|
||||||
k->set_base = kvm_apic_set_base;
|
k->set_base = kvm_apic_set_base;
|
||||||
k->set_tpr = kvm_apic_set_tpr;
|
k->set_tpr = kvm_apic_set_tpr;
|
||||||
|
|
279
hw/i386/pc.c
279
hw/i386/pc.c
|
@ -471,9 +471,6 @@ void pc_cmos_init(PCMachineState *pcms,
|
||||||
rtc_set_memory(s, 0x5c, val >> 8);
|
rtc_set_memory(s, 0x5c, val >> 8);
|
||||||
rtc_set_memory(s, 0x5d, val >> 16);
|
rtc_set_memory(s, 0x5d, val >> 16);
|
||||||
|
|
||||||
/* set the number of CPU */
|
|
||||||
rtc_set_memory(s, 0x5f, smp_cpus - 1);
|
|
||||||
|
|
||||||
object_property_add_link(OBJECT(pcms), "rtc_state",
|
object_property_add_link(OBJECT(pcms), "rtc_state",
|
||||||
TYPE_ISA_DEVICE,
|
TYPE_ISA_DEVICE,
|
||||||
(Object **)&pcms->rtc,
|
(Object **)&pcms->rtc,
|
||||||
|
@ -1090,6 +1087,17 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pc_present_cpus_count(PCMachineState *pcms)
|
||||||
|
{
|
||||||
|
int i, boot_cpus = 0;
|
||||||
|
for (i = 0; i < pcms->possible_cpus->len; i++) {
|
||||||
|
if (pcms->possible_cpus->cpus[i].cpu) {
|
||||||
|
boot_cpus++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boot_cpus;
|
||||||
|
}
|
||||||
|
|
||||||
static X86CPU *pc_new_cpu(const char *typename, int64_t apic_id,
|
static X86CPU *pc_new_cpu(const char *typename, int64_t apic_id,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -1122,18 +1130,6 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_exists(apic_id)) {
|
|
||||||
error_setg(errp, "Unable to add CPU: %" PRIi64
|
|
||||||
", it already exists", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id >= max_cpus) {
|
|
||||||
error_setg(errp, "Unable to add CPU: %" PRIi64
|
|
||||||
", max allowed: %d", id, max_cpus - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) {
|
if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) {
|
||||||
error_setg(errp, "Unable to add CPU: %" PRIi64
|
error_setg(errp, "Unable to add CPU: %" PRIi64
|
||||||
", resulting APIC ID (%" PRIi64 ") is too large",
|
", resulting APIC ID (%" PRIi64 ") is too large",
|
||||||
|
@ -1208,7 +1204,6 @@ void pc_cpus_init(PCMachineState *pcms)
|
||||||
if (i < smp_cpus) {
|
if (i < smp_cpus) {
|
||||||
cpu = pc_new_cpu(typename, x86_cpu_apic_id_from_index(i),
|
cpu = pc_new_cpu(typename, x86_cpu_apic_id_from_index(i),
|
||||||
&error_fatal);
|
&error_fatal);
|
||||||
pcms->possible_cpus->cpus[i].cpu = CPU(cpu);
|
|
||||||
object_unref(OBJECT(cpu));
|
object_unref(OBJECT(cpu));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1252,6 +1247,9 @@ void pc_machine_done(Notifier *notifier, void *data)
|
||||||
PCMachineState, machine_done);
|
PCMachineState, machine_done);
|
||||||
PCIBus *bus = pcms->bus;
|
PCIBus *bus = pcms->bus;
|
||||||
|
|
||||||
|
/* set the number of CPUs */
|
||||||
|
rtc_set_memory(pcms->rtc, 0x5f, pc_present_cpus_count(pcms) - 1);
|
||||||
|
|
||||||
if (bus) {
|
if (bus) {
|
||||||
int extra_hosts = 0;
|
int extra_hosts = 0;
|
||||||
|
|
||||||
|
@ -1756,39 +1754,48 @@ static int pc_apic_cmp(const void *a, const void *b)
|
||||||
return apic_a->arch_id - apic_b->arch_id;
|
return apic_a->arch_id - apic_b->arch_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
|
||||||
|
* in pcms->possible_cpus->cpus, if pcms->possible_cpus->cpus has no
|
||||||
|
* entry correponding to CPU's apic_id returns NULL.
|
||||||
|
*/
|
||||||
|
static CPUArchId *pc_find_cpu_slot(PCMachineState *pcms, CPUState *cpu,
|
||||||
|
int *idx)
|
||||||
|
{
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
CPUArchId apic_id, *found_cpu;
|
||||||
|
|
||||||
|
apic_id.arch_id = cc->get_arch_id(CPU(cpu));
|
||||||
|
found_cpu = bsearch(&apic_id, pcms->possible_cpus->cpus,
|
||||||
|
pcms->possible_cpus->len, sizeof(*pcms->possible_cpus->cpus),
|
||||||
|
pc_apic_cmp);
|
||||||
|
if (found_cpu && idx) {
|
||||||
|
*idx = found_cpu - pcms->possible_cpus->cpus;
|
||||||
|
}
|
||||||
|
return found_cpu;
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_cpu_plug(HotplugHandler *hotplug_dev,
|
static void pc_cpu_plug(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
CPUClass *cc = CPU_GET_CLASS(dev);
|
CPUArchId *found_cpu;
|
||||||
CPUArchId apic_id, *found_cpu;
|
|
||||||
HotplugHandlerClass *hhc;
|
HotplugHandlerClass *hhc;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||||
|
|
||||||
if (!dev->hotplugged) {
|
if (pcms->acpi_dev) {
|
||||||
goto out;
|
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
||||||
|
hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pcms->acpi_dev) {
|
if (dev->hotplugged) {
|
||||||
error_setg(&local_err,
|
/* increment the number of CPUs */
|
||||||
"cpu hotplug is not enabled: missing acpi device");
|
rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1);
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL);
|
||||||
hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* increment the number of CPUs */
|
|
||||||
rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1);
|
|
||||||
|
|
||||||
apic_id.arch_id = cc->get_arch_id(CPU(dev));
|
|
||||||
found_cpu = bsearch(&apic_id, pcms->possible_cpus->cpus,
|
|
||||||
pcms->possible_cpus->len, sizeof(*pcms->possible_cpus->cpus),
|
|
||||||
pc_apic_cmp);
|
|
||||||
assert(found_cpu);
|
|
||||||
found_cpu->cpu = CPU(dev);
|
found_cpu->cpu = CPU(dev);
|
||||||
out:
|
out:
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
@ -1796,10 +1803,35 @@ out:
|
||||||
static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
|
int idx = -1;
|
||||||
HotplugHandlerClass *hhc;
|
HotplugHandlerClass *hhc;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||||
|
|
||||||
|
pc_find_cpu_slot(pcms, CPU(dev), &idx);
|
||||||
|
assert(idx != -1);
|
||||||
|
if (idx == 0) {
|
||||||
|
error_setg(&local_err, "Boot CPU is unpluggable");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < pcms->possible_cpus->len - 1 &&
|
||||||
|
pcms->possible_cpus->cpus[idx + 1].cpu != NULL) {
|
||||||
|
X86CPU *cpu;
|
||||||
|
|
||||||
|
for (idx = pcms->possible_cpus->len - 1;
|
||||||
|
pcms->possible_cpus->cpus[idx].cpu == NULL; idx--) {
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu = X86_CPU(pcms->possible_cpus->cpus[idx].cpu);
|
||||||
|
error_setg(&local_err, "CPU [socket-id: %u, core-id: %u,"
|
||||||
|
" thread-id: %u] should be removed first",
|
||||||
|
cpu->socket_id, cpu->core_id, cpu->thread_id);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
||||||
hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||||
|
|
||||||
|
@ -1815,6 +1847,7 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||||
static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
|
static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
|
CPUArchId *found_cpu;
|
||||||
HotplugHandlerClass *hhc;
|
HotplugHandlerClass *hhc;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||||
|
@ -1826,17 +1859,129 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL);
|
||||||
* TODO: enable unplug once generic CPU remove bits land
|
found_cpu->cpu = NULL;
|
||||||
* for now guest will be able to eject CPU ACPI wise but
|
object_unparent(OBJECT(dev));
|
||||||
* it will come back again on machine reset.
|
|
||||||
*/
|
|
||||||
/* object_unparent(OBJECT(dev)); */
|
|
||||||
|
|
||||||
|
rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) - 1);
|
||||||
out:
|
out:
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
CPUArchId *cpu_slot;
|
||||||
|
X86CPUTopoInfo topo;
|
||||||
|
X86CPU *cpu = X86_CPU(dev);
|
||||||
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||||
|
|
||||||
|
/* if APIC ID is not set, set it based on socket/core/thread properties */
|
||||||
|
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
|
||||||
|
int max_socket = (max_cpus - 1) / smp_threads / smp_cores;
|
||||||
|
|
||||||
|
if (cpu->socket_id < 0) {
|
||||||
|
error_setg(errp, "CPU socket-id is not set");
|
||||||
|
return;
|
||||||
|
} else if (cpu->socket_id > max_socket) {
|
||||||
|
error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
|
||||||
|
cpu->socket_id, max_socket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cpu->core_id < 0) {
|
||||||
|
error_setg(errp, "CPU core-id is not set");
|
||||||
|
return;
|
||||||
|
} else if (cpu->core_id > (smp_cores - 1)) {
|
||||||
|
error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
|
||||||
|
cpu->core_id, smp_cores - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cpu->thread_id < 0) {
|
||||||
|
error_setg(errp, "CPU thread-id is not set");
|
||||||
|
return;
|
||||||
|
} else if (cpu->thread_id > (smp_threads - 1)) {
|
||||||
|
error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
|
||||||
|
cpu->thread_id, smp_threads - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
topo.pkg_id = cpu->socket_id;
|
||||||
|
topo.core_id = cpu->core_id;
|
||||||
|
topo.smt_id = cpu->thread_id;
|
||||||
|
cpu->apic_id = apicid_from_topo_ids(smp_cores, smp_threads, &topo);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_slot = pc_find_cpu_slot(pcms, CPU(dev), &idx);
|
||||||
|
if (!cpu_slot) {
|
||||||
|
x86_topo_ids_from_apicid(cpu->apic_id, smp_cores, smp_threads, &topo);
|
||||||
|
error_setg(errp, "Invalid CPU [socket: %u, core: %u, thread: %u] with"
|
||||||
|
" APIC ID %" PRIu32 ", valid index range 0:%d",
|
||||||
|
topo.pkg_id, topo.core_id, topo.smt_id, cpu->apic_id,
|
||||||
|
pcms->possible_cpus->len - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_slot->cpu) {
|
||||||
|
error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
|
||||||
|
idx, cpu->apic_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx != 0 && pcms->possible_cpus->cpus[idx - 1].cpu == NULL) {
|
||||||
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
||||||
|
|
||||||
|
for (idx = 1; pcms->possible_cpus->cpus[idx].cpu != NULL; idx++) {
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_topo_ids_from_apicid(pcms->possible_cpus->cpus[idx].arch_id,
|
||||||
|
smp_cores, smp_threads, &topo);
|
||||||
|
|
||||||
|
if (!pcmc->legacy_cpu_hotplug) {
|
||||||
|
error_setg(errp, "CPU [socket: %u, core: %u, thread: %u] should be"
|
||||||
|
" added first", topo.pkg_id, topo.core_id, topo.smt_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if 'address' properties socket-id/core-id/thread-id are not set, set them
|
||||||
|
* so that query_hotpluggable_cpus would show correct values
|
||||||
|
*/
|
||||||
|
/* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
|
||||||
|
* once -smp refactoring is complete and there will be CPU private
|
||||||
|
* CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
|
||||||
|
x86_topo_ids_from_apicid(cpu->apic_id, smp_cores, smp_threads, &topo);
|
||||||
|
if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) {
|
||||||
|
error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
|
||||||
|
" 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, topo.pkg_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cpu->socket_id = topo.pkg_id;
|
||||||
|
|
||||||
|
if (cpu->core_id != -1 && cpu->core_id != topo.core_id) {
|
||||||
|
error_setg(errp, "property core-id: %u doesn't match set apic-id:"
|
||||||
|
" 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, topo.core_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cpu->core_id = topo.core_id;
|
||||||
|
|
||||||
|
if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) {
|
||||||
|
error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
|
||||||
|
" 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id, topo.smt_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cpu->thread_id = topo.smt_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||||
|
pc_cpu_pre_plug(hotplug_dev, dev, errp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -2090,6 +2235,50 @@ static CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HotpluggableCPUList *pc_query_hotpluggable_cpus(MachineState *machine)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CPUState *cpu;
|
||||||
|
HotpluggableCPUList *head = NULL;
|
||||||
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
|
const char *cpu_type;
|
||||||
|
|
||||||
|
cpu = pcms->possible_cpus->cpus[0].cpu;
|
||||||
|
assert(cpu); /* BSP is always present */
|
||||||
|
cpu_type = object_class_get_name(OBJECT_CLASS(CPU_GET_CLASS(cpu)));
|
||||||
|
|
||||||
|
for (i = 0; i < pcms->possible_cpus->len; i++) {
|
||||||
|
X86CPUTopoInfo topo;
|
||||||
|
HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
|
||||||
|
HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
|
||||||
|
CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1);
|
||||||
|
const uint32_t apic_id = pcms->possible_cpus->cpus[i].arch_id;
|
||||||
|
|
||||||
|
x86_topo_ids_from_apicid(apic_id, smp_cores, smp_threads, &topo);
|
||||||
|
|
||||||
|
cpu_item->type = g_strdup(cpu_type);
|
||||||
|
cpu_item->vcpus_count = 1;
|
||||||
|
cpu_props->has_socket_id = true;
|
||||||
|
cpu_props->socket_id = topo.pkg_id;
|
||||||
|
cpu_props->has_core_id = true;
|
||||||
|
cpu_props->core_id = topo.core_id;
|
||||||
|
cpu_props->has_thread_id = true;
|
||||||
|
cpu_props->thread_id = topo.smt_id;
|
||||||
|
cpu_item->props = cpu_props;
|
||||||
|
|
||||||
|
cpu = pcms->possible_cpus->cpus[i].cpu;
|
||||||
|
if (cpu) {
|
||||||
|
cpu_item->has_qom_path = true;
|
||||||
|
cpu_item->qom_path = object_get_canonical_path(OBJECT(cpu));
|
||||||
|
}
|
||||||
|
|
||||||
|
list_item->value = cpu_item;
|
||||||
|
list_item->next = head;
|
||||||
|
head = list_item;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
|
static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
|
||||||
{
|
{
|
||||||
/* cpu index isn't used */
|
/* cpu index isn't used */
|
||||||
|
@ -2130,10 +2319,12 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||||
mc->get_hotplug_handler = pc_get_hotpug_handler;
|
mc->get_hotplug_handler = pc_get_hotpug_handler;
|
||||||
mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
|
mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
|
||||||
mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
|
mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
|
||||||
|
mc->query_hotpluggable_cpus = pc_query_hotpluggable_cpus;
|
||||||
mc->default_boot_order = "cad";
|
mc->default_boot_order = "cad";
|
||||||
mc->hot_add_cpu = pc_hot_add_cpu;
|
mc->hot_add_cpu = pc_hot_add_cpu;
|
||||||
mc->max_cpus = 255;
|
mc->max_cpus = 255;
|
||||||
mc->reset = pc_machine_reset;
|
mc->reset = pc_machine_reset;
|
||||||
|
hc->pre_plug = pc_machine_device_pre_plug_cb;
|
||||||
hc->plug = pc_machine_device_plug_cb;
|
hc->plug = pc_machine_device_plug_cb;
|
||||||
hc->unplug_request = pc_machine_device_unplug_request_cb;
|
hc->unplug_request = pc_machine_device_unplug_request_cb;
|
||||||
hc->unplug = pc_machine_device_unplug_cb;
|
hc->unplug = pc_machine_device_unplug_cb;
|
||||||
|
|
|
@ -28,7 +28,9 @@
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "hw/i386/pc.h"
|
#include "hw/i386/pc.h"
|
||||||
#include "hw/i386/apic-msidef.h"
|
#include "hw/i386/apic-msidef.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#define MAX_APICS 255
|
||||||
#define MAX_APIC_WORDS 8
|
#define MAX_APIC_WORDS 8
|
||||||
|
|
||||||
#define SYNC_FROM_VAPIC 0x1
|
#define SYNC_FROM_VAPIC 0x1
|
||||||
|
@ -419,7 +421,7 @@ static int apic_find_dest(uint8_t dest)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (apic && apic->id == dest)
|
if (apic && apic->id == dest)
|
||||||
return dest; /* shortcut in case apic->id == apic->idx */
|
return dest; /* shortcut in case apic->id == local_apics[dest]->id */
|
||||||
|
|
||||||
for (i = 0; i < MAX_APICS; i++) {
|
for (i = 0; i < MAX_APICS; i++) {
|
||||||
apic = local_apics[i];
|
apic = local_apics[i];
|
||||||
|
@ -502,14 +504,14 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
|
memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
|
||||||
apic_set_bit(deliver_bitmask, s->idx);
|
apic_set_bit(deliver_bitmask, s->id);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
|
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
|
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
|
||||||
apic_reset_bit(deliver_bitmask, s->idx);
|
apic_reset_bit(deliver_bitmask, s->id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,20 +872,36 @@ static void apic_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
APICCommonState *s = APIC_COMMON(dev);
|
APICCommonState *s = APIC_COMMON(dev);
|
||||||
|
|
||||||
|
if (s->id >= MAX_APICS) {
|
||||||
|
error_setg(errp, "%s initialization failed. APIC ID %d is invalid",
|
||||||
|
object_get_typename(OBJECT(dev)), s->id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
|
memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
|
||||||
APIC_SPACE_SIZE);
|
APIC_SPACE_SIZE);
|
||||||
|
|
||||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
|
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
|
||||||
local_apics[s->idx] = s;
|
local_apics[s->id] = s;
|
||||||
|
|
||||||
msi_nonbroken = true;
|
msi_nonbroken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void apic_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
APICCommonState *s = APIC_COMMON(dev);
|
||||||
|
|
||||||
|
timer_del(s->timer);
|
||||||
|
timer_free(s->timer);
|
||||||
|
local_apics[s->id] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void apic_class_init(ObjectClass *klass, void *data)
|
static void apic_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
APICCommonClass *k = APIC_COMMON_CLASS(klass);
|
APICCommonClass *k = APIC_COMMON_CLASS(klass);
|
||||||
|
|
||||||
k->realize = apic_realize;
|
k->realize = apic_realize;
|
||||||
|
k->unrealize = apic_unrealize;
|
||||||
k->set_base = apic_set_base;
|
k->set_base = apic_set_base;
|
||||||
k->set_tpr = apic_set_tpr;
|
k->set_tpr = apic_set_tpr;
|
||||||
k->get_tpr = apic_get_tpr;
|
k->get_tpr = apic_get_tpr;
|
||||||
|
|
|
@ -294,19 +294,14 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_apic_common;
|
||||||
|
|
||||||
static void apic_common_realize(DeviceState *dev, Error **errp)
|
static void apic_common_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
APICCommonState *s = APIC_COMMON(dev);
|
APICCommonState *s = APIC_COMMON(dev);
|
||||||
APICCommonClass *info;
|
APICCommonClass *info;
|
||||||
static DeviceState *vapic;
|
static DeviceState *vapic;
|
||||||
static int apic_no;
|
int instance_id = s->id;
|
||||||
|
|
||||||
if (apic_no >= MAX_APICS) {
|
|
||||||
error_setg(errp, "%s initialization failed.",
|
|
||||||
object_get_typename(OBJECT(dev)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s->idx = apic_no++;
|
|
||||||
|
|
||||||
info = APIC_COMMON_GET_CLASS(s);
|
info = APIC_COMMON_GET_CLASS(s);
|
||||||
info->realize(dev, errp);
|
info->realize(dev, errp);
|
||||||
|
@ -321,6 +316,24 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
|
||||||
info->enable_tpr_reporting(s, true);
|
info->enable_tpr_reporting(s, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->legacy_instance_id) {
|
||||||
|
instance_id = -1;
|
||||||
|
}
|
||||||
|
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
|
||||||
|
s, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apic_common_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
APICCommonState *s = APIC_COMMON(dev);
|
||||||
|
APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
|
||||||
|
|
||||||
|
vmstate_unregister(NULL, &vmstate_apic_common, s);
|
||||||
|
info->unrealize(dev, errp);
|
||||||
|
|
||||||
|
if (apic_report_tpr_access && info->enable_tpr_reporting) {
|
||||||
|
info->enable_tpr_reporting(s, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apic_pre_load(void *opaque)
|
static int apic_pre_load(void *opaque)
|
||||||
|
@ -418,6 +431,8 @@ static Property apic_properties_common[] = {
|
||||||
DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
|
DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
|
||||||
DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
|
DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
|
||||||
true),
|
true),
|
||||||
|
DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id,
|
||||||
|
false),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -425,10 +440,10 @@ static void apic_common_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->vmsd = &vmstate_apic_common;
|
|
||||||
dc->reset = apic_reset_common;
|
dc->reset = apic_reset_common;
|
||||||
dc->props = apic_properties_common;
|
dc->props = apic_properties_common;
|
||||||
dc->realize = apic_common_realize;
|
dc->realize = apic_common_realize;
|
||||||
|
dc->unrealize = apic_common_unrealize;
|
||||||
/*
|
/*
|
||||||
* Reason: APIC and CPU need to be wired up by
|
* Reason: APIC and CPU need to be wired up by
|
||||||
* x86_cpu_apic_create()
|
* x86_cpu_apic_create()
|
||||||
|
|
|
@ -121,8 +121,6 @@
|
||||||
#define VAPIC_ENABLE_BIT 0
|
#define VAPIC_ENABLE_BIT 0
|
||||||
#define VAPIC_ENABLE_MASK (1 << VAPIC_ENABLE_BIT)
|
#define VAPIC_ENABLE_MASK (1 << VAPIC_ENABLE_BIT)
|
||||||
|
|
||||||
#define MAX_APICS 255
|
|
||||||
|
|
||||||
typedef struct APICCommonState APICCommonState;
|
typedef struct APICCommonState APICCommonState;
|
||||||
|
|
||||||
#define TYPE_APIC_COMMON "apic-common"
|
#define TYPE_APIC_COMMON "apic-common"
|
||||||
|
@ -138,6 +136,7 @@ typedef struct APICCommonClass
|
||||||
DeviceClass parent_class;
|
DeviceClass parent_class;
|
||||||
|
|
||||||
DeviceRealize realize;
|
DeviceRealize realize;
|
||||||
|
DeviceUnrealize unrealize;
|
||||||
void (*set_base)(APICCommonState *s, uint64_t val);
|
void (*set_base)(APICCommonState *s, uint64_t val);
|
||||||
void (*set_tpr)(APICCommonState *s, uint8_t val);
|
void (*set_tpr)(APICCommonState *s, uint8_t val);
|
||||||
uint8_t (*get_tpr)(APICCommonState *s);
|
uint8_t (*get_tpr)(APICCommonState *s);
|
||||||
|
@ -176,7 +175,6 @@ struct APICCommonState {
|
||||||
uint32_t initial_count;
|
uint32_t initial_count;
|
||||||
int64_t initial_count_load_time;
|
int64_t initial_count_load_time;
|
||||||
int64_t next_time;
|
int64_t next_time;
|
||||||
int idx;
|
|
||||||
QEMUTimer *timer;
|
QEMUTimer *timer;
|
||||||
int64_t timer_expiry;
|
int64_t timer_expiry;
|
||||||
int sipi_vector;
|
int sipi_vector;
|
||||||
|
@ -185,6 +183,7 @@ struct APICCommonState {
|
||||||
uint32_t vapic_control;
|
uint32_t vapic_control;
|
||||||
DeviceState *vapic;
|
DeviceState *vapic;
|
||||||
hwaddr vapic_paddr; /* note: persistence via kvmvapic */
|
hwaddr vapic_paddr; /* note: persistence via kvmvapic */
|
||||||
|
bool legacy_instance_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct VAPICState {
|
typedef struct VAPICState {
|
||||||
|
|
|
@ -377,6 +377,16 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||||
.driver = "vmxnet3",\
|
.driver = "vmxnet3",\
|
||||||
.property = "romfile",\
|
.property = "romfile",\
|
||||||
.value = "",\
|
.value = "",\
|
||||||
|
},\
|
||||||
|
{\
|
||||||
|
.driver = TYPE_X86_CPU,\
|
||||||
|
.property = "fill-mtrr-mask",\
|
||||||
|
.value = "off",\
|
||||||
|
},\
|
||||||
|
{\
|
||||||
|
.driver = "apic",\
|
||||||
|
.property = "legacy-instance-id",\
|
||||||
|
.value = "on",\
|
||||||
},
|
},
|
||||||
|
|
||||||
#define PC_COMPAT_2_5 \
|
#define PC_COMPAT_2_5 \
|
||||||
|
|
|
@ -117,6 +117,21 @@ static inline void x86_topo_ids_from_idx(unsigned nr_cores,
|
||||||
topo->pkg_id = core_index / nr_cores;
|
topo->pkg_id = core_index / nr_cores;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate thread/core/package IDs for a specific topology,
|
||||||
|
* based on APIC ID
|
||||||
|
*/
|
||||||
|
static inline void x86_topo_ids_from_apicid(apic_id_t apicid,
|
||||||
|
unsigned nr_cores,
|
||||||
|
unsigned nr_threads,
|
||||||
|
X86CPUTopoInfo *topo)
|
||||||
|
{
|
||||||
|
topo->smt_id = apicid &
|
||||||
|
~(0xFFFFFFFFUL << apicid_smt_width(nr_cores, nr_threads));
|
||||||
|
topo->core_id = (apicid >> apicid_core_offset(nr_cores, nr_threads)) &
|
||||||
|
~(0xFFFFFFFFUL << apicid_core_width(nr_cores, nr_threads));
|
||||||
|
topo->pkg_id = apicid >> apicid_pkg_offset(nr_cores, nr_threads);
|
||||||
|
}
|
||||||
|
|
||||||
/* Make APIC ID for the CPU 'cpu_index'
|
/* Make APIC ID for the CPU 'cpu_index'
|
||||||
*
|
*
|
||||||
* 'cpu_index' is a sequential, contiguous ID for the CPU.
|
* 'cpu_index' is a sequential, contiguous ID for the CPU.
|
||||||
|
|
|
@ -5026,3 +5026,18 @@ Example for pseries machine type started with
|
||||||
{ "props": { "core-id": 0 }, "type": "POWER8-spapr-cpu-core",
|
{ "props": { "core-id": 0 }, "type": "POWER8-spapr-cpu-core",
|
||||||
"vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
|
"vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
|
||||||
]}'
|
]}'
|
||||||
|
|
||||||
|
Example for pc machine type started with
|
||||||
|
-smp 1,maxcpus=2:
|
||||||
|
-> { "execute": "query-hotpluggable-cpus" }
|
||||||
|
<- {"return": [
|
||||||
|
{
|
||||||
|
"type": "qemu64-x86_64-cpu", "vcpus-count": 1,
|
||||||
|
"props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"qom-path": "/machine/unattached/device[0]",
|
||||||
|
"type": "qemu64-x86_64-cpu", "vcpus-count": 1,
|
||||||
|
"props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
|
|
@ -305,12 +305,12 @@ static const char *cpuid_7_0_ebx_feature_name[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *cpuid_7_0_ecx_feature_name[] = {
|
static const char *cpuid_7_0_ecx_feature_name[] = {
|
||||||
NULL, NULL, NULL, "pku",
|
NULL, NULL, "umip", "pku",
|
||||||
"ospke", NULL, NULL, NULL,
|
"ospke", 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, NULL, NULL,
|
NULL, NULL, "rdpid", NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
};
|
};
|
||||||
|
@ -1893,50 +1893,6 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, const char *name,
|
||||||
cpu->env.tsc_khz = cpu->env.user_tsc_khz = value / 1000;
|
cpu->env.tsc_khz = cpu->env.user_tsc_khz = value / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x86_cpuid_get_apic_id(Object *obj, Visitor *v, const char *name,
|
|
||||||
void *opaque, Error **errp)
|
|
||||||
{
|
|
||||||
X86CPU *cpu = X86_CPU(obj);
|
|
||||||
int64_t value = cpu->apic_id;
|
|
||||||
|
|
||||||
visit_type_int(v, name, &value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, const char *name,
|
|
||||||
void *opaque, Error **errp)
|
|
||||||
{
|
|
||||||
X86CPU *cpu = X86_CPU(obj);
|
|
||||||
DeviceState *dev = DEVICE(obj);
|
|
||||||
const int64_t min = 0;
|
|
||||||
const int64_t max = UINT32_MAX;
|
|
||||||
Error *error = NULL;
|
|
||||||
int64_t value;
|
|
||||||
|
|
||||||
if (dev->realized) {
|
|
||||||
error_setg(errp, "Attempt to set property '%s' on '%s' after "
|
|
||||||
"it was realized", name, object_get_typename(obj));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
visit_type_int(v, name, &value, &error);
|
|
||||||
if (error) {
|
|
||||||
error_propagate(errp, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (value < min || value > max) {
|
|
||||||
error_setg(errp, "Property %s.%s doesn't take value %" PRId64
|
|
||||||
" (minimum: %" PRId64 ", maximum: %" PRId64 ")" ,
|
|
||||||
object_get_typename(obj), name, value, min, max);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((value != cpu->apic_id) && cpu_exists(value)) {
|
|
||||||
error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cpu->apic_id = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generic getter for "feature-words" and "filtered-features" properties */
|
/* Generic getter for "feature-words" and "filtered-features" properties */
|
||||||
static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
|
static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
|
||||||
const char *name, void *opaque,
|
const char *name, void *opaque,
|
||||||
|
@ -2641,17 +2597,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||||
break;
|
break;
|
||||||
case 0x80000008:
|
case 0x80000008:
|
||||||
/* virtual & phys address size in low 2 bytes. */
|
/* virtual & phys address size in low 2 bytes. */
|
||||||
/* XXX: This value must match the one used in the MMU code. */
|
|
||||||
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
||||||
/* 64 bit processor */
|
/* 64 bit processor, 48 bits virtual, configurable
|
||||||
/* XXX: The physical address space is limited to 42 bits in exec.c. */
|
* physical bits.
|
||||||
*eax = 0x00003028; /* 48 bits virtual, 40 bits physical */
|
*/
|
||||||
|
*eax = 0x00003000 + cpu->phys_bits;
|
||||||
} else {
|
} else {
|
||||||
if (env->features[FEAT_1_EDX] & CPUID_PSE36) {
|
*eax = cpu->phys_bits;
|
||||||
*eax = 0x00000024; /* 36 bits physical */
|
|
||||||
} else {
|
|
||||||
*eax = 0x00000020; /* 32 bits physical */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*ebx = 0;
|
*ebx = 0;
|
||||||
*ecx = 0;
|
*ecx = 0;
|
||||||
|
@ -2874,8 +2826,10 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
|
||||||
|
|
||||||
cpu->apic_state = DEVICE(object_new(apic_type));
|
cpu->apic_state = DEVICE(object_new(apic_type));
|
||||||
|
|
||||||
object_property_add_child(OBJECT(cpu), "apic",
|
object_property_add_child(OBJECT(cpu), "lapic",
|
||||||
OBJECT(cpu->apic_state), NULL);
|
OBJECT(cpu->apic_state), &error_abort);
|
||||||
|
object_unref(OBJECT(cpu->apic_state));
|
||||||
|
|
||||||
qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id);
|
qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id);
|
||||||
/* TODO: convert to link<> */
|
/* TODO: convert to link<> */
|
||||||
apic = APIC_COMMON(cpu->apic_state);
|
apic = APIC_COMMON(cpu->apic_state);
|
||||||
|
@ -2926,6 +2880,31 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
|
#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \
|
||||||
(env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
|
(env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
|
||||||
|
@ -2950,7 +2929,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu->apic_id < 0) {
|
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
|
||||||
error_setg(errp, "apic-id property was not initialized properly");
|
error_setg(errp, "apic-id property was not initialized properly");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2993,7 +2972,70 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
& CPUID_EXT2_AMD_ALIASES);
|
& CPUID_EXT2_AMD_ALIASES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
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)) {
|
||||||
|
error_setg(errp, "phys-bits should be between 32 and %u "
|
||||||
|
" (but is %u)",
|
||||||
|
TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cpu->phys_bits && cpu->phys_bits != TCG_PHYS_ADDR_BITS) {
|
||||||
|
error_setg(errp, "TCG only supports phys-bits=%u",
|
||||||
|
TCG_PHYS_ADDR_BITS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->features[FEAT_1_EDX] & CPUID_PSE36) {
|
||||||
|
cpu->phys_bits = 36;
|
||||||
|
} else {
|
||||||
|
cpu->phys_bits = 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
cpu_exec_init(cs, &error_abort);
|
cpu_exec_init(cs, &error_abort);
|
||||||
|
|
||||||
if (tcg_enabled()) {
|
if (tcg_enabled()) {
|
||||||
|
@ -3072,6 +3114,21 @@ out:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
X86CPU *cpu = X86_CPU(dev);
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct BitProperty {
|
typedef struct BitProperty {
|
||||||
uint32_t *ptr;
|
uint32_t *ptr;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
|
@ -3207,9 +3264,6 @@ static void x86_cpu_initfn(Object *obj)
|
||||||
object_property_add(obj, "tsc-frequency", "int",
|
object_property_add(obj, "tsc-frequency", "int",
|
||||||
x86_cpuid_get_tsc_freq,
|
x86_cpuid_get_tsc_freq,
|
||||||
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
|
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
|
||||||
object_property_add(obj, "apic-id", "int",
|
|
||||||
x86_cpuid_get_apic_id,
|
|
||||||
x86_cpuid_set_apic_id, NULL, NULL, NULL);
|
|
||||||
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
|
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
|
||||||
x86_cpu_get_feature_words,
|
x86_cpu_get_feature_words,
|
||||||
NULL, NULL, (void *)env->features, NULL);
|
NULL, NULL, (void *)env->features, NULL);
|
||||||
|
@ -3219,11 +3273,6 @@ static void x86_cpu_initfn(Object *obj)
|
||||||
|
|
||||||
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
|
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
/* Any code creating new X86CPU objects have to set apic-id explicitly */
|
|
||||||
cpu->apic_id = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (w = 0; w < FEATURE_WORDS; w++) {
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||||
int bitnr;
|
int bitnr;
|
||||||
|
|
||||||
|
@ -3280,6 +3329,18 @@ static bool x86_cpu_has_work(CPUState *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property x86_cpu_properties[] = {
|
static Property x86_cpu_properties[] = {
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/* apic_id = 0 by default for *-user, see commit 9886e834 */
|
||||||
|
DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, 0),
|
||||||
|
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),
|
||||||
|
#else
|
||||||
|
DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, UNASSIGNED_APIC_ID),
|
||||||
|
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),
|
||||||
|
#endif
|
||||||
DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
|
DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
|
||||||
{ .name = "hv-spinlocks", .info = &qdev_prop_spinlocks },
|
{ .name = "hv-spinlocks", .info = &qdev_prop_spinlocks },
|
||||||
DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
|
DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
|
||||||
|
@ -3294,6 +3355,9 @@ static Property x86_cpu_properties[] = {
|
||||||
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true),
|
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true),
|
||||||
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
|
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
|
||||||
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
|
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
|
||||||
|
DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0),
|
||||||
|
DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false),
|
||||||
|
DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true),
|
||||||
DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, 0),
|
DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, 0),
|
||||||
DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0),
|
DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0),
|
||||||
DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0),
|
DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0),
|
||||||
|
@ -3311,6 +3375,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
||||||
|
|
||||||
xcc->parent_realize = dc->realize;
|
xcc->parent_realize = dc->realize;
|
||||||
dc->realize = x86_cpu_realizefn;
|
dc->realize = x86_cpu_realizefn;
|
||||||
|
dc->unrealize = x86_cpu_unrealizefn;
|
||||||
dc->props = x86_cpu_properties;
|
dc->props = x86_cpu_properties;
|
||||||
|
|
||||||
xcc->parent_reset = cc->reset;
|
xcc->parent_reset = cc->reset;
|
||||||
|
@ -3347,6 +3412,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
||||||
cc->cpu_exec_enter = x86_cpu_exec_enter;
|
cc->cpu_exec_enter = x86_cpu_exec_enter;
|
||||||
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
||||||
|
|
||||||
|
dc->cannot_instantiate_with_device_add_yet = false;
|
||||||
/*
|
/*
|
||||||
* Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the
|
* Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the
|
||||||
* object in cpus -> dangling pointer after final object_unref().
|
* object in cpus -> dangling pointer after final object_unref().
|
||||||
|
|
|
@ -616,8 +616,10 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
|
||||||
#define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */
|
#define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */
|
||||||
#define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */
|
#define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */
|
||||||
|
|
||||||
|
#define CPUID_7_0_ECX_UMIP (1U << 2)
|
||||||
#define CPUID_7_0_ECX_PKU (1U << 3)
|
#define CPUID_7_0_ECX_PKU (1U << 3)
|
||||||
#define CPUID_7_0_ECX_OSPKE (1U << 4)
|
#define CPUID_7_0_ECX_OSPKE (1U << 4)
|
||||||
|
#define CPUID_7_0_ECX_RDPID (1U << 22)
|
||||||
|
|
||||||
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
|
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
|
||||||
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
||||||
|
@ -845,6 +847,11 @@ typedef struct {
|
||||||
|
|
||||||
#define NB_OPMASK_REGS 8
|
#define NB_OPMASK_REGS 8
|
||||||
|
|
||||||
|
/* CPU can't have 0xFFFFFFFF APIC ID, use that value to distinguish
|
||||||
|
* that APIC ID hasn't been set yet
|
||||||
|
*/
|
||||||
|
#define UNASSIGNED_APIC_ID 0xFFFFFFFF
|
||||||
|
|
||||||
typedef union X86LegacyXSaveArea {
|
typedef union X86LegacyXSaveArea {
|
||||||
struct {
|
struct {
|
||||||
uint16_t fcw;
|
uint16_t fcw;
|
||||||
|
@ -1174,7 +1181,7 @@ struct X86CPU {
|
||||||
bool expose_kvm;
|
bool expose_kvm;
|
||||||
bool migratable;
|
bool migratable;
|
||||||
bool host_features;
|
bool host_features;
|
||||||
int64_t apic_id;
|
uint32_t apic_id;
|
||||||
|
|
||||||
/* if true the CPUID code directly forward host cache leaves to the guest */
|
/* if true the CPUID code directly forward host cache leaves to the guest */
|
||||||
bool cache_info_passthrough;
|
bool cache_info_passthrough;
|
||||||
|
@ -1198,6 +1205,15 @@ struct X86CPU {
|
||||||
/* Compatibility bits for old machine types: */
|
/* Compatibility bits for old machine types: */
|
||||||
bool enable_cpuid_0xb;
|
bool enable_cpuid_0xb;
|
||||||
|
|
||||||
|
/* if true fill the top bits of the MTRR_PHYSMASKn variable range */
|
||||||
|
bool fill_mtrr_mask;
|
||||||
|
|
||||||
|
/* if true override the phys_bits value with a value read from the host */
|
||||||
|
bool host_phys_bits;
|
||||||
|
|
||||||
|
/* Number of physical address bits supported */
|
||||||
|
uint32_t phys_bits;
|
||||||
|
|
||||||
/* in order to simplify APIC support, we leave this pointer to the
|
/* in order to simplify APIC support, we leave this pointer to the
|
||||||
user */
|
user */
|
||||||
struct DeviceState *apic_state;
|
struct DeviceState *apic_state;
|
||||||
|
@ -1205,6 +1221,10 @@ struct X86CPU {
|
||||||
Notifier machine_done;
|
Notifier machine_done;
|
||||||
|
|
||||||
struct kvm_msrs *kvm_msr_buf;
|
struct kvm_msrs *kvm_msr_buf;
|
||||||
|
|
||||||
|
int32_t socket_id;
|
||||||
|
int32_t core_id;
|
||||||
|
int32_t thread_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
|
static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
|
||||||
|
@ -1419,11 +1439,13 @@ uint64_t cpu_get_tsc(CPUX86State *env);
|
||||||
/* XXX: This value should match the one returned by CPUID
|
/* XXX: This value should match the one returned by CPUID
|
||||||
* and in exec.c */
|
* and in exec.c */
|
||||||
# if defined(TARGET_X86_64)
|
# if defined(TARGET_X86_64)
|
||||||
# define PHYS_ADDR_MASK 0xffffffffffLL
|
# define TCG_PHYS_ADDR_BITS 40
|
||||||
# else
|
# else
|
||||||
# define PHYS_ADDR_MASK 0xfffffffffLL
|
# define TCG_PHYS_ADDR_BITS 36
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#define PHYS_ADDR_MASK MAKE_64BIT_MASK(0, TCG_PHYS_ADDR_BITS)
|
||||||
|
|
||||||
#define cpu_init(cpu_model) CPU(cpu_x86_init(cpu_model))
|
#define cpu_init(cpu_model) CPU(cpu_x86_init(cpu_model))
|
||||||
|
|
||||||
#define cpu_signal_handler cpu_x86_signal_handler
|
#define cpu_signal_handler cpu_x86_signal_handler
|
||||||
|
|
|
@ -1716,6 +1716,8 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (has_msr_mtrr) {
|
if (has_msr_mtrr) {
|
||||||
|
uint64_t phys_mask = MAKE_64BIT_MASK(0, cpu->phys_bits);
|
||||||
|
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRdefType, env->mtrr_deftype);
|
kvm_msr_entry_add(cpu, MSR_MTRRdefType, env->mtrr_deftype);
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRfix64K_00000, env->mtrr_fixed[0]);
|
kvm_msr_entry_add(cpu, MSR_MTRRfix64K_00000, env->mtrr_fixed[0]);
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRfix16K_80000, env->mtrr_fixed[1]);
|
kvm_msr_entry_add(cpu, MSR_MTRRfix16K_80000, env->mtrr_fixed[1]);
|
||||||
|
@ -1729,10 +1731,15 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRfix4K_F0000, env->mtrr_fixed[9]);
|
kvm_msr_entry_add(cpu, MSR_MTRRfix4K_F0000, env->mtrr_fixed[9]);
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRfix4K_F8000, env->mtrr_fixed[10]);
|
kvm_msr_entry_add(cpu, MSR_MTRRfix4K_F8000, env->mtrr_fixed[10]);
|
||||||
for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
|
for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
|
||||||
|
/* The CPU GPs if we write to a bit above the physical limit of
|
||||||
|
* the host CPU (and KVM emulates that)
|
||||||
|
*/
|
||||||
|
uint64_t mask = env->mtrr_var[i].mask;
|
||||||
|
mask &= phys_mask;
|
||||||
|
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRphysBase(i),
|
kvm_msr_entry_add(cpu, MSR_MTRRphysBase(i),
|
||||||
env->mtrr_var[i].base);
|
env->mtrr_var[i].base);
|
||||||
kvm_msr_entry_add(cpu, MSR_MTRRphysMask(i),
|
kvm_msr_entry_add(cpu, MSR_MTRRphysMask(i), mask);
|
||||||
env->mtrr_var[i].mask);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1970,6 +1977,7 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
struct kvm_msr_entry *msrs = cpu->kvm_msr_buf->entries;
|
struct kvm_msr_entry *msrs = cpu->kvm_msr_buf->entries;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
uint64_t mtrr_top_bits;
|
||||||
|
|
||||||
kvm_msr_buf_reset(cpu);
|
kvm_msr_buf_reset(cpu);
|
||||||
|
|
||||||
|
@ -2122,6 +2130,30 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(ret == cpu->kvm_msr_buf->nmsrs);
|
assert(ret == cpu->kvm_msr_buf->nmsrs);
|
||||||
|
/*
|
||||||
|
* MTRR masks: Each mask consists of 5 parts
|
||||||
|
* a 10..0: must be zero
|
||||||
|
* b 11 : valid bit
|
||||||
|
* c n-1.12: actual mask bits
|
||||||
|
* d 51..n: reserved must be zero
|
||||||
|
* e 63.52: reserved must be zero
|
||||||
|
*
|
||||||
|
* 'n' is the number of physical bits supported by the CPU and is
|
||||||
|
* apparently always <= 52. We know our 'n' but don't know what
|
||||||
|
* the destinations 'n' is; it might be smaller, in which case
|
||||||
|
* it masks (c) on loading. It might be larger, in which case
|
||||||
|
* we fill 'd' so that d..c is consistent irrespetive of the 'n'
|
||||||
|
* we're migrating to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cpu->fill_mtrr_mask) {
|
||||||
|
QEMU_BUILD_BUG_ON(TARGET_PHYS_ADDR_SPACE_BITS > 52);
|
||||||
|
assert(cpu->phys_bits <= TARGET_PHYS_ADDR_SPACE_BITS);
|
||||||
|
mtrr_top_bits = MAKE_64BIT_MASK(cpu->phys_bits, 52 - cpu->phys_bits);
|
||||||
|
} else {
|
||||||
|
mtrr_top_bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < ret; i++) {
|
for (i = 0; i < ret; i++) {
|
||||||
uint32_t index = msrs[i].index;
|
uint32_t index = msrs[i].index;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
|
@ -2320,7 +2352,8 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||||
break;
|
break;
|
||||||
case MSR_MTRRphysBase(0) ... MSR_MTRRphysMask(MSR_MTRRcap_VCNT - 1):
|
case MSR_MTRRphysBase(0) ... MSR_MTRRphysMask(MSR_MTRRcap_VCNT - 1):
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
env->mtrr_var[MSR_MTRRphysIndex(index)].mask = msrs[i].data;
|
env->mtrr_var[MSR_MTRRphysIndex(index)].mask = msrs[i].data |
|
||||||
|
mtrr_top_bits;
|
||||||
} else {
|
} else {
|
||||||
env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
|
env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue