mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2024-12-02 11:59:08 -06:00
239 lines
7.0 KiB
C
239 lines
7.0 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
// Copyright (C) 2020 Martin Whitaker.
|
||
|
//
|
||
|
// Derived from an extract of memtest86+ main.c:
|
||
|
//
|
||
|
// MemTest86+ V5 Specific code (GPL V2.0)
|
||
|
// By Samuel DEMEULEMEESTER, sdemeule@memtest.org
|
||
|
// http://www.canardpc.com - http://www.memtest.org
|
||
|
// ------------------------------------------------
|
||
|
// main.c - MemTest-86 Version 3.5
|
||
|
//
|
||
|
// Released under version 2 of the Gnu Public License.
|
||
|
// By Chris Brady
|
||
|
|
||
|
#include <stdbool.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#include "boot.h"
|
||
|
|
||
|
#include "cache.h"
|
||
|
#include "cpuid.h"
|
||
|
#include "tsc.h"
|
||
|
#include "vmem.h"
|
||
|
|
||
|
#include "barrier.h"
|
||
|
|
||
|
#include "config.h"
|
||
|
#include "display.h"
|
||
|
#include "test.h"
|
||
|
|
||
|
#include "test_funcs.h"
|
||
|
#include "test_helper.h"
|
||
|
|
||
|
#include "tests.h"
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Constants
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
#ifndef TRACE_BARRIERS
|
||
|
#define TRACE_BARRIERS 0
|
||
|
#endif
|
||
|
|
||
|
#define MODULO_N 20
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Public Variables
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
test_pattern_t test_list[NUM_TEST_PATTERNS] = {
|
||
|
// ena, cpu, stgs, itrs, errs, description
|
||
|
{ true, SEQ, 1, 6, 0, "[Address test, walking ones, no cache] "},
|
||
|
{ true, SEQ, 1, 6, 0, "[Address test, own address in window] "},
|
||
|
{ true, SEQ, 2, 6, 0, "[Address test, own address + window] "},
|
||
|
{ true, PAR, 1, 6, 0, "[Moving inversions, 1s & 0s] "},
|
||
|
{ true, PAR, 1, 3, 0, "[Moving inversions, 8 bit pattern] "},
|
||
|
{ true, PAR, 1, 30, 0, "[Moving inversions, random pattern] "},
|
||
|
#if TESTWORD_WIDTH > 32
|
||
|
{ true, PAR, 1, 3, 0, "[Moving inversions, 64 bit pattern] "},
|
||
|
#else
|
||
|
{ true, PAR, 1, 3, 0, "[Moving inversions, 32 bit pattern] "},
|
||
|
#endif
|
||
|
{ true, PAR, 1, 81, 0, "[Block move] "},
|
||
|
{ true, PAR, 1, 48, 0, "[Random number sequence] "},
|
||
|
{ true, PAR, 1, 6, 0, "[Modulo 20, random pattern] "},
|
||
|
{ true, ONE, 6, 240, 0, "[Bit fade test, 2 patterns] "},
|
||
|
};
|
||
|
|
||
|
int ticks_per_pass[NUM_PASS_TYPES];
|
||
|
int ticks_per_test[NUM_PASS_TYPES][NUM_TEST_PATTERNS];
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Public Functions
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
#define BARRIER \
|
||
|
if (my_vcpu >= 0) { \
|
||
|
if (TRACE_BARRIERS) { \
|
||
|
trace(my_vcpu, "Run barrier wait at %s line %i", __FILE__, __LINE__); \
|
||
|
} \
|
||
|
barrier_wait(run_barrier); \
|
||
|
}
|
||
|
|
||
|
int run_test(int my_vcpu, int test, int stage, int iterations)
|
||
|
{
|
||
|
if (my_vcpu == master_vcpu) {
|
||
|
if ((uintptr_t)&_start > LOW_LOAD_ADDR) {
|
||
|
// Relocated so we need to test all selected lower memory.
|
||
|
vm_map[0].start = first_word_mapping(pm_limit_lower);
|
||
|
|
||
|
// For USB_WORKAROUND.
|
||
|
if (vm_map[0].start < (uintptr_t *)0x500) {
|
||
|
vm_map[0].start = (uintptr_t *)0x500;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Update display of memory segments being tested */
|
||
|
uintptr_t pb = page_of(vm_map[0].start);
|
||
|
uintptr_t pe = page_of(vm_map[vm_map_size - 1].end) + 1;
|
||
|
display_test_addresses(pb << 2, pe << 2, num_pages_to_test << 2);
|
||
|
}
|
||
|
BARRIER;
|
||
|
|
||
|
int ticks = 0;
|
||
|
|
||
|
switch (test) {
|
||
|
// Address test, walking ones.
|
||
|
case 0:
|
||
|
cache_off();
|
||
|
ticks += test_addr_walk1(my_vcpu);
|
||
|
cache_on();
|
||
|
BAILOUT;
|
||
|
break;
|
||
|
|
||
|
// Address test, own address in window.
|
||
|
case 1:
|
||
|
ticks += test_own_addr1(my_vcpu);
|
||
|
BAILOUT;
|
||
|
break;
|
||
|
|
||
|
// Address test, own address + window.
|
||
|
case 2:
|
||
|
ticks += test_own_addr2(my_vcpu, stage);
|
||
|
BAILOUT;
|
||
|
break;
|
||
|
|
||
|
// Moving inversions, all ones and zeros.
|
||
|
case 3: {
|
||
|
testword_t pattern1 = 0;
|
||
|
testword_t pattern2 = ~pattern1;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern1, pattern2);
|
||
|
BAILOUT;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern2, pattern1);
|
||
|
BAILOUT;
|
||
|
} break;
|
||
|
|
||
|
// Moving inversions, 8 bit walking ones and zeros.
|
||
|
case 4: {
|
||
|
#if TESTWORD_WIDTH > 32
|
||
|
testword_t pattern1 = UINT64_C(0x8080808080808080);
|
||
|
#else
|
||
|
testword_t pattern1 = 0x80808080;
|
||
|
#endif
|
||
|
for (int i = 0; i < 8; i++) {
|
||
|
testword_t pattern2 = ~pattern1;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern1, pattern2);
|
||
|
BAILOUT;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern2, pattern1);
|
||
|
BAILOUT;
|
||
|
|
||
|
pattern1 >>= 1;
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
// Moving inversions, fixed random pattern.
|
||
|
case 5:
|
||
|
if (cpuid_info.flags.rdtsc) {
|
||
|
random_seed(my_vcpu, get_tsc());
|
||
|
} else {
|
||
|
random_seed(my_vcpu, UINT64_C(0x12345678) * (1 + pass_num));
|
||
|
}
|
||
|
for (int i = 0; i < iterations; i++) {
|
||
|
testword_t pattern1 = random(my_vcpu);
|
||
|
testword_t pattern2 = ~pattern1;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_fixed(my_vcpu, 2, pattern1, pattern2);
|
||
|
BAILOUT;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// Moving inversions, 32/64 bit shifting pattern.
|
||
|
case 6:
|
||
|
for (int offset = 0; offset < TESTWORD_WIDTH; offset++) {
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_walk1(my_vcpu, iterations, offset, false);
|
||
|
BAILOUT;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_walk1(my_vcpu, iterations, offset, true);
|
||
|
BAILOUT;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// Block move.
|
||
|
case 7:
|
||
|
ticks += test_block_move(my_vcpu, iterations);
|
||
|
BAILOUT;
|
||
|
break;
|
||
|
|
||
|
// Moving inversions, fully random patterns.
|
||
|
case 8:
|
||
|
for (int i = 0; i < iterations; i++) {
|
||
|
BARRIER;
|
||
|
ticks += test_mov_inv_random(my_vcpu);
|
||
|
BAILOUT;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// Modulo 20 check, fixed random pattern.
|
||
|
case 9:
|
||
|
if (cpuid_info.flags.rdtsc) {
|
||
|
random_seed(my_vcpu, get_tsc());
|
||
|
} else {
|
||
|
random_seed(my_vcpu, UINT64_C(0x12345678) * (1 + pass_num));
|
||
|
}
|
||
|
for (int i = 0; i < iterations; i++) {
|
||
|
for (int offset = 0; offset < MODULO_N; offset++) {
|
||
|
testword_t pattern1 = random(my_vcpu);
|
||
|
testword_t pattern2 = ~pattern1;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_modulo_n(my_vcpu, 2, pattern1, pattern2, MODULO_N, offset);
|
||
|
BAILOUT;
|
||
|
|
||
|
BARRIER;
|
||
|
ticks += test_modulo_n(my_vcpu, 2, pattern2, pattern1, MODULO_N, offset);
|
||
|
BAILOUT;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// Bit fade test.
|
||
|
case 10:
|
||
|
ticks += test_bit_fade(my_vcpu, stage, iterations);
|
||
|
BAILOUT;
|
||
|
break;
|
||
|
}
|
||
|
return ticks;
|
||
|
}
|