From: Jan Kiszka <[email protected]> This introduces the concept of functional units which can register themselves with the core.
Each unit will then receive a number of callbacks on events of common interest: hypervisor init and shutdown, cell creation and destruction, and counting of MMIO regions per cell. All callbacks are mandatory, so unused ones need to be stubbed. For the more common cases of missing shutdown or mmio_count_regions callbacks, macros are provided. The init callbacks are run in linking order, cleanup callbacks in the reverse order. Registration is performed by adding a unit structure to the units section. From there, for_each_unit* iterators can pick them up in linking order (or reversed). The goal of this abstraction is to remove explicit hooks for the mentioned events for each unit. It also allows to add a unit by simply linking it against the hypervisor. This is specifically useful for existing target-specific variations (e.g. CAT for Intel or VExpress extensions) or upcoming optional features. The reason to call this "unit", instead of "module", is to avoid confusion with abstractions in Linux or other projects that have broader semantics. E.g., a unit is not intended to become a runtime loadable entity. Signed-off-by: Jan Kiszka <[email protected]> --- hypervisor/control.c | 21 +++++++++++++++ hypervisor/hypervisor.lds.S | 6 +++++ hypervisor/include/jailhouse/unit.h | 54 +++++++++++++++++++++++++++++++++++++ hypervisor/mmio.c | 4 +++ hypervisor/setup.c | 9 +++++++ 5 files changed, 94 insertions(+) create mode 100644 hypervisor/include/jailhouse/unit.h diff --git a/hypervisor/control.c b/hypervisor/control.c index 52ef8733e..c71cb82b7 100644 --- a/hypervisor/control.c +++ b/hypervisor/control.c @@ -17,6 +17,7 @@ #include <jailhouse/paging.h> #include <jailhouse/processor.h> #include <jailhouse/string.h> +#include <jailhouse/unit.h> #include <jailhouse/utils.h> #include <asm/bitops.h> #include <asm/spinlock.h> @@ -302,6 +303,7 @@ static void cell_destroy_internal(struct per_cpu *cpu_data, struct cell *cell) { const struct jailhouse_memory *mem; unsigned int cpu, n; + struct unit *unit; for_each_cpu(cpu, cell->cpu_set) { arch_park_cpu(cpu); @@ -326,6 +328,8 @@ static void cell_destroy_internal(struct per_cpu *cpu_data, struct cell *cell) remap_to_root_cell(mem, WARN_ON_ERROR); } + for_each_unit_reverse(unit) + unit->cell_exit(cell); pci_cell_exit(cell); arch_cell_destroy(cell); @@ -342,6 +346,7 @@ static int cell_create(struct per_cpu *cpu_data, unsigned long config_address) struct jailhouse_cell_desc *cfg; unsigned long cfg_total_size; struct cell *cell, *last; + struct unit *unit; void *cfg_mapping; int err; @@ -427,6 +432,15 @@ static int cell_create(struct per_cpu *cpu_data, unsigned long config_address) if (err) goto err_arch_destroy; + for_each_unit(unit) { + err = unit->cell_init(cell); + if (err) { + for_each_unit_before_reverse(unit, unit) + unit->cell_exit(cell); + goto err_pci_exit; + } + } + /* * Shrinking: the new cell's CPUs are parked, then removed from the root * cell, assigned to the new cell and get their stats cleared. @@ -488,6 +502,8 @@ err_destroy_cell: cell_destroy_internal(cpu_data, cell); /* cell_destroy_internal already calls arch_cell_destroy & cell_exit */ goto err_free_cell; +err_pci_exit: + pci_cell_exit(cell); err_arch_destroy: arch_cell_destroy(cell); err_cell_exit: @@ -694,9 +710,14 @@ static int cell_get_state(struct per_cpu *cpu_data, unsigned long id) */ void shutdown(void) { + struct unit *unit; + pci_prepare_handover(); arch_shutdown(); pci_shutdown(); + + for_each_unit_reverse(unit) + unit->shutdown(); } static int hypervisor_disable(struct per_cpu *cpu_data) diff --git a/hypervisor/hypervisor.lds.S b/hypervisor/hypervisor.lds.S index ea1abd330..3db6a8c4d 100644 --- a/hypervisor/hypervisor.lds.S +++ b/hypervisor/hypervisor.lds.S @@ -37,6 +37,12 @@ SECTIONS __init_array_end = .; } + .units : { + __unit_array_start = .; + *(.units); + __unit_array_end = .; + } + ARCH_SECTIONS /* The console section shall only contain the hypervisor console. This diff --git a/hypervisor/include/jailhouse/unit.h b/hypervisor/include/jailhouse/unit.h new file mode 100644 index 000000000..40e1cbfe2 --- /dev/null +++ b/hypervisor/include/jailhouse/unit.h @@ -0,0 +1,54 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka <[email protected]> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include <jailhouse/cell.h> + +struct unit { + const char *name; + + int (*init)(void); + void (*shutdown)(void); + + unsigned int (*mmio_count_regions)(struct cell *); + int (*cell_init)(struct cell *); + void (*cell_exit)(struct cell *); +}; + +#define DEFINE_UNIT(__name, __description) \ + static const struct unit unit_##__name \ + __attribute__((section(".units"), aligned(8), used)) = { \ + .name = __description, \ + .init = __name##_init, \ + .shutdown = __name##_shutdown, \ + .mmio_count_regions = __name##_mmio_count_regions, \ + .cell_init = __name##_cell_init, \ + .cell_exit = __name##_cell_exit, \ + } + +#define DEFINE_UNIT_SHUTDOWN_STUB(__name) \ + static void __name##_shutdown(void) { } + +#define DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(__name) \ + static unsigned int __name##_mmio_count_regions(struct cell *cell) \ + { return 0; } + +extern struct unit __unit_array_start[0], __unit_array_end[0]; + +#define for_each_unit(unit) \ + for ((unit) = __unit_array_start; (unit) < __unit_array_end; (unit)++) + +#define for_each_unit_before_reverse(unit, before_unit) \ + for ((unit) = before_unit - 1; (unit) >= __unit_array_start; \ + (unit)--) + +#define for_each_unit_reverse(unit) \ + for_each_unit_before_reverse(unit, __unit_array_end) diff --git a/hypervisor/mmio.c b/hypervisor/mmio.c index 7f3f8fad4..ec7cd40cf 100644 --- a/hypervisor/mmio.c +++ b/hypervisor/mmio.c @@ -15,6 +15,7 @@ #include <jailhouse/mmio.h> #include <jailhouse/paging.h> #include <jailhouse/printk.h> +#include <jailhouse/unit.h> #include <asm/percpu.h> /** @@ -28,11 +29,14 @@ int mmio_cell_init(struct cell *cell) { const struct jailhouse_memory *mem; + const struct unit *unit; unsigned int n; void *pages; cell->max_mmio_regions = arch_mmio_count_regions(cell) + pci_mmio_count_regions(cell); + for_each_unit(unit) + cell->max_mmio_regions += unit->mmio_count_regions(cell); for_each_mem_region(mem, cell->config, n) if (JAILHOUSE_MEMORY_IS_SUBPAGE(mem)) diff --git a/hypervisor/setup.c b/hypervisor/setup.c index 2924a1170..a7936c983 100644 --- a/hypervisor/setup.c +++ b/hypervisor/setup.c @@ -18,6 +18,7 @@ #include <jailhouse/paging.h> #include <jailhouse/control.h> #include <jailhouse/string.h> +#include <jailhouse/unit.h> #include <generated/version.h> #include <asm/spinlock.h> @@ -133,6 +134,7 @@ static void init_late(void) { unsigned int n, cpu, expected_cpus = 0; const struct jailhouse_memory *mem; + struct unit *unit; for_each_cpu(cpu, root_cell.cpu_set) expected_cpus++; @@ -149,6 +151,13 @@ static void init_late(void) if (error) return; + for_each_unit(unit) { + printk("Initializing unit: %s\n", unit->name); + error = unit->init(); + if (error) + return; + } + for_each_mem_region(mem, root_cell.config, n) { if (JAILHOUSE_MEMORY_IS_SUBPAGE(mem)) error = mmio_subpage_register(&root_cell, mem); -- 2.13.6 -- 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]. For more options, visit https://groups.google.com/d/optout.
