Use atomic memory read/write functions in tests.

This ensures compiler optimisations won't interfere with the tests.
This commit is contained in:
Martin Whitaker 2021-12-23 09:46:01 +00:00
parent eb58a63ad4
commit 11c0c6c2f5
10 changed files with 126 additions and 51 deletions

60
system/memrw64.h Normal file
View File

@ -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

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // Derived from an extract of memtest86+ test.c:
// //
@ -56,7 +56,7 @@ int test_addr_walk1(int my_vcpu)
break; break;
} }
testword_t expect = invert ^ (testword_t)p1; testword_t expect = invert ^ (testword_t)p1;
*p1 = expect; write_word(p1, expect);
// Walking one on our second address. // Walking one on our second address.
uintptr_t mask2 = sizeof(testword_t); uintptr_t mask2 = sizeof(testword_t);
@ -69,12 +69,12 @@ int test_addr_walk1(int my_vcpu)
if (p2 > (testword_t *)pe) { if (p2 > (testword_t *)pe) {
break; 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)) { if (unlikely(actual != expect)) {
addr_error(p1, p2, expect, actual); addr_error(p1, p2, expect, actual);
*p1 = expect; // recover from error write_word(p1, expect); // recover from error
} }
} while (mask2); } while (mask2);

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
*p = pattern; write_word(p, pattern);
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; BAILOUT;
@ -95,7 +95,7 @@ static int pattern_check(int my_vcpu, testword_t pattern)
} }
test_addr[my_vcpu] = (uintptr_t)p; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != pattern)) { if (unlikely(actual != pattern)) {
data_error(p, pattern, actual, true); data_error(p, pattern, actual, true);
} }

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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; testword_t pattern1 = 1;
do { do {
testword_t pattern2 = ~pattern1; testword_t pattern2 = ~pattern1;
p[ 0] = pattern1; write_word(p + 0, pattern1);
p[ 1] = pattern1; write_word(p + 1, pattern1);
p[ 2] = pattern1; write_word(p + 2, pattern1);
p[ 3] = pattern1; write_word(p + 3, pattern1);
p[ 4] = pattern2; write_word(p + 4, pattern2);
p[ 5] = pattern2; write_word(p + 5, pattern2);
p[ 6] = pattern1; write_word(p + 6, pattern1);
p[ 7] = pattern1; write_word(p + 7, pattern1);
p[ 8] = pattern1; write_word(p + 8, pattern1);
p[ 9] = pattern1; write_word(p + 9, pattern1);
p[10] = pattern2; write_word(p + 10, pattern2);
p[11] = pattern2; write_word(p + 11, pattern2);
p[12] = pattern1; write_word(p + 12, pattern1);
p[13] = pattern1; write_word(p + 13, pattern1);
p[14] = pattern2; write_word(p + 14, pattern2);
p[15] = pattern2; write_word(p + 15, pattern2);
pattern1 = pattern1 << 1 | pattern1 >> (TESTWORD_WIDTH - 1); // rotate left pattern1 = pattern1 << 1 | pattern1 >> (TESTWORD_WIDTH - 1); // rotate left
} while (p <= (pe - 16) && (p += 16)); // test before increment in case pointer overflows } while (p <= (pe - 16) && (p += 16)); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
@ -219,8 +219,10 @@ int test_block_move(int my_vcpu, int iterations)
} }
test_addr[my_vcpu] = (uintptr_t)p; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
if (unlikely(p[0] != p[1])) { testword_t p0 = read_word(p + 0);
data_error(p, p[0], p[1], false); 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 } while (p <= (pe - 2) && (p += 2)); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
*p = pattern1; write_word(p, pattern1);
} while (p <= (pe - n) && (p += n)); // test before increment in case pointer overflows } while (p <= (pe - n) && (p += n)); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
if (k != offset) { if (k != offset) {
*p = pattern2; write_word(p, pattern2);
} }
k++; k++;
if (k == n) { 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != pattern1)) { if (unlikely(actual != pattern1)) {
data_error(p, pattern1, actual, true); data_error(p, pattern1, actual, true);
} }

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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 #endif
#else #else
do { do {
*p = pattern1; write_word(p, pattern1);
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
#endif #endif
do_tick(my_vcpu); 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != pattern1)) { if (unlikely(actual != pattern1)) {
data_error(p, pattern1, actual, true); data_error(p, pattern1, actual, true);
} }
*p = pattern2; write_word(p, pattern2);
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != pattern2)) { if (unlikely(actual != pattern2)) {
data_error(p, pattern2, actual, true); data_error(p, pattern2, actual, true);
} }
*p = pattern1; write_word(p, pattern1);
} while (p-- > ps); // test before decrement in case pointer overflows } while (p-- > ps); // test before decrement in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; BAILOUT;

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
*p = random(my_vcpu); write_word(p, random(my_vcpu));
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; BAILOUT;
@ -104,11 +104,11 @@ int test_mov_inv_random(int my_vcpu)
test_addr[my_vcpu] = (uintptr_t)p; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t expect = random(my_vcpu) ^ invert; testword_t expect = random(my_vcpu) ^ invert;
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != expect)) { if (unlikely(actual != expect)) {
data_error(p, expect, actual, true); data_error(p, expect, actual, true);
} }
*p = ~expect; write_word(p, ~expect);
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; BAILOUT;

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
*p = inverse ? ~pattern : pattern; write_word(p, inverse ? ~pattern : pattern);
pattern = pattern << 1 | pattern >> (TESTWORD_WIDTH - 1); // rotate left pattern = pattern << 1 | pattern >> (TESTWORD_WIDTH - 1); // rotate left
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t expect = inverse ? ~pattern : pattern; testword_t expect = inverse ? ~pattern : pattern;
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != expect)) { if (unlikely(actual != expect)) {
data_error(p, expect, actual, true); data_error(p, expect, actual, true);
} }
*p = ~expect; write_word(p, ~expect);
pattern = pattern << 1 | pattern >> (TESTWORD_WIDTH - 1); // rotate left pattern = pattern << 1 | pattern >> (TESTWORD_WIDTH - 1); // rotate left
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
@ -132,11 +132,11 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
do { do {
pattern = pattern >> 1 | pattern << (TESTWORD_WIDTH - 1); // rotate right pattern = pattern >> 1 | pattern << (TESTWORD_WIDTH - 1); // rotate right
testword_t expect = inverse ? pattern : ~pattern; testword_t expect = inverse ? pattern : ~pattern;
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != expect)) { if (unlikely(actual != expect)) {
data_error(p, expect, actual, true); data_error(p, expect, actual, true);
} }
*p = ~expect; write_word(p, ~expect);
} while (p-- > ps); // test before decrement in case pointer overflows } while (p-- > ps); // test before decrement in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; BAILOUT;

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0 // 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: // 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; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
*p = (testword_t)p + offset; write_word(p, (testword_t)p + offset);
} while (p++ < pe); // test before increment in case pointer overflows } while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu); do_tick(my_vcpu);
BAILOUT; BAILOUT;
@ -96,7 +96,7 @@ static int pattern_check(int my_vcpu, testword_t offset)
test_addr[my_vcpu] = (uintptr_t)p; test_addr[my_vcpu] = (uintptr_t)p;
do { do {
testword_t expect = (testword_t)p + offset; testword_t expect = (testword_t)p + offset;
testword_t actual = *p; testword_t actual = read_word(p);
if (unlikely(actual != expect)) { if (unlikely(actual != expect)) {
data_error(p, expect, actual, true); data_error(p, expect, actual, true);
} }

View File

@ -5,7 +5,7 @@
* Provides some common definitions and helper functions for the memory * Provides some common definitions and helper functions for the memory
* tests. * tests.
* *
* Copyright (C) 2020 Martin Whitaker. * Copyright (C) 2020-2021 Martin Whitaker.
*/ */
#include <stddef.h> #include <stddef.h>
@ -13,6 +13,19 @@
#include "test.h" #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. * A wrapper for guiding branch prediction.
*/ */