linux/arch/x86/platform/intel-quark/imr_selftest.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/**
   3 * imr_selftest.c -- Intel Isolated Memory Region self-test driver
   4 *
   5 * Copyright(c) 2013 Intel Corporation.
   6 * Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie>
   7 *
   8 * IMR self test. The purpose of this module is to run a set of tests on the
   9 * IMR API to validate it's sanity. We check for overlapping, reserved
  10 * addresses and setup/teardown sanity.
  11 *
  12 */
  13
  14#include <asm-generic/sections.h>
  15#include <asm/cpu_device_id.h>
  16#include <asm/imr.h>
  17#include <linux/init.h>
  18#include <linux/mm.h>
  19#include <linux/types.h>
  20
  21#define SELFTEST KBUILD_MODNAME ": "
  22/**
  23 * imr_self_test_result - Print result string for self test.
  24 *
  25 * @res:        result code - true if test passed false otherwise.
  26 * @fmt:        format string.
  27 * ...          variadic argument list.
  28 */
  29static __printf(2, 3)
  30void __init imr_self_test_result(int res, const char *fmt, ...)
  31{
  32        va_list vlist;
  33
  34        /* Print pass/fail. */
  35        if (res)
  36                pr_info(SELFTEST "pass ");
  37        else
  38                pr_info(SELFTEST "fail ");
  39
  40        /* Print variable string. */
  41        va_start(vlist, fmt);
  42        vprintk(fmt, vlist);
  43        va_end(vlist);
  44
  45        /* Optional warning. */
  46        WARN(res == 0, "test failed");
  47}
  48#undef SELFTEST
  49
  50/**
  51 * imr_self_test
  52 *
  53 * Verify IMR self_test with some simple tests to verify overlap,
  54 * zero sized allocations and 1 KiB sized areas.
  55 *
  56 */
  57static void __init imr_self_test(void)
  58{
  59        phys_addr_t base  = virt_to_phys(&_text);
  60        size_t size = virt_to_phys(&__end_rodata) - base;
  61        const char *fmt_over = "overlapped IMR @ (0x%08lx - 0x%08lx)\n";
  62        int ret;
  63
  64        /* Test zero zero. */
  65        ret = imr_add_range(0, 0, 0, 0);
  66        imr_self_test_result(ret < 0, "zero sized IMR\n");
  67
  68        /* Test exact overlap. */
  69        ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
  70        imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
  71
  72        /* Test overlap with base inside of existing. */
  73        base += size - IMR_ALIGN;
  74        ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
  75        imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
  76
  77        /* Test overlap with end inside of existing. */
  78        base -= size + IMR_ALIGN * 2;
  79        ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
  80        imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
  81
  82        /* Test that a 1 KiB IMR @ zero with read/write all will bomb out. */
  83        ret = imr_add_range(0, IMR_ALIGN, IMR_READ_ACCESS_ALL,
  84                            IMR_WRITE_ACCESS_ALL);
  85        imr_self_test_result(ret < 0, "1KiB IMR @ 0x00000000 - access-all\n");
  86
  87        /* Test that a 1 KiB IMR @ zero with CPU only will work. */
  88        ret = imr_add_range(0, IMR_ALIGN, IMR_CPU, IMR_CPU);
  89        imr_self_test_result(ret >= 0, "1KiB IMR @ 0x00000000 - cpu-access\n");
  90        if (ret >= 0) {
  91                ret = imr_remove_range(0, IMR_ALIGN);
  92                imr_self_test_result(ret == 0, "teardown - cpu-access\n");
  93        }
  94
  95        /* Test 2 KiB works. */
  96        size = IMR_ALIGN * 2;
  97        ret = imr_add_range(0, size, IMR_READ_ACCESS_ALL, IMR_WRITE_ACCESS_ALL);
  98        imr_self_test_result(ret >= 0, "2KiB IMR @ 0x00000000\n");
  99        if (ret >= 0) {
 100                ret = imr_remove_range(0, size);
 101                imr_self_test_result(ret == 0, "teardown 2KiB\n");
 102        }
 103}
 104
 105static const struct x86_cpu_id imr_ids[] __initconst = {
 106        { X86_VENDOR_INTEL, 5, 9 },     /* Intel Quark SoC X1000. */
 107        {}
 108};
 109
 110/**
 111 * imr_self_test_init - entry point for IMR driver.
 112 *
 113 * return: -ENODEV for no IMR support 0 if good to go.
 114 */
 115static int __init imr_self_test_init(void)
 116{
 117        if (x86_match_cpu(imr_ids))
 118                imr_self_test();
 119        return 0;
 120}
 121
 122/**
 123 * imr_self_test_exit - exit point for IMR code.
 124 *
 125 * return:
 126 */
 127device_initcall(imr_self_test_init);
 128