diff --git a/kernel/multikernel/instance_dt.c b/kernel/multikernel/instance_dt.c index 8503733372da18..4607edc44a453d 100644 --- a/kernel/multikernel/instance_dt.c +++ b/kernel/multikernel/instance_dt.c @@ -319,14 +319,14 @@ static int __init mk_restore_host_instance(void) phys_addr_t host_ipi_phys; u32 host_ipi_pages; size_t host_ipi_size; - u64 host_ipi_cpu; + u64 host_ipi_cpu = 0; - if (!mk_chosen_ring("host-ipi", &host_ipi_phys, &host_ipi_pages) || - of_property_read_u64(of_chosen, "multikernel,host-ipi-cpu", - &host_ipi_cpu)) { + if (!mk_chosen_ring("host-ipi", &host_ipi_phys, &host_ipi_pages)) { pr_warn("No host IPI buffer in the boot tree (spawn won't be able to send to host)\n"); return -ENOENT; } + /* Older hosts ring physical CPU 0 and do not describe a target. */ + of_property_read_u64(of_chosen, "multikernel,host-ipi-cpu", &host_ipi_cpu); host_ipi_size = (size_t)host_ipi_pages << PAGE_SHIFT; hi = mk_instance_alloc(0, "host"); diff --git a/tools/testing/selftests/multikernel/host_target_test.c b/tools/testing/selftests/multikernel/host_target_test.c new file mode 100644 index 00000000000000..7e0f047b1c3246 --- /dev/null +++ b/tools/testing/selftests/multikernel/host_target_test.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Actual host restore; OF, allocation and mapping boundaries controlled. */ +#include +#include +#include +#include +#include +#include + +typedef uint64_t u64; +typedef uint32_t u32; +typedef u64 phys_addr_t; +#define __init +#define PAGE_SHIFT 12 +#define MEMREMAP_WB 1 +#define MK_STATE_ACTIVE 3 +#define pr_warn(...) do { } while (0) +#define pr_err(...) do { } while (0) +#define pr_info(...) do { } while (0) +struct mk_instance { + u64 ipi_target, ipi_phys, pool_slot_phys; + u32 ipi_pages; + void *ipi_data; + int state; +}; +static struct mk_instance record, *host_instance; +static void *of_chosen = &record; +static bool has_ring = true, has_cpu = true, fail_alloc, fail_map, fail_publish; +static u64 target = UINT64_C(0x100000001); +static unsigned int checks, failures, frees, unmaps; + +static bool mk_chosen_ring(const char *name, phys_addr_t *phys, u32 *pages) +{ + assert(!strcmp(name, "host-ipi")); + *phys = 0x90000000; + *pages = 2; + return has_ring; +} +static int of_property_read_u64(void *node, const char *name, u64 *value) +{ + assert(node == of_chosen); + if (strcmp(name, "multikernel,host-ipi-cpu") || !has_cpu) + return -EINVAL; + *value = target; + return 0; +} +static struct mk_instance *mk_instance_alloc(int id, const char *name) +{ + assert(id == 0 && !strcmp(name, "host")); + memset(&record, 0, sizeof(record)); + return fail_alloc ? NULL : &record; +} +static void *memremap(phys_addr_t phys, size_t size, int mode) +{ + assert(phys == 0x90000000 && size == 8192 && mode == MEMREMAP_WB); + return fail_map ? NULL : &record; +} +static void memunmap(void *addr) { assert(addr == &record); unmaps++; } +static int mk_instance_publish(struct mk_instance *p) +{ + assert(p == &record); + return fail_publish ? -ENOMEM : 0; +} +static void mk_instance_set_state(struct mk_instance *p, int state) { p->state = state; } +static void mk_instance_free(struct mk_instance *p) { assert(p == &record); frees++; } +#include "host-production.h" + +static void expect(const char *name, int got, int want) +{ + checks++; + if (got != want) { + fprintf(stderr, "FAIL %s: %d != %d\n", name, got, want); + failures++; + } +} + +int main(void) +{ + expect("explicit sparse physical target restores", mk_restore_host_instance(), 0); + expect("64-bit physical target preserved", record.ipi_target == target, true); + has_cpu = false; + host_instance = NULL; + expect("old host ring without CPU property restores", mk_restore_host_instance(), 0); + expect("old host uses physical CPU zero", host_instance && !host_instance->ipi_target, true); + has_ring = false; + expect("missing ring still refuses restore", mk_restore_host_instance(), -ENOENT); + has_ring = true; + has_cpu = true; + fail_alloc = true; + expect("allocation failure", mk_restore_host_instance(), -ENOMEM); + fail_alloc = false; + fail_map = true; + expect("mapping failure", mk_restore_host_instance(), -ENOMEM); + expect("mapping failure drops allocation", frees, 1); + fail_map = false; + fail_publish = true; + expect("publication failure", mk_restore_host_instance(), -ENOMEM); + expect("publication failure unmaps", unmaps, 1); + expect("publication failure drops allocation", frees, 2); + printf("Host target: %u checks, %u failures\n", checks, failures); + return failures ? 1 : 0; +} diff --git a/tools/testing/selftests/multikernel/host_target_test.sh b/tools/testing/selftests/multikernel/host_target_test.sh new file mode 100644 index 00000000000000..102cc8f7c634be --- /dev/null +++ b/tools/testing/selftests/multikernel/host_target_test.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +set -eu +test_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +src=$(CDPATH= cd -- "$test_dir/../../../.." && pwd) +build=$(mktemp -d "${TMPDIR:-/tmp}/mk-host-target.XXXXXX") +trap 'rm -rf -- "$build"' EXIT HUP INT TERM +awk '/^static int __init mk_restore_host_instance\(/ { copy = 1 } + copy { print } + copy && /^}/ { copy = 0 }' "$src/kernel/multikernel/instance_dt.c" > "$build/host-production.h" +${CC:-cc} ${CFLAGS:-} -std=gnu11 -Wall -Wextra -Werror -I"$build" \ + "$test_dir/host_target_test.c" -o "$build/host_target_test" +"$build/host_target_test"