pc: Set fw_cfg data based on APIC ID calculation

This changes FW_CFG_MAX_CPUS and FW_CFG_NUMA to use apic_id_for_cpu(),
so the NUMA table can be based on the APIC IDs, instead of CPU index
(SeaBIOS knows nothing about CPU indexes, just APIC IDs).

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
Eduardo Habkost 2013-01-23 15:51:18 -02:00 committed by Andreas Färber
parent 54fb7bf685
commit 1d934e8979

40
hw/pc.c
View File

@ -551,6 +551,18 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
return index;
}
/* Calculates the limit to CPU APIC ID values
*
* This function returns the limit for the APIC ID value, so that all
* CPU APIC IDs are < pc_apic_id_limit().
*
* This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
*/
static unsigned int pc_apic_id_limit(unsigned int max_cpus)
{
return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
}
static void *bochs_bios_init(void)
{
void *fw_cfg;
@ -558,9 +570,24 @@ static void *bochs_bios_init(void)
size_t smbios_len;
uint64_t *numa_fw_cfg;
int i, j;
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
*
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
* QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC
* ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the
* "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS
* may see".
*
* So, this means we must not use max_cpus, here, but the maximum possible
* APIC ID value, plus one.
*
* [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is
* the APIC ID, not the "CPU index"
*/
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
@ -579,21 +606,24 @@ static void *bochs_bios_init(void)
* of nodes, one word for each VCPU->node and one word for each node to
* hold the amount of memory.
*/
numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes);
numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes);
numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
for (i = 0; i < max_cpus; i++) {
unsigned int apic_id = x86_cpu_apic_id_from_index(i);
assert(apic_id < apic_id_limit);
for (j = 0; j < nb_numa_nodes; j++) {
if (test_bit(i, node_cpumask[j])) {
numa_fw_cfg[i + 1] = cpu_to_le64(j);
numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
break;
}
}
}
for (i = 0; i < nb_numa_nodes; i++) {
numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]);
numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]);
}
fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
(1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg));
(1 + apic_id_limit + nb_numa_nodes) *
sizeof(*numa_fw_cfg));
return fw_cfg;
}