Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions arch/x86/include/asm/multikernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#ifndef __ASSEMBLY__

#include <linux/init.h>
#include <linux/types.h>
#include <linux/cpumask.h>
#include <linux/sizes.h>
Expand Down Expand Up @@ -54,17 +55,21 @@ static inline int arch_cpu_from_physical_id(u64 phys_id)
* from a page written by the host while running on CPUs parked by (possibly
* differently built) spawn kernels.
*
* The fields fall into two classes that must not be mixed up:
* The fields fall into three classes that must not be mixed up:
*
* - Anchor fields (self_phys, park_phys, park_cr3, ctrl_phys,
* ctrl_size): the context's own identity, written once when the
* context is set up. The spawn kernel reads them whenever it parks a
* CPU on halt or offline, so they must stay valid for the context's
* whole lifetime.
*
* - Dispatch fields (everything else): the wake mailbox, rewritten for
* every publication and staged into registers by the CPU that claims
* it. Reparking gets its own repark_* dispatch fields precisely so a
* - Primary boot fields (boot_* and bp): written before the boot CPU is
* released and consumed while that kernel initializes. Secondary and
* repark publications do not rewrite them.
*
* - Dispatch fields (the remaining fixed-size fields): the wake mailbox,
* rewritten for every publication and staged into registers by the CPU
* that claims it. Reparking gets its own repark_* dispatch fields so a
* repark publication never overwrites the anchor: the two used to
* share fields, and a repark left the anchor pointing at another
* kernel's park area, which triple-faulted the next halt.
Expand All @@ -80,6 +85,10 @@ struct mk_spawn_context {
unsigned long gs_base; /* Per-CPU GS base (for secondary) */
unsigned long stack; /* Stack pointer (for secondary) */
unsigned long spawn_cr3; /* Spawn kernel's CR3 (for secondary CPU final switch) */
unsigned long boot_lps; /* Host delay loops per second */
unsigned long boot_cpu_khz; /* Host CPU frequency calibration */
unsigned long boot_tsc_khz; /* Host TSC frequency calibration */
unsigned long boot_apic_hz; /* Host local APIC timer frequency */

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering why you have to handle clock in this PR? If anything is wrong with clock, please separate it out

unsigned long park_phys; /* Pool park code page (host owned, never reloaded) */
unsigned long park_cr3; /* Page table parked CPUs run on (host owned) */
unsigned long repark_park_phys; /* REPARK dispatch: park page to move to */
Expand Down Expand Up @@ -161,6 +170,19 @@ int multikernel_wakeup_secondary_cpu_64(u32 apicid, unsigned long start_eip,
int multikernel_restore_ap(unsigned int cpu, unsigned long cr3,
unsigned long gs_base, unsigned long stack,
unsigned long entry);
struct mk_pci_host_bridge;

#ifdef CONFIG_MULTIKERNEL
int mk_arch_snapshot_pci_host_bridges(const struct mk_instance *instance,
struct mk_pci_host_bridge *bridges,
size_t capacity);
#endif

#if defined(CONFIG_MULTIKERNEL) && defined(CONFIG_PCI)
void __init x86_multikernel_pci_platform_init(void);
#else
static inline void x86_multikernel_pci_platform_init(void) { }
#endif

#endif /* __ASSEMBLY__ */

Expand Down
4 changes: 4 additions & 0 deletions arch/x86/include/asm/pci_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ extern struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,

extern struct list_head pci_mmcfg_list;

typedef int (*pci_mmcfg_region_cb)(const struct pci_mmcfg_region *region,
void *data);
int pci_mmcfg_walk_regions(pci_mmcfg_region_cb callback, void *data);

#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)

/*
Expand Down
41 changes: 40 additions & 1 deletion arch/x86/kernel/platform-quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
#include <asm/e820/api.h>
#include <asm/apic.h>
#include <asm/apicdef.h>
#include <asm/cpufeature.h>
#include <asm/mpspec.h>
#include <asm/numa.h>
#include <asm/page.h>
#include <linux/pgtable.h>
#include <asm/pgtable.h>
#include <asm/pgtable_64_types.h>
Expand All @@ -28,6 +30,35 @@ extern pmd_t *populate_extra_pmd(unsigned long vaddr);
extern unsigned long orig_boot_params;

#ifdef CONFIG_MULTIKERNEL
static unsigned long multikernel_cpu_khz;
static unsigned long multikernel_tsc_khz;

static unsigned long multikernel_calibrate_cpu(void)
{
return multikernel_cpu_khz;
}

static unsigned long multikernel_calibrate_tsc(void)
{
return multikernel_tsc_khz;
}

static void __init multikernel_setup_calibration(void)
{
phys_addr_t ctx_phys = orig_boot_params -
offsetof(struct mk_spawn_context, bp);
struct mk_spawn_context *ctx = __va(ctx_phys);

if (ctx->self_phys != ctx_phys || !ctx->boot_tsc_khz)
return;

multikernel_tsc_khz = ctx->boot_tsc_khz;
multikernel_cpu_khz = ctx->boot_cpu_khz ?: ctx->boot_tsc_khz;
x86_platform.calibrate_cpu = multikernel_calibrate_cpu;
x86_platform.calibrate_tsc = multikernel_calibrate_tsc;
setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
}

/*
* Custom wakeup for multikernel spawn kernels.
* Uses shared spawn table instead of realmode trampoline.
Expand Down Expand Up @@ -105,6 +136,10 @@ static void __init multikernel_parse_smp_config(void)
*/
apic_update_callback(wakeup_secondary_cpu_64, multikernel_wakeup_cpu);
}
#else
static inline void multikernel_setup_calibration(void)
{
}
#endif /* CONFIG_MULTIKERNEL */

void __init x86_early_init_platform_quirks(void)
Expand Down Expand Up @@ -135,6 +170,8 @@ void __init x86_early_init_platform_quirks(void)
x86_platform.legacy.i8042 = X86_LEGACY_I8042_PLATFORM_ABSENT;
break;
case X86_SUBARCH_MULTIKERNEL:
multikernel_setup_calibration();
x86_multikernel_pci_platform_init();
x86_platform.legacy.devices.pnpbios = 0;
x86_platform.legacy.i8042 = X86_LEGACY_I8042_PLATFORM_ABSENT;
x86_platform.legacy.rtc = 0;
Expand Down Expand Up @@ -175,7 +212,9 @@ void __init x86_early_init_platform_quirks(void)
* the PIT - which belongs to the host - and then request
* legacy IRQ0, which can never reach an instance CPU that
* has neither a PIC nor an IO-APIC. Ticks come from the
* local APIC timer via setup_percpu_clockev() instead.
* local APIC timer initialized by setup_percpu_clockev().
* Keeping global_clock_event unset bypasses LAPIC timer
* verification, whose fallback path requires legacy IRQ0.
*/
x86_init.timers.timer_init = x86_init_noop;
x86_init.timers.wallclock_init = x86_init_noop;
Expand Down
1 change: 1 addition & 0 deletions arch/x86/multikernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
#

obj-y += spawn.o direct_boot.o head_64.o
obj-$(CONFIG_PCI) += pci.o
Loading