/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Storage Key migration tests
 *
 * There are two variants of this test:
 * - sequential: set storage keys on some pages, migrates the VM and then
 *   verifies that the storage keys are still as we expect.
 * - parallel: start migration and set and check storage keys on some
 *   pages while migration is in process.
 *
 * Copyright IBM Corp. 2022
 *
 * Authors:
 *  Nico Boehr <nrb@linux.ibm.com>
 */

#include <libcflat.h>
#include <migrate.h>
#include <asm/facility.h>
#include <asm/page.h>
#include <asm/mem.h>
#include <asm/barrier.h>
#include <hardware.h>
#include <smp.h>

struct verify_result {
	bool verify_failed;
	union skey expected_key;
	union skey actual_key;
	unsigned long page_mismatch_idx;
	unsigned long page_mismatch_addr;
};

#define NUM_PAGES 128
static uint8_t pagebuf[NUM_PAGES * PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));

static struct verify_result result;

static unsigned int thread_iters;
static bool thread_should_exit;
static bool thread_exited;

static enum {
	TEST_INVALID,
	TEST_SEQUENTIAL,
	TEST_PARALLEL
} arg_test_to_run;

/*
 * Set storage key test pattern on pagebuf with a seed for the storage keys.
 *
 * Each page's storage key is generated by taking the page's index in pagebuf,
 * XOR-ing that with the given seed and then multipling the result with two.
 *
 * Only the lower seven bits of the seed are considered.
 */
static void set_test_pattern(unsigned char seed)
{
	unsigned char key_to_set;
	unsigned long i;

	for (i = 0; i < NUM_PAGES; i++) {
		/*
		 * Storage keys are 7 bit, lowest bit is always returned as zero
		 * by iske.
		 * This loop will set all 7 bits which means we set fetch
		 * protection as well as reference and change indication for
		 * some keys.
		 */
		key_to_set = (i ^ seed) * 2;
		set_storage_key(pagebuf + i * PAGE_SIZE, key_to_set, 1);
	}
}

/*
 * Verify storage keys on pagebuf.
 * Storage keys must have been set by set_test_pattern on pagebuf before.
 * set_test_pattern must have been called with the same seed value.
 *
 * If storage keys match the expected result, will return a verify_result
 * with verify_failed false. All other fields are then invalid.
 * If there is a mismatch, returned struct will have verify_failed true and will
 * be filled with the details on the first mismatch encountered.
 */
static struct verify_result verify_test_pattern(unsigned char seed)
{
	union skey expected_key, actual_key;
	struct verify_result result = {
		.verify_failed = true
	};
	uint8_t *cur_page;
	unsigned long i;

	for (i = 0; i < NUM_PAGES; i++) {
		cur_page = pagebuf + i * PAGE_SIZE;
		actual_key.val = get_storage_key(cur_page);
		expected_key.val = (i ^ seed) * 2;

		/*
		 * The PoP neither gives a guarantee that the reference bit is
		 * accurate nor that it won't be cleared by hardware. Hence we
		 * don't rely on it and just clear the bits to avoid compare
		 * errors.
		 */
		actual_key.str.rf = 0;
		expected_key.str.rf = 0;

		if (actual_key.val != expected_key.val) {
			result.expected_key.val = expected_key.val;
			result.actual_key.val = actual_key.val;
			result.page_mismatch_idx = i;
			result.page_mismatch_addr = (unsigned long)cur_page;
			return result;
		}
	}

	result.verify_failed = false;
	return result;
}

static void report_verify_result(const struct verify_result * result)
{
	if (result->verify_failed)
		report_fail("page skey mismatch: first page idx = %lu, addr = 0x%lx, "
			    "expected_key = 0x%02x, actual_key = 0x%02x",
			    result->page_mismatch_idx, result->page_mismatch_addr,
			    result->expected_key.val, result->actual_key.val);
	else
		report_pass("skeys match");
}

static void test_skey_migration_sequential(void)
{
	report_prefix_push("sequential");

	set_test_pattern(0);

	migrate_once();

	result = verify_test_pattern(0);
	report_verify_result(&result);

	report_prefix_pop();
}

static void set_skeys_thread(void)
{
	while (!READ_ONCE(thread_should_exit)) {
		set_test_pattern(thread_iters);

		result = verify_test_pattern(thread_iters);

		/*
		 * Always increment even if the verify fails. This ensures primary CPU knows where
		 * we left off and can do an additional verify round after migration finished.
		 */
		thread_iters++;

		if (result.verify_failed)
			break;
	}

	WRITE_ONCE(thread_exited, 1);
}

static void test_skey_migration_parallel(void)
{
	report_prefix_push("parallel");

	if (smp_query_num_cpus() == 1) {
		report_skip("need at least 2 cpus for this test");
		goto error;
	}

	smp_cpu_setup(1, PSW_WITH_CUR_MASK(set_skeys_thread));

	migrate_once();

	WRITE_ONCE(thread_should_exit, 1);

	while (!READ_ONCE(thread_exited))
		;

	/* Ensure we read result and thread_iters below from memory after thread exited */
	mb();
	report_info("thread completed %u iterations", thread_iters);

	report_prefix_push("during migration");
	report_verify_result(&result);
	report_prefix_pop();

	/*
	 * Verification of skeys occurs on the thread. We don't know if we
	 * were still migrating during the verification.
	 * To be sure, make another verification round after the migration
	 * finished to catch skeys which might not have been migrated
	 * correctly.
	 */
	report_prefix_push("after migration");
	assert(thread_iters > 0);
	result = verify_test_pattern(thread_iters - 1);
	report_verify_result(&result);
	report_prefix_pop();

error:
	report_prefix_pop();
}

static void print_usage(void)
{
	report_info("Usage: migration-skey [--parallel|--sequential]");
}

static void parse_args(int argc, char **argv)
{
	if (argc < 2) {
		/* default to sequential since it only needs one cpu */
		arg_test_to_run = TEST_SEQUENTIAL;
		return;
	}

	if (!strcmp("--parallel", argv[1]))
		arg_test_to_run = TEST_PARALLEL;
	else if (!strcmp("--sequential", argv[1]))
		arg_test_to_run = TEST_SEQUENTIAL;
	else
		arg_test_to_run = TEST_INVALID;
}

int main(int argc, char **argv)
{
	report_prefix_push("migration-skey");

	if (test_facility(169)) {
		report_skip("storage key removal facility is active");
		goto error;
	}

	parse_args(argc, argv);

	switch (arg_test_to_run) {
	case TEST_SEQUENTIAL:
		test_skey_migration_sequential();
		break;
	case TEST_PARALLEL:
		test_skey_migration_parallel();
		break;
	default:
		print_usage();
		break;
	}

error:
	migrate_once();
	report_prefix_pop();
	return report_summary();
}
