cpu/x86/smm: Refactor creating a stub/save state map
This code was very hard to read so rewrite it using as few mutable local variables as possible. Tested on qemu with 128 cores. Change-Id: I7a455ba45a1c92533a8ecfd1aeecf34b4a63e409 Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/c/coreboot/+/63474 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Martin L Roth <gaumless@tutanota.com>
This commit is contained in:
parent
04860bb1e7
commit
0ab98d5ed3
|
@ -1,5 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#include "assert.h"
|
||||||
#include <acpi/acpi_gnvs.h>
|
#include <acpi/acpi_gnvs.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -85,65 +86,54 @@ struct cpu_smm_info cpus[CONFIG_MAX_CPUS] = { 0 };
|
||||||
* input : num_cpus in the system. The map will
|
* input : num_cpus in the system. The map will
|
||||||
* be created from 0 to num_cpus.
|
* be created from 0 to num_cpus.
|
||||||
*/
|
*/
|
||||||
static int smm_create_map(uintptr_t smbase, unsigned int num_cpus,
|
static int smm_create_map(const uintptr_t smbase, const unsigned int num_cpus,
|
||||||
const struct smm_loader_params *params)
|
const struct smm_loader_params *params)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
struct rmodule smm_stub;
|
struct rmodule smm_stub;
|
||||||
unsigned int ss_size = params->per_cpu_save_state_size, stub_size;
|
|
||||||
unsigned int smm_entry_offset = SMM_ENTRY_OFFSET;
|
if (ARRAY_SIZE(cpus) < num_cpus) {
|
||||||
unsigned int seg_count = 0, segments = 0, available;
|
printk(BIOS_ERR, "%s: increase MAX_CPUS in Kconfig\n", __func__);
|
||||||
unsigned int cpus_in_segment = 0;
|
return 0;
|
||||||
unsigned int base = smbase;
|
}
|
||||||
|
|
||||||
if (rmodule_parse(&_binary_smmstub_start, &smm_stub)) {
|
if (rmodule_parse(&_binary_smmstub_start, &smm_stub)) {
|
||||||
printk(BIOS_ERR, "%s: unable to get SMM module size\n", __func__);
|
printk(BIOS_ERR, "%s: unable to get SMM module size\n", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stub_size = rmodule_memory_size(&smm_stub);
|
/*
|
||||||
/* How many CPUs can fit into one 64K segment? */
|
* How many CPUs can fit into one 64K segment?
|
||||||
available = 0xFFFF - smm_entry_offset - ss_size - stub_size;
|
* Make sure that the first stub does not overlap with the last save state of a segment.
|
||||||
if (available > 0) {
|
*/
|
||||||
cpus_in_segment = available / ss_size;
|
const size_t stub_size = rmodule_memory_size(&smm_stub);
|
||||||
/* minimum segments needed will always be 1 */
|
const size_t needed_ss_size = MAX(params->real_cpu_save_state_size, stub_size);
|
||||||
segments = num_cpus / cpus_in_segment + 1;
|
const size_t cpus_per_segment =
|
||||||
printk(BIOS_DEBUG,
|
(SMM_CODE_SEGMENT_SIZE - SMM_ENTRY_OFFSET - stub_size) / needed_ss_size;
|
||||||
"%s: cpus allowed in one segment %d\n", __func__, cpus_in_segment);
|
|
||||||
printk(BIOS_DEBUG,
|
if (cpus_per_segment == 0) {
|
||||||
"%s: min # of segments needed %d\n", __func__, segments);
|
printk(BIOS_ERR, "%s: CPUs won't fit in segment. Broken stub or save state size\n",
|
||||||
} else {
|
__func__);
|
||||||
printk(BIOS_ERR, "%s: not enough space in SMM to setup all CPUs\n", __func__);
|
|
||||||
printk(BIOS_ERR, " save state & stub size need to be reduced\n");
|
|
||||||
printk(BIOS_ERR, " or increase SMRAM size\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARRAY_SIZE(cpus) < num_cpus) {
|
for (unsigned int i = 0; i < num_cpus; i++) {
|
||||||
printk(BIOS_ERR,
|
if (i % cpus_per_segment == 0)
|
||||||
"%s: increase MAX_CPUS in Kconfig\n", __func__);
|
printk(BIOS_DEBUG, "-------------NEW CODE SEGMENT --------------\n");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num_cpus; i++) {
|
|
||||||
printk(BIOS_DEBUG, "CPU 0x%x\n", i);
|
printk(BIOS_DEBUG, "CPU 0x%x\n", i);
|
||||||
cpus[i].smbase = base;
|
/* We copy the same stub for each CPU so they all need the same 'smbase'. */
|
||||||
cpus[i].entry = base + smm_entry_offset;
|
const size_t segment_number = i / cpus_per_segment;
|
||||||
printk(BIOS_DEBUG, " smbase %lx entry %lx\n", cpus[i].smbase,
|
cpus[i].smbase = smbase - SMM_CODE_SEGMENT_SIZE * segment_number
|
||||||
cpus[i].entry);
|
- needed_ss_size * (i % cpus_per_segment);
|
||||||
cpus[i].ss_start = cpus[i].entry + (smm_entry_offset - ss_size);
|
cpus[i].entry = cpus[i].smbase + SMM_ENTRY_OFFSET;
|
||||||
|
cpus[i].ss_start = cpus[i].smbase + SMM_CODE_SEGMENT_SIZE - needed_ss_size;
|
||||||
cpus[i].code_start = cpus[i].entry;
|
cpus[i].code_start = cpus[i].entry;
|
||||||
cpus[i].code_end = cpus[i].entry + stub_size;
|
cpus[i].code_end = cpus[i].entry + stub_size;
|
||||||
printk(BIOS_DEBUG, " ss_start %lx code_end %lx\n", cpus[i].ss_start,
|
printk(BIOS_DEBUG, " Stub [0x%lx-0x%lx[\n", cpus[i].code_start,
|
||||||
cpus[i].code_end);
|
cpus[i].code_end);
|
||||||
|
printk(BIOS_DEBUG, " Save state [0x%lx-0x%lx[\n",
|
||||||
|
cpus[i].ss_start + needed_ss_size - params->real_cpu_save_state_size,
|
||||||
|
cpus[i].ss_start + needed_ss_size);
|
||||||
cpus[i].active = 1;
|
cpus[i].active = 1;
|
||||||
base -= ss_size;
|
|
||||||
seg_count++;
|
|
||||||
if (seg_count >= cpus_in_segment) {
|
|
||||||
base -= smm_entry_offset;
|
|
||||||
seg_count = 0;
|
|
||||||
printk(BIOS_DEBUG, "-------------NEW CODE SEGMENT --------------\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
Loading…
Reference in New Issue