Use atomic memory read/write functions in tests.
This ensures compiler optimisations won't interfere with the tests.
This commit is contained in:
parent
eb58a63ad4
commit
11c0c6c2f5
|
@ -0,0 +1,60 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef MEMRW64_H
|
||||
#define MEMRW64_H
|
||||
/*
|
||||
* Provides some 64-bit memory access functions. These stop the compiler
|
||||
* optimizing accesses which need to be ordered and atomic. Mostly used
|
||||
* for accessing memory-mapped hardware registers.
|
||||
*
|
||||
* Copyright (C) 2021 Martin Whitaker.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Reads and returns the value stored in the 64-bit memory location pointed
|
||||
* to by ptr.
|
||||
*/
|
||||
static inline uint64_t read64(const volatile uint64_t *ptr)
|
||||
{
|
||||
uint64_t val;
|
||||
__asm__ __volatile__(
|
||||
"movq %1, %0"
|
||||
: "=r" (val)
|
||||
: "m" (*ptr)
|
||||
: "memory"
|
||||
);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes val to the 64-bit memory location pointed to by ptr.
|
||||
*/
|
||||
static inline void write64(const volatile uint64_t *ptr, uint64_t val)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"movq %1, %0"
|
||||
:
|
||||
: "m" (*ptr),
|
||||
"r" (val)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes val to the 64-bit memory location pointed to by ptr. Reads it
|
||||
* back (and discards it) to ensure the write is complete.
|
||||
*/
|
||||
static inline void flush64(const volatile uint64_t *ptr, uint64_t val)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"movl %1, %0\n"
|
||||
"movl %0, %1"
|
||||
:
|
||||
: "m" (*ptr),
|
||||
"r" (val)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif // MEMRW64_H
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -56,7 +56,7 @@ int test_addr_walk1(int my_vcpu)
|
|||
break;
|
||||
}
|
||||
testword_t expect = invert ^ (testword_t)p1;
|
||||
*p1 = expect;
|
||||
write_word(p1, expect);
|
||||
|
||||
// Walking one on our second address.
|
||||
uintptr_t mask2 = sizeof(testword_t);
|
||||
|
@ -69,12 +69,12 @@ int test_addr_walk1(int my_vcpu)
|
|||
if (p2 > (testword_t *)pe) {
|
||||
break;
|
||||
}
|
||||
*p2 = ~invert ^ (testword_t)p2;
|
||||
write_word(p2, ~invert ^ (testword_t)p2);
|
||||
|
||||
testword_t actual = *p1;
|
||||
testword_t actual = read_word(p1);
|
||||
if (unlikely(actual != expect)) {
|
||||
addr_error(p1, p2, expect, actual);
|
||||
*p1 = expect; // recover from error
|
||||
write_word(p1, expect); // recover from error
|
||||
}
|
||||
} while (mask2);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -59,7 +59,7 @@ static int pattern_fill(int my_vcpu, testword_t pattern)
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
*p = pattern;
|
||||
write_word(p, pattern);
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
@ -95,7 +95,7 @@ static int pattern_check(int my_vcpu, testword_t pattern)
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != pattern)) {
|
||||
data_error(p, pattern, actual, true);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -60,22 +60,22 @@ int test_block_move(int my_vcpu, int iterations)
|
|||
testword_t pattern1 = 1;
|
||||
do {
|
||||
testword_t pattern2 = ~pattern1;
|
||||
p[ 0] = pattern1;
|
||||
p[ 1] = pattern1;
|
||||
p[ 2] = pattern1;
|
||||
p[ 3] = pattern1;
|
||||
p[ 4] = pattern2;
|
||||
p[ 5] = pattern2;
|
||||
p[ 6] = pattern1;
|
||||
p[ 7] = pattern1;
|
||||
p[ 8] = pattern1;
|
||||
p[ 9] = pattern1;
|
||||
p[10] = pattern2;
|
||||
p[11] = pattern2;
|
||||
p[12] = pattern1;
|
||||
p[13] = pattern1;
|
||||
p[14] = pattern2;
|
||||
p[15] = pattern2;
|
||||
write_word(p + 0, pattern1);
|
||||
write_word(p + 1, pattern1);
|
||||
write_word(p + 2, pattern1);
|
||||
write_word(p + 3, pattern1);
|
||||
write_word(p + 4, pattern2);
|
||||
write_word(p + 5, pattern2);
|
||||
write_word(p + 6, pattern1);
|
||||
write_word(p + 7, pattern1);
|
||||
write_word(p + 8, pattern1);
|
||||
write_word(p + 9, pattern1);
|
||||
write_word(p + 10, pattern2);
|
||||
write_word(p + 11, pattern2);
|
||||
write_word(p + 12, pattern1);
|
||||
write_word(p + 13, pattern1);
|
||||
write_word(p + 14, pattern2);
|
||||
write_word(p + 15, pattern2);
|
||||
pattern1 = pattern1 << 1 | pattern1 >> (TESTWORD_WIDTH - 1); // rotate left
|
||||
} while (p <= (pe - 16) && (p += 16)); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
|
@ -219,8 +219,10 @@ int test_block_move(int my_vcpu, int iterations)
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
if (unlikely(p[0] != p[1])) {
|
||||
data_error(p, p[0], p[1], false);
|
||||
testword_t p0 = read_word(p + 0);
|
||||
testword_t p1 = read_word(p + 1);
|
||||
if (unlikely(p0 != p1)) {
|
||||
data_error(p, p0, p1, false);
|
||||
}
|
||||
} while (p <= (pe - 2) && (p += 2)); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -59,7 +59,7 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
*p = pattern1;
|
||||
write_word(p, pattern1);
|
||||
} while (p <= (pe - n) && (p += n)); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
@ -92,7 +92,7 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
|
|||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
if (k != offset) {
|
||||
*p = pattern2;
|
||||
write_word(p, pattern2);
|
||||
}
|
||||
k++;
|
||||
if (k == n) {
|
||||
|
@ -129,7 +129,7 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != pattern1)) {
|
||||
data_error(p, pattern1, actual, true);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -83,7 +83,7 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
|
|||
#endif
|
||||
#else
|
||||
do {
|
||||
*p = pattern1;
|
||||
write_word(p, pattern1);
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
#endif
|
||||
do_tick(my_vcpu);
|
||||
|
@ -116,11 +116,11 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != pattern1)) {
|
||||
data_error(p, pattern1, actual, true);
|
||||
}
|
||||
*p = pattern2;
|
||||
write_word(p, pattern2);
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
@ -149,11 +149,11 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != pattern2)) {
|
||||
data_error(p, pattern2, actual, true);
|
||||
}
|
||||
*p = pattern1;
|
||||
write_word(p, pattern1);
|
||||
} while (p-- > ps); // test before decrement in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -69,7 +69,7 @@ int test_mov_inv_random(int my_vcpu)
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
*p = random(my_vcpu);
|
||||
write_word(p, random(my_vcpu));
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
@ -104,11 +104,11 @@ int test_mov_inv_random(int my_vcpu)
|
|||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t expect = random(my_vcpu) ^ invert;
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != expect)) {
|
||||
data_error(p, expect, actual, true);
|
||||
}
|
||||
*p = ~expect;
|
||||
write_word(p, ~expect);
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -60,7 +60,7 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
*p = inverse ? ~pattern : pattern;
|
||||
write_word(p, inverse ? ~pattern : pattern);
|
||||
pattern = pattern << 1 | pattern >> (TESTWORD_WIDTH - 1); // rotate left
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
|
@ -96,11 +96,11 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
|
|||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t expect = inverse ? ~pattern : pattern;
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != expect)) {
|
||||
data_error(p, expect, actual, true);
|
||||
}
|
||||
*p = ~expect;
|
||||
write_word(p, ~expect);
|
||||
pattern = pattern << 1 | pattern >> (TESTWORD_WIDTH - 1); // rotate left
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
|
@ -132,11 +132,11 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
|
|||
do {
|
||||
pattern = pattern >> 1 | pattern << (TESTWORD_WIDTH - 1); // rotate right
|
||||
testword_t expect = inverse ? pattern : ~pattern;
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != expect)) {
|
||||
data_error(p, expect, actual, true);
|
||||
}
|
||||
*p = ~expect;
|
||||
write_word(p, ~expect);
|
||||
} while (p-- > ps); // test before decrement in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
||||
//
|
||||
// Derived from an extract of memtest86+ test.c:
|
||||
//
|
||||
|
@ -58,7 +58,7 @@ static int pattern_fill(int my_vcpu, testword_t offset)
|
|||
}
|
||||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
*p = (testword_t)p + offset;
|
||||
write_word(p, (testword_t)p + offset);
|
||||
} while (p++ < pe); // test before increment in case pointer overflows
|
||||
do_tick(my_vcpu);
|
||||
BAILOUT;
|
||||
|
@ -96,7 +96,7 @@ static int pattern_check(int my_vcpu, testword_t offset)
|
|||
test_addr[my_vcpu] = (uintptr_t)p;
|
||||
do {
|
||||
testword_t expect = (testword_t)p + offset;
|
||||
testword_t actual = *p;
|
||||
testword_t actual = read_word(p);
|
||||
if (unlikely(actual != expect)) {
|
||||
data_error(p, expect, actual, true);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Provides some common definitions and helper functions for the memory
|
||||
* tests.
|
||||
*
|
||||
* Copyright (C) 2020 Martin Whitaker.
|
||||
* Copyright (C) 2020-2021 Martin Whitaker.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
@ -13,6 +13,19 @@
|
|||
|
||||
#include "test.h"
|
||||
|
||||
/*
|
||||
* Test word atomic read and write functions.
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
#include "memrw64.h"
|
||||
#define read_word read64
|
||||
#define write_word write64
|
||||
#else
|
||||
#include "memrw32.h"
|
||||
#define read_word read32
|
||||
#define write_word write32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A wrapper for guiding branch prediction.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue