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
8 changes: 4 additions & 4 deletions kernel/multikernel/instance_dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
102 changes: 102 additions & 0 deletions tools/testing/selftests/multikernel/host_target_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Actual host restore; OF, allocation and mapping boundaries controlled. */
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

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;
}
13 changes: 13 additions & 0 deletions tools/testing/selftests/multikernel/host_target_test.sh
Original file line number Diff line number Diff line change
@@ -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"