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);
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi",
 | 
			
		||||
                          APIC_SPACE_SIZE);
 | 
			
		||||
    memory_region_init_io(&s->io_memory, OBJECT(s), &kvm_apic_io_ops, s,
 | 
			
		||||
                          "kvm-apic-msi", APIC_SPACE_SIZE);
 | 
			
		||||
 | 
			
		||||
    if (kvm_has_gsi_routing()) {
 | 
			
		||||
        msi_nonbroken = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void kvm_apic_unrealize(DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void kvm_apic_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    APICCommonClass *k = APIC_COMMON_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    k->realize = kvm_apic_realize;
 | 
			
		||||
    k->unrealize = kvm_apic_unrealize;
 | 
			
		||||
    k->reset = kvm_apic_reset;
 | 
			
		||||
    k->set_base = kvm_apic_set_base;
 | 
			
		||||
    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, 0x5d, val >> 16);
 | 
			
		||||
 | 
			
		||||
    /* set the number of CPU */
 | 
			
		||||
    rtc_set_memory(s, 0x5f, smp_cpus - 1);
 | 
			
		||||
 | 
			
		||||
    object_property_add_link(OBJECT(pcms), "rtc_state",
 | 
			
		||||
                             TYPE_ISA_DEVICE,
 | 
			
		||||
                             (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,
 | 
			
		||||
                          Error **errp)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1122,18 +1130,6 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
 | 
			
		|||
        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) {
 | 
			
		||||
        error_setg(errp, "Unable to add CPU: %" PRIi64
 | 
			
		||||
                   ", resulting APIC ID (%" PRIi64 ") is too large",
 | 
			
		||||
| 
						 | 
				
			
			@ -1208,7 +1204,6 @@ void pc_cpus_init(PCMachineState *pcms)
 | 
			
		|||
        if (i < smp_cpus) {
 | 
			
		||||
            cpu = pc_new_cpu(typename, x86_cpu_apic_id_from_index(i),
 | 
			
		||||
                             &error_fatal);
 | 
			
		||||
            pcms->possible_cpus->cpus[i].cpu = CPU(cpu);
 | 
			
		||||
            object_unref(OBJECT(cpu));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1252,6 +1247,9 @@ void pc_machine_done(Notifier *notifier, void *data)
 | 
			
		|||
                                        PCMachineState, machine_done);
 | 
			
		||||
    PCIBus *bus = pcms->bus;
 | 
			
		||||
 | 
			
		||||
    /* set the number of CPUs */
 | 
			
		||||
    rtc_set_memory(pcms->rtc, 0x5f, pc_present_cpus_count(pcms) - 1);
 | 
			
		||||
 | 
			
		||||
    if (bus) {
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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,
 | 
			
		||||
                        DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    CPUClass *cc = CPU_GET_CLASS(dev);
 | 
			
		||||
    CPUArchId apic_id, *found_cpu;
 | 
			
		||||
    CPUArchId *found_cpu;
 | 
			
		||||
    HotplugHandlerClass *hhc;
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
 | 
			
		||||
 | 
			
		||||
    if (!dev->hotplugged) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    if (pcms->acpi_dev) {
 | 
			
		||||
        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) {
 | 
			
		||||
        error_setg(&local_err,
 | 
			
		||||
                   "cpu hotplug is not enabled: missing acpi device");
 | 
			
		||||
        goto out;
 | 
			
		||||
    if (dev->hotplugged) {
 | 
			
		||||
        /* increment the number of CPUs */
 | 
			
		||||
        rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
 | 
			
		||||
    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 = pc_find_cpu_slot(pcms, CPU(dev), NULL);
 | 
			
		||||
    found_cpu->cpu = CPU(dev);
 | 
			
		||||
out:
 | 
			
		||||
    error_propagate(errp, local_err);
 | 
			
		||||
| 
						 | 
				
			
			@ -1796,10 +1803,35 @@ out:
 | 
			
		|||
static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
 | 
			
		||||
                                     DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    int idx = -1;
 | 
			
		||||
    HotplugHandlerClass *hhc;
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
    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->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,
 | 
			
		||||
                             DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    CPUArchId *found_cpu;
 | 
			
		||||
    HotplugHandlerClass *hhc;
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1826,17 +1859,129 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
 | 
			
		|||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * TODO: enable unplug once generic CPU remove bits land
 | 
			
		||||
     * for now guest will be able to eject CPU ACPI wise but
 | 
			
		||||
     * it will come back again on machine reset.
 | 
			
		||||
     */
 | 
			
		||||
    /*  object_unparent(OBJECT(dev)); */
 | 
			
		||||
    found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL);
 | 
			
		||||
    found_cpu->cpu = NULL;
 | 
			
		||||
    object_unparent(OBJECT(dev));
 | 
			
		||||
 | 
			
		||||
    rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) - 1);
 | 
			
		||||
 out:
 | 
			
		||||
    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,
 | 
			
		||||
                                      DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -2090,6 +2235,50 @@ static CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine)
 | 
			
		|||
    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)
 | 
			
		||||
{
 | 
			
		||||
    /* 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->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
 | 
			
		||||
    mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
 | 
			
		||||
    mc->query_hotpluggable_cpus = pc_query_hotpluggable_cpus;
 | 
			
		||||
    mc->default_boot_order = "cad";
 | 
			
		||||
    mc->hot_add_cpu = pc_hot_add_cpu;
 | 
			
		||||
    mc->max_cpus = 255;
 | 
			
		||||
    mc->reset = pc_machine_reset;
 | 
			
		||||
    hc->pre_plug = pc_machine_device_pre_plug_cb;
 | 
			
		||||
    hc->plug = pc_machine_device_plug_cb;
 | 
			
		||||
    hc->unplug_request = pc_machine_device_unplug_request_cb;
 | 
			
		||||
    hc->unplug = pc_machine_device_unplug_cb;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,9 @@
 | 
			
		|||
#include "trace.h"
 | 
			
		||||
#include "hw/i386/pc.h"
 | 
			
		||||
#include "hw/i386/apic-msidef.h"
 | 
			
		||||
#include "qapi/error.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_APICS 255
 | 
			
		||||
#define MAX_APIC_WORDS 8
 | 
			
		||||
 | 
			
		||||
#define SYNC_FROM_VAPIC                 0x1
 | 
			
		||||
| 
						 | 
				
			
			@ -419,7 +421,7 @@ static int apic_find_dest(uint8_t dest)
 | 
			
		|||
    int i;
 | 
			
		||||
 | 
			
		||||
    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++) {
 | 
			
		||||
        apic = local_apics[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -502,14 +504,14 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
 | 
			
		|||
        break;
 | 
			
		||||
    case 1:
 | 
			
		||||
        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
 | 
			
		||||
        apic_set_bit(deliver_bitmask, s->idx);
 | 
			
		||||
        apic_set_bit(deliver_bitmask, s->id);
 | 
			
		||||
        break;
 | 
			
		||||
    case 2:
 | 
			
		||||
        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
 | 
			
		||||
        break;
 | 
			
		||||
    case 3:
 | 
			
		||||
        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
 | 
			
		||||
        apic_reset_bit(deliver_bitmask, s->idx);
 | 
			
		||||
        apic_reset_bit(deliver_bitmask, s->id);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -870,20 +872,36 @@ static void apic_realize(DeviceState *dev, Error **errp)
 | 
			
		|||
{
 | 
			
		||||
    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",
 | 
			
		||||
                          APIC_SPACE_SIZE);
 | 
			
		||||
 | 
			
		||||
    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
 | 
			
		||||
    local_apics[s->idx] = s;
 | 
			
		||||
    local_apics[s->id] = s;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    APICCommonClass *k = APIC_COMMON_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    k->realize = apic_realize;
 | 
			
		||||
    k->unrealize = apic_unrealize;
 | 
			
		||||
    k->set_base = apic_set_base;
 | 
			
		||||
    k->set_tpr = apic_set_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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription vmstate_apic_common;
 | 
			
		||||
 | 
			
		||||
static void apic_common_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    APICCommonState *s = APIC_COMMON(dev);
 | 
			
		||||
    APICCommonClass *info;
 | 
			
		||||
    static DeviceState *vapic;
 | 
			
		||||
    static int apic_no;
 | 
			
		||||
 | 
			
		||||
    if (apic_no >= MAX_APICS) {
 | 
			
		||||
        error_setg(errp, "%s initialization failed.",
 | 
			
		||||
                   object_get_typename(OBJECT(dev)));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    s->idx = apic_no++;
 | 
			
		||||
    int instance_id = s->id;
 | 
			
		||||
 | 
			
		||||
    info = APIC_COMMON_GET_CLASS(s);
 | 
			
		||||
    info->realize(dev, errp);
 | 
			
		||||
| 
						 | 
				
			
			@ -321,6 +316,24 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
 | 
			
		|||
        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)
 | 
			
		||||
| 
						 | 
				
			
			@ -418,6 +431,8 @@ static Property apic_properties_common[] = {
 | 
			
		|||
    DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
 | 
			
		||||
    DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
 | 
			
		||||
                    true),
 | 
			
		||||
    DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id,
 | 
			
		||||
                     false),
 | 
			
		||||
    DEFINE_PROP_END_OF_LIST(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -425,10 +440,10 @@ static void apic_common_class_init(ObjectClass *klass, void *data)
 | 
			
		|||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    dc->vmsd = &vmstate_apic_common;
 | 
			
		||||
    dc->reset = apic_reset_common;
 | 
			
		||||
    dc->props = apic_properties_common;
 | 
			
		||||
    dc->realize = apic_common_realize;
 | 
			
		||||
    dc->unrealize = apic_common_unrealize;
 | 
			
		||||
    /*
 | 
			
		||||
     * Reason: APIC and CPU need to be wired up by
 | 
			
		||||
     * x86_cpu_apic_create()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,8 +121,6 @@
 | 
			
		|||
#define VAPIC_ENABLE_BIT                0
 | 
			
		||||
#define VAPIC_ENABLE_MASK               (1 << VAPIC_ENABLE_BIT)
 | 
			
		||||
 | 
			
		||||
#define MAX_APICS 255
 | 
			
		||||
 | 
			
		||||
typedef struct APICCommonState APICCommonState;
 | 
			
		||||
 | 
			
		||||
#define TYPE_APIC_COMMON "apic-common"
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +136,7 @@ typedef struct APICCommonClass
 | 
			
		|||
    DeviceClass parent_class;
 | 
			
		||||
 | 
			
		||||
    DeviceRealize realize;
 | 
			
		||||
    DeviceUnrealize unrealize;
 | 
			
		||||
    void (*set_base)(APICCommonState *s, uint64_t val);
 | 
			
		||||
    void (*set_tpr)(APICCommonState *s, uint8_t val);
 | 
			
		||||
    uint8_t (*get_tpr)(APICCommonState *s);
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +175,6 @@ struct APICCommonState {
 | 
			
		|||
    uint32_t initial_count;
 | 
			
		||||
    int64_t initial_count_load_time;
 | 
			
		||||
    int64_t next_time;
 | 
			
		||||
    int idx;
 | 
			
		||||
    QEMUTimer *timer;
 | 
			
		||||
    int64_t timer_expiry;
 | 
			
		||||
    int sipi_vector;
 | 
			
		||||
| 
						 | 
				
			
			@ -185,6 +183,7 @@ struct APICCommonState {
 | 
			
		|||
    uint32_t vapic_control;
 | 
			
		||||
    DeviceState *vapic;
 | 
			
		||||
    hwaddr vapic_paddr; /* note: persistence via kvmvapic */
 | 
			
		||||
    bool legacy_instance_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct VAPICState {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -377,6 +377,16 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
 | 
			
		|||
        .driver   = "vmxnet3",\
 | 
			
		||||
        .property = "romfile",\
 | 
			
		||||
        .value    = "",\
 | 
			
		||||
    },\
 | 
			
		||||
    {\
 | 
			
		||||
        .driver = TYPE_X86_CPU,\
 | 
			
		||||
        .property = "fill-mtrr-mask",\
 | 
			
		||||
        .value = "off",\
 | 
			
		||||
    },\
 | 
			
		||||
    {\
 | 
			
		||||
        .driver   = "apic",\
 | 
			
		||||
        .property = "legacy-instance-id",\
 | 
			
		||||
        .value    = "on",\
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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'
 | 
			
		||||
 *
 | 
			
		||||
 * '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",
 | 
			
		||||
       "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[] = {
 | 
			
		||||
    NULL, NULL, NULL, "pku",
 | 
			
		||||
    NULL, NULL, "umip", "pku",
 | 
			
		||||
    "ospke", 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,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
 | 
			
		||||
                                      const char *name, void *opaque,
 | 
			
		||||
| 
						 | 
				
			
			@ -2641,17 +2597,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
 | 
			
		|||
        break;
 | 
			
		||||
    case 0x80000008:
 | 
			
		||||
        /* 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) {
 | 
			
		||||
            /* 64 bit processor */
 | 
			
		||||
/* XXX: The physical address space is limited to 42 bits in exec.c. */
 | 
			
		||||
            *eax = 0x00003028; /* 48 bits virtual, 40 bits physical */
 | 
			
		||||
            /* 64 bit processor, 48 bits virtual, configurable
 | 
			
		||||
             * physical bits.
 | 
			
		||||
             */
 | 
			
		||||
            *eax = 0x00003000 + cpu->phys_bits;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (env->features[FEAT_1_EDX] & CPUID_PSE36) {
 | 
			
		||||
                *eax = 0x00000024; /* 36 bits physical */
 | 
			
		||||
            } else {
 | 
			
		||||
                *eax = 0x00000020; /* 32 bits physical */
 | 
			
		||||
            }
 | 
			
		||||
            *eax = cpu->phys_bits;
 | 
			
		||||
        }
 | 
			
		||||
        *ebx = 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));
 | 
			
		||||
 | 
			
		||||
    object_property_add_child(OBJECT(cpu), "apic",
 | 
			
		||||
                              OBJECT(cpu->apic_state), NULL);
 | 
			
		||||
    object_property_add_child(OBJECT(cpu), "lapic",
 | 
			
		||||
                              OBJECT(cpu->apic_state), &error_abort);
 | 
			
		||||
    object_unref(OBJECT(cpu->apic_state));
 | 
			
		||||
 | 
			
		||||
    qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id);
 | 
			
		||||
    /* TODO: convert to link<> */
 | 
			
		||||
    apic = APIC_COMMON(cpu->apic_state);
 | 
			
		||||
| 
						 | 
				
			
			@ -2926,6 +2880,31 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
 | 
			
		|||
}
 | 
			
		||||
#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 && \
 | 
			
		||||
                           (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \
 | 
			
		||||
| 
						 | 
				
			
			@ -2950,7 +2929,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
 | 
			
		|||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cpu->apic_id < 0) {
 | 
			
		||||
    if (cpu->apic_id == UNASSIGNED_APIC_ID) {
 | 
			
		||||
        error_setg(errp, "apic-id property was not initialized properly");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2993,7 +2972,70 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
 | 
			
		|||
           & 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);
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
    uint32_t *ptr;
 | 
			
		||||
    uint32_t mask;
 | 
			
		||||
| 
						 | 
				
			
			@ -3207,9 +3264,6 @@ static void x86_cpu_initfn(Object *obj)
 | 
			
		|||
    object_property_add(obj, "tsc-frequency", "int",
 | 
			
		||||
                        x86_cpuid_get_tsc_freq,
 | 
			
		||||
                        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",
 | 
			
		||||
                        x86_cpu_get_feature_words,
 | 
			
		||||
                        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;
 | 
			
		||||
 | 
			
		||||
#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++) {
 | 
			
		||||
        int bitnr;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3280,6 +3329,18 @@ static bool x86_cpu_has_work(CPUState *cs)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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),
 | 
			
		||||
    { .name  = "hv-spinlocks", .info  = &qdev_prop_spinlocks },
 | 
			
		||||
    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("enforce", X86CPU, enforce_cpuid, false),
 | 
			
		||||
    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("xlevel", X86CPU, env.cpuid_xlevel, 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;
 | 
			
		||||
    dc->realize = x86_cpu_realizefn;
 | 
			
		||||
    dc->unrealize = x86_cpu_unrealizefn;
 | 
			
		||||
    dc->props = x86_cpu_properties;
 | 
			
		||||
 | 
			
		||||
    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_exit = x86_cpu_exec_exit;
 | 
			
		||||
 | 
			
		||||
    dc->cannot_instantiate_with_device_add_yet = false;
 | 
			
		||||
    /*
 | 
			
		||||
     * Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the
 | 
			
		||||
     * 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_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_OSPKE    (1U << 4)
 | 
			
		||||
#define CPUID_7_0_ECX_RDPID    (1U << 22)
 | 
			
		||||
 | 
			
		||||
#define CPUID_XSAVE_XSAVEOPT   (1U << 0)
 | 
			
		||||
#define CPUID_XSAVE_XSAVEC     (1U << 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -845,6 +847,11 @@ typedef struct {
 | 
			
		|||
 | 
			
		||||
#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 {
 | 
			
		||||
    struct {
 | 
			
		||||
        uint16_t fcw;
 | 
			
		||||
| 
						 | 
				
			
			@ -1174,7 +1181,7 @@ struct X86CPU {
 | 
			
		|||
    bool expose_kvm;
 | 
			
		||||
    bool migratable;
 | 
			
		||||
    bool host_features;
 | 
			
		||||
    int64_t apic_id;
 | 
			
		||||
    uint32_t apic_id;
 | 
			
		||||
 | 
			
		||||
    /* if true the CPUID code directly forward host cache leaves to the guest */
 | 
			
		||||
    bool cache_info_passthrough;
 | 
			
		||||
| 
						 | 
				
			
			@ -1198,6 +1205,15 @@ struct X86CPU {
 | 
			
		|||
    /* Compatibility bits for old machine types: */
 | 
			
		||||
    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
 | 
			
		||||
       user */
 | 
			
		||||
    struct DeviceState *apic_state;
 | 
			
		||||
| 
						 | 
				
			
			@ -1205,6 +1221,10 @@ struct X86CPU {
 | 
			
		|||
    Notifier machine_done;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
| 
						 | 
				
			
			@ -1419,11 +1439,13 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 | 
			
		|||
/* XXX: This value should match the one returned by CPUID
 | 
			
		||||
 * and in exec.c */
 | 
			
		||||
# if defined(TARGET_X86_64)
 | 
			
		||||
# define PHYS_ADDR_MASK 0xffffffffffLL
 | 
			
		||||
# define TCG_PHYS_ADDR_BITS 40
 | 
			
		||||
# else
 | 
			
		||||
# define PHYS_ADDR_MASK 0xfffffffffLL
 | 
			
		||||
# define TCG_PHYS_ADDR_BITS 36
 | 
			
		||||
# 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_signal_handler cpu_x86_signal_handler
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1716,6 +1716,8 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
        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_MTRRfix64K_00000, env->mtrr_fixed[0]);
 | 
			
		||||
            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_F8000, env->mtrr_fixed[10]);
 | 
			
		||||
            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),
 | 
			
		||||
                                  env->mtrr_var[i].base);
 | 
			
		||||
                kvm_msr_entry_add(cpu, MSR_MTRRphysMask(i),
 | 
			
		||||
                                  env->mtrr_var[i].mask);
 | 
			
		||||
                kvm_msr_entry_add(cpu, MSR_MTRRphysMask(i), mask);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1970,6 +1977,7 @@ static int kvm_get_msrs(X86CPU *cpu)
 | 
			
		|||
    CPUX86State *env = &cpu->env;
 | 
			
		||||
    struct kvm_msr_entry *msrs = cpu->kvm_msr_buf->entries;
 | 
			
		||||
    int ret, i;
 | 
			
		||||
    uint64_t mtrr_top_bits;
 | 
			
		||||
 | 
			
		||||
    kvm_msr_buf_reset(cpu);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2122,6 +2130,30 @@ static int kvm_get_msrs(X86CPU *cpu)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    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++) {
 | 
			
		||||
        uint32_t index = msrs[i].index;
 | 
			
		||||
        switch (index) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2320,7 +2352,8 @@ static int kvm_get_msrs(X86CPU *cpu)
 | 
			
		|||
            break;
 | 
			
		||||
        case MSR_MTRRphysBase(0) ... MSR_MTRRphysMask(MSR_MTRRcap_VCNT - 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 {
 | 
			
		||||
                env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue