#include <config.h>
#include <arch/machine.h>
#include <arch/kernel/boot_sys.h>
#include <arch/kernel/smp_sys.h>
#include <smp/lock.h>
#if CONFIG_MAX_NUM_NODES > 1
BOOT_DATA VISIBLE
volatile word_t smp_aps_index = 1;
#ifdef CONFIG_USE_LOGICAL_IDS
BOOT_CODE static void
update_logical_id_mappings(void)
{
cpu_mapping.index_to_logical_id[getCurrentCPUIndex()] = apic_get_logical_id();
for (int i = 0; i < smp_aps_index; i++) {
if (apic_get_cluster(cpu_mapping.index_to_logical_id[getCurrentCPUIndex()]) ==
apic_get_cluster(cpu_mapping.index_to_logical_id[i])) {
cpu_mapping.other_indexes_in_cluster[getCurrentCPUIndex()] |= BIT(i);
cpu_mapping.other_indexes_in_cluster[i] |= BIT(getCurrentCPUIndex());
}
}
}
#endif
BOOT_CODE static void
start_cpu(cpu_id_t cpu_id, paddr_t boot_fun_paddr)
{
x86_mfence();
apic_send_init_ipi(cpu_id);
apic_send_startup_ipi(cpu_id, boot_fun_paddr);
}
BOOT_CODE void
start_boot_aps(void)
{
cpu_mapping.index_to_cpu_id[getCurrentCPUIndex()] = boot_state.cpus[0];
#ifdef CONFIG_USE_LOGICAL_IDS
cpu_mapping.index_to_logical_id[getCurrentCPUIndex()] = apic_get_logical_id();
#endif
while (smp_aps_index < boot_state.num_cpus) {
word_t current_ap_index = smp_aps_index;
printf("Starting node #%lu with APIC ID %lu \n",
current_ap_index, boot_state.cpus[current_ap_index]);
cpu_mapping.index_to_cpu_id[current_ap_index] = boot_state.cpus[current_ap_index];
start_cpu(boot_state.cpus[current_ap_index], BOOT_NODE_PADDR);
while (smp_aps_index == current_ap_index);
}
}
BOOT_CODE bool_t
copy_boot_code_aps(uint32_t mem_lower)
{
assert(boot_cpu_end - boot_cpu_start < 0x400);
word_t boot_size = (word_t)(boot_cpu_end - boot_cpu_start);
word_t boot_node_top = BOOT_NODE_PADDR + boot_size;
word_t mem_lower_bytes = mem_lower << 10;
if (boot_node_top > BOOT_NODE_MAX_PADDR) {
printf("AP boot code does not fit in chosen memory hole. Can be at most %lu, is %lu\n",
(word_t)(BOOT_NODE_MAX_PADDR - BOOT_NODE_PADDR), boot_size);
return false;
}
if (mem_lower_bytes < boot_node_top) {
printf("Need lower physical memory up to %lu to be free. Multiboot reports only up to %lu\n",
boot_node_top, mem_lower_bytes);
return false;
}
memcpy((void*)BOOT_NODE_PADDR, boot_cpu_start, boot_size);
return true;
}
static BOOT_CODE bool_t
try_boot_node(void)
{
setCurrentVSpaceRoot(kpptr_to_paddr(X86_GLOBAL_VSPACE_ROOT), 0);
asm volatile("" ::: "memory");
if (!init_cpu(1)) {
return false;
}
#ifdef CONFIG_USE_LOGICAL_IDS
update_logical_id_mappings();
#endif
return true;
}
VISIBLE void
boot_node(void)
{
bool_t result;
mode_init_tls(smp_aps_index);
result = try_boot_node();
if (!result) {
fail("boot_node failed for some reason :(\n");
}
smp_aps_index++;
NODE_LOCK_SYS;
init_core_state(SchedulerAction_ChooseNewThread);
ARCH_NODE_STATE(x86KScurInterrupt) = int_invalid;
ARCH_NODE_STATE(x86KSPendingInterrupt) = int_invalid;
schedule();
activateThread();
}
#endif