From: Jan Kiszka <[email protected]> These are the necessary changes to adapt the hypervisor core to the new struct-array CPU configuration format.
Some things become easier: cpu_id_valid() is now a simple inline bounds check, counting CPUs is already done in the config. Other things become more complex: An arch-provided cpu_by_phys_processor_id() is now required in order to map a non-root cell CPU to the logical ID used inside Jailhouse during cell creation. Jailhouse keeps the bitmap of assigned CPUs per cell in order to iterate over them without requiring that physical-to-logical mapping during critical code paths. Signed-off-by: Jan Kiszka <[email protected]> --- hypervisor/arch/arm-common/lib.c | 6 ++--- hypervisor/arch/arm-common/psci.c | 13 +++++---- hypervisor/arch/arm64/gic-v3.c | 20 +++++--------- hypervisor/arch/arm64/paging.c | 5 ++-- hypervisor/arch/x86/apic.c | 8 ++++++ hypervisor/arch/x86/control.c | 5 +--- hypervisor/control.c | 34 +++++++++--------------- hypervisor/include/jailhouse/control.h | 2 -- hypervisor/include/jailhouse/percpu.h | 4 +-- hypervisor/include/jailhouse/processor.h | 4 ++- hypervisor/setup.c | 17 ++++++------ 11 files changed, 52 insertions(+), 66 deletions(-) diff --git a/hypervisor/arch/arm-common/lib.c b/hypervisor/arch/arm-common/lib.c index 5c0dde0a..b3d48da7 100644 --- a/hypervisor/arch/arm-common/lib.c +++ b/hypervisor/arch/arm-common/lib.c @@ -23,12 +23,12 @@ unsigned long phys_processor_id(void) return mpidr & MPIDR_CPUID_MASK; } -unsigned int arm_cpu_by_mpidr(struct cell *cell, unsigned long mpidr) +unsigned int cpu_by_phys_processor_id(u64 phys_id) { unsigned int cpu; - for_each_cpu(cpu, &cell->cpu_set) - if (mpidr == (public_per_cpu(cpu)->mpidr & MPIDR_CPUID_MASK)) + for (cpu = 0; cpu < system_config->root_cell.num_cpus; cpu++) + if (phys_id == (public_per_cpu(cpu)->mpidr & MPIDR_CPUID_MASK)) return cpu; return INVALID_CPU_ID; diff --git a/hypervisor/arch/arm-common/psci.c b/hypervisor/arch/arm-common/psci.c index a0f0b6a7..e832adf9 100644 --- a/hypervisor/arch/arm-common/psci.c +++ b/hypervisor/arch/arm-common/psci.c @@ -2,7 +2,7 @@ * Jailhouse, a Linux-based partitioning hypervisor * * Copyright (c) ARM Limited, 2014 - * Copyright (c) Siemens AG, 2016 + * Copyright (c) Siemens AG, 2016-2022 * * Authors: * Jean-Philippe Brucker <[email protected]> @@ -13,6 +13,7 @@ */ #include <jailhouse/control.h> +#include <jailhouse/processor.h> #include <asm/control.h> #include <asm/psci.h> #include <asm/smccc.h> @@ -26,9 +27,8 @@ static long psci_emulate_cpu_on(struct trap_context *ctx) unsigned int cpu; long result; - cpu = arm_cpu_by_mpidr(this_cell(), ctx->regs[1] & mask); - if (cpu == INVALID_CPU_ID) - /* Virtual id not in set */ + cpu = cpu_by_phys_processor_id(ctx->regs[1] & mask); + if (!cell_owns_cpu(this_cell(), cpu)) return PSCI_DENIED; target_data = public_per_cpu(cpu); @@ -61,10 +61,9 @@ static long psci_emulate_cpu_on(struct trap_context *ctx) static long psci_emulate_affinity_info(struct trap_context *ctx) { - unsigned int cpu = arm_cpu_by_mpidr(this_cell(), ctx->regs[1]); + unsigned int cpu = cpu_by_phys_processor_id(ctx->regs[1]); - if (cpu == INVALID_CPU_ID) - /* Virtual id not in set */ + if (!cell_owns_cpu(this_cell(), cpu)) return PSCI_DENIED; return public_per_cpu(cpu)->wait_for_poweron ? diff --git a/hypervisor/arch/arm64/gic-v3.c b/hypervisor/arch/arm64/gic-v3.c index 8d18f6ec..3da0053f 100644 --- a/hypervisor/arch/arm64/gic-v3.c +++ b/hypervisor/arch/arm64/gic-v3.c @@ -35,7 +35,6 @@ static unsigned int gic_num_lr; static unsigned int gic_num_priority_bits; -static unsigned int last_gicr; static u32 gic_version; static void *gicr_base; @@ -136,10 +135,6 @@ static int gicv3_init(void) if (!(mmio_read32(gicd_base + GICD_CTLR) & GICD_CTLR_ARE_NS)) return trace_error(-EIO); - last_gicr = system_config->root_cell.cpu_set_size * 8 - 1; - while (!cpu_id_valid(last_gicr)) - last_gicr--; - /* * Let the per-cpu code access the redistributors. This makes the * assumption, that redistributors can be found in a sequence. @@ -147,7 +142,7 @@ static int gicv3_init(void) if (gic_version == 4) redist_size = GIC_V4_REDIST_SIZE; - gicr_size = redist_size * (last_gicr + 1); + gicr_size = redist_size * system_config->root_cell.num_cpus; gicr_base = paging_map_device( system_config->platform_info.arm.gicr_base, gicr_size); if (!gicr_base) @@ -341,8 +336,8 @@ static void gicv3_adjust_irq_target(struct cell *cell, u16 irq_id) { void *irouter = gicd_base + GICD_IROUTER + 8 * irq_id; u64 mpidr = public_per_cpu(first_cpu(&cell->cpu_set))->mpidr; - u32 route = arm_cpu_by_mpidr(cell, - mmio_read64(irouter) & MPIDR_CPUID_MASK); + unsigned int route = cpu_by_phys_processor_id(mmio_read64(irouter) & + MPIDR_CPUID_MASK); if (!cell_owns_cpu(cell, route)) mmio_write64(irouter, mpidr); @@ -357,8 +352,8 @@ static enum mmio_result gicv3_handle_redist_access(void *arg, switch (mmio->address) { case GICR_TYPER: mmio_perform_access(cpu_public->gicr.base, mmio); - if (cpu_public->cpu_id == last_gicr) - mmio->value |= GICR_TYPER_Last; + if (cpu_public->cpu_id == system_config->root_cell.num_cpus - 1) + mmio->value |= GICR_TYPER_Last; return MMIO_HANDLED; case GICR_TYPER + 4: mmio_perform_access(cpu_public->gicr.base, mmio); @@ -409,14 +404,11 @@ static int gicv3_cell_init(struct cell *cell) * We register all regions so that the cell can iterate over the * original range in order to find corresponding redistributors. */ - for (cpu = 0; cpu < system_config->root_cell.cpu_set_size * 8; cpu++) { - if (!cpu_id_valid(cpu)) - continue; + for (cpu = 0; cpu < system_config->root_cell.num_cpus; cpu++) mmio_region_register(cell, public_per_cpu(cpu)->gicr.phys_addr, gic_version == 4 ? 0x40000 : 0x20000, gicv3_handle_redist_access, public_per_cpu(cpu)); - } return 0; } diff --git a/hypervisor/arch/arm64/paging.c b/hypervisor/arch/arm64/paging.c index 27adcf55..cc3c50f7 100644 --- a/hypervisor/arch/arm64/paging.c +++ b/hypervisor/arch/arm64/paging.c @@ -38,9 +38,8 @@ unsigned int get_cpu_parange(void) * for_each_cpu yet. So we need to iterate over the configuration * of the root cell. */ - for (cpu = 0; cpu < system_config->root_cell.cpu_set_size * 8; cpu++) - if (cpu_id_valid(cpu) && - (per_cpu(cpu)->id_aa64mmfr0 & 0xf) < cpu_parange_encoded) + for (cpu = 0; cpu < system_config->root_cell.num_cpus; cpu++) + if ((per_cpu(cpu)->id_aa64mmfr0 & 0xf) < cpu_parange_encoded) cpu_parange_encoded = per_cpu(cpu)->id_aa64mmfr0 & 0xf; return cpu_parange_encoded < ARRAY_SIZE(pa_bits) ? diff --git a/hypervisor/arch/x86/apic.c b/hypervisor/arch/x86/apic.c index 9c6313eb..74b43e5d 100644 --- a/hypervisor/arch/x86/apic.c +++ b/hypervisor/arch/x86/apic.c @@ -140,6 +140,14 @@ unsigned long phys_processor_id(void) return apic_ops.read_id(); } +unsigned int cpu_by_phys_processor_id(u64 phys_id) +{ + unsigned int cpu_id = phys_id < APIC_MAX_PHYS_ID ? + apic_to_cpu_id[phys_id] : INVALID_CPU_ID; + + return cpu_id != APIC_INVALID_CPU ? cpu_id : INVALID_CPU_ID; +} + int apic_cpu_init(struct per_cpu *cpu_data) { unsigned int xlc = MAX((apic_ext_features() >> 16) & 0xff, diff --git a/hypervisor/arch/x86/control.c b/hypervisor/arch/x86/control.c index 3d84308d..188a6d19 100644 --- a/hypervisor/arch/x86/control.c +++ b/hypervisor/arch/x86/control.c @@ -88,13 +88,10 @@ void arch_cell_destroy(struct cell *cell) void arch_cell_reset(struct cell *cell) { struct jailhouse_comm_region *comm_region = &cell->comm_page.comm_region; - unsigned int cpu; comm_region->pm_timer_address = system_config->platform_info.x86.pm_timer_address; - /* comm_region, and hence num_cpus, is zero-initialised */ - for_each_cpu(cpu, &cell->cpu_set) - comm_region->num_cpus++; + comm_region->num_cpus = cell->config->num_cpus; comm_region->tsc_khz = system_config->platform_info.x86.tsc_khz; comm_region->apic_khz = system_config->platform_info.x86.apic_khz; diff --git a/hypervisor/control.c b/hypervisor/control.c index 9642493c..8eaaa46a 100644 --- a/hypervisor/control.c +++ b/hypervisor/control.c @@ -58,22 +58,6 @@ unsigned int next_cpu(unsigned int cpu, struct cpu_set *cpu_set, return cpu; } -/** - * Check if a CPU ID is contained in the system's CPU set, i.e. the initial CPU - * set of the root cell. - * @param cpu_id CPU ID to check. - * - * @return True if CPU ID is valid. - */ -bool cpu_id_valid(unsigned long cpu_id) -{ - const unsigned long *system_cpu_set = - jailhouse_cell_cpu_set(&system_config->root_cell); - - return (cpu_id < system_config->root_cell.cpu_set_size * 8 && - test_bit(cpu_id, system_cpu_set)); -} - /** * Suspend a remote CPU. * @param cpu_id ID of the target CPU. @@ -240,14 +224,22 @@ static void cell_reconfig_completed(void) */ int cell_init(struct cell *cell) { - const unsigned long *config_cpu_set = - jailhouse_cell_cpu_set(cell->config); - unsigned long cpu_set_size = cell->config->cpu_set_size; + const struct jailhouse_cpu *cell_cpu = + jailhouse_cell_cpus(cell->config); + unsigned long cpu_set_size = (cell->config->num_cpus + 7) / 8; + unsigned int cpu_idx, result; if (cpu_set_size > sizeof(cell->cpu_set.bitmap)) return trace_error(-EINVAL); cell->cpu_set.max_cpu_id = cpu_set_size * 8 - 1; - memcpy(cell->cpu_set.bitmap, config_cpu_set, cpu_set_size); + + for (cpu_idx = 0; cpu_idx < cell->config->num_cpus; cpu_idx++) { + result = cpu_by_phys_processor_id(cell_cpu[cpu_idx].phys_id); + if (result == INVALID_CPU_ID) + return -ENOENT; + + set_bit(result, cell->cpu_set.bitmap); + } return mmio_cell_init(cell); } @@ -892,7 +884,7 @@ static long hypervisor_get_info(struct per_cpu *cpu_data, unsigned long type) static int cpu_get_info(struct per_cpu *cpu_data, unsigned long cpu_id, unsigned long type) { - if (!cpu_id_valid(cpu_id)) + if (cpu_id >= system_config->root_cell.num_cpus) return -EINVAL; /* diff --git a/hypervisor/include/jailhouse/control.h b/hypervisor/include/jailhouse/control.h index cb720af5..f01af617 100644 --- a/hypervisor/include/jailhouse/control.h +++ b/hypervisor/include/jailhouse/control.h @@ -119,8 +119,6 @@ static inline bool cell_owns_cpu(struct cell *cell, unsigned int cpu_id) test_bit(cpu_id, cell->cpu_set.bitmap)); } -bool cpu_id_valid(unsigned long cpu_id); - int cell_init(struct cell *cell); void config_commit(struct cell *cell_added_removed); diff --git a/hypervisor/include/jailhouse/percpu.h b/hypervisor/include/jailhouse/percpu.h index 4f0867da..c5a9c109 100644 --- a/hypervisor/include/jailhouse/percpu.h +++ b/hypervisor/include/jailhouse/percpu.h @@ -1,7 +1,7 @@ /* * Jailhouse, a Linux-based partitioning hypervisor * - * Copyright (c) Siemens AG, 2013-2018 + * Copyright (c) Siemens AG, 2013-2022 * * Authors: * Jan Kiszka <[email protected]> @@ -34,7 +34,7 @@ struct public_per_cpu { * page walks at any time. */ u8 root_table_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); - /** Logical CPU ID (same as Linux). */ + /** Logical CPU ID. */ unsigned int cpu_id; /** Owning cell. */ struct cell *cell; diff --git a/hypervisor/include/jailhouse/processor.h b/hypervisor/include/jailhouse/processor.h index 639b2e5e..26f0907f 100644 --- a/hypervisor/include/jailhouse/processor.h +++ b/hypervisor/include/jailhouse/processor.h @@ -1,7 +1,7 @@ /* * Jailhouse, a Linux-based partitioning hypervisor * - * Copyright (c) Siemens AG, 2013 + * Copyright (c) Siemens AG, 2013-2022 * * Authors: * Jan Kiszka <[email protected]> @@ -16,4 +16,6 @@ unsigned long phys_processor_id(void); +unsigned int cpu_by_phys_processor_id(u64 phys_id); + #endif diff --git a/hypervisor/setup.c b/hypervisor/setup.c index 7f7cf041..00bc280c 100644 --- a/hypervisor/setup.c +++ b/hypervisor/setup.c @@ -59,6 +59,11 @@ static void init_early(unsigned int cpu_id) root_cell.config = &system_config->root_cell; + if (hypervisor_header.online_cpus != root_cell.config->num_cpus) { + error = trace_error(-EINVAL); + return; + } + error = arch_init_early(); if (error) return; @@ -99,7 +104,8 @@ static void cpu_init(struct per_cpu *cpu_data) printk(" CPU %d... ", cpu_data->public.cpu_id); - if (!cpu_id_valid(cpu_data->public.cpu_id)) + if (cpu_data->public.cpu_id >= system_config->root_cell.num_cpus || + cpu_data->public.cell != NULL) goto failed; cpu_data->public.cell = &root_cell; @@ -160,21 +166,14 @@ failed: static void init_late(void) { - unsigned int n, cpu, expected_cpus = 0; const struct jailhouse_memory *mem; struct unit *unit; + unsigned int n; error = cell_init(&root_cell); if (error) return; - for_each_cpu(cpu, &root_cell.cpu_set) - expected_cpus++; - if (hypervisor_header.online_cpus != expected_cpus) { - error = trace_error(-EINVAL); - return; - } - for_each_unit(unit) { printk("Initializing unit: %s\n", unit->name); error = unit->init(); -- 2.36.1 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/jailhouse-dev/20220627131329.3659-15-ralf.ramsauer%40oth-regensburg.de.
