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:
parent
54fb7bf685
commit
1d934e8979
40
hw/pc.c
40
hw/pc.c
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user