Remove distinction between physical and virtual CPUs.

This is no longer needed, now we can display as many CPUs as we can
physically handle.
This commit is contained in:
Martin Whitaker
2022-01-31 22:59:14 +00:00
parent 4100a44b12
commit 16d55b7dad
29 changed files with 340 additions and 347 deletions
+17 -17
View File
@@ -87,7 +87,7 @@ cpu_mode_t cpu_mode = PAR;
error_mode_t error_mode = ERROR_MODE_NONE;
cpu_state_t pcpu_state[MAX_PCPUS];
cpu_state_t cpu_state[MAX_CPUS];
bool enable_temperature = false;
bool enable_trace = false;
@@ -508,8 +508,8 @@ static void error_mode_menu(void)
static bool set_all_cpus(cpu_state_t state, int display_offset)
{
clear_popup_row(POP_R+16);
for (int i = 1; i < num_pcpus; i++) {
pcpu_state[i] = state;
for (int i = 1; i < num_available_cpus; i++) {
cpu_state[i] = state;
display_enabled(POP_R+12, i - display_offset, state == CPU_STATE_ENABLED);
}
return true;
@@ -520,11 +520,11 @@ static bool add_or_remove_cpu(bool add, int display_offset)
display_input_message(POP_R+16, "Enter CPU #");
int n = read_value(POP_R+16, POP_LM+11, 2, 0);
if (n < 1 || n >= num_pcpus) {
if (n < 1 || n >= num_available_cpus) {
display_error_message(POP_R+16, "Invalid CPU number");
return false;
}
pcpu_state[n] = add ? CPU_STATE_ENABLED : CPU_STATE_DISABLED;
cpu_state[n] = add ? CPU_STATE_ENABLED : CPU_STATE_DISABLED;
display_enabled(POP_R+12, n - display_offset, add);
clear_popup_row(POP_R+16);
return true;
@@ -534,18 +534,18 @@ static bool add_cpu_range(int display_offset)
{
display_input_message(POP_R+16, "Enter first CPU #");
int n1 = read_value(POP_R+16, POP_LM+17, 2, 0);
if (n1 < 1 || n1 >= num_pcpus) {
if (n1 < 1 || n1 >= num_available_cpus) {
display_error_message(POP_R+16, "Invalid CPU number");
return false;
}
display_input_message(POP_R+16, "Enter last CPU #");
int n2 = read_value(POP_R+16, POP_LM+16, 2, 0);
if (n2 < n1 || n2 >= num_pcpus) {
if (n2 < n1 || n2 >= num_available_cpus) {
display_error_message(POP_R+16, "Invalid CPU range");
return false;
}
for (int i = n1; i <= n2; i++) {
pcpu_state[i] = CPU_STATE_ENABLED;
cpu_state[i] = CPU_STATE_ENABLED;
display_enabled(POP_R+12, i - display_offset, true);
}
clear_popup_row(POP_R+16);
@@ -555,12 +555,12 @@ static bool add_cpu_range(int display_offset)
static void display_cpu_selection(int display_offset)
{
clear_screen_region(POP_R+11, POP_C, POP_LAST_R, POP_LAST_C);
display_selection_header(POP_R+10, num_pcpus - 1, display_offset);
display_selection_header(POP_R+10, num_available_cpus - 1, display_offset);
if (display_offset == 0) {
printc(POP_R+12, POP_LM, 'B');
}
for (int i = 1; i < num_pcpus; i++) {
display_enabled(POP_R+12, i - display_offset, pcpu_state[i] == CPU_STATE_ENABLED);
for (int i = 1; i < num_available_cpus; i++) {
display_enabled(POP_R+12, i - display_offset, cpu_state[i] == CPU_STATE_ENABLED);
}
}
@@ -605,7 +605,7 @@ static void cpu_selection_menu(void)
}
break;
case 'd':
if (display_offset < (num_pcpus - SEL_AREA)) {
if (display_offset < (num_available_cpus - SEL_AREA)) {
display_offset += SEL_W;
display_cpu_selection(display_offset);
}
@@ -641,8 +641,8 @@ void config_init(void)
error_mode = ERROR_MODE_ADDRESS;
for (int i = 0; i < MAX_PCPUS; i++) {
pcpu_state[i] = CPU_STATE_ENABLED;
for (int i = 0; i < MAX_CPUS; i++) {
cpu_state[i] = CPU_STATE_ENABLED;
}
enable_temperature = !no_temperature;
@@ -673,9 +673,9 @@ void config_menu(bool initial)
prints(POP_R+5, POP_LI, "<F3> CPU sequencing mode");
prints(POP_R+6, POP_LI, "<F4> Error reporting mode");
if (initial) {
if (num_pcpus < 2) set_foreground_colour(BOLD+BLACK);
if (num_available_cpus < 2) set_foreground_colour(BOLD+BLACK);
prints(POP_R+7, POP_LI, "<F5> CPU selection");
if (num_pcpus < 2) set_foreground_colour(WHITE);
if (num_available_cpus < 2) set_foreground_colour(WHITE);
if (no_temperature) set_foreground_colour(BOLD+BLACK);
printf(POP_R+8, POP_LI, "<F6> Temperature %s", enable_temperature ? "disable" : "enable ");
if (no_temperature) set_foreground_colour(WHITE);
@@ -701,7 +701,7 @@ void config_menu(bool initial)
break;
case '5':
if (initial) {
if (num_pcpus > 1) {
if (num_available_cpus > 1) {
cpu_selection_menu();
}
} else {
+2 -2
View File
@@ -4,7 +4,7 @@
/*
* Provides the configuration settings and pop-up menu.
*
* Copyright (C) 2020-2021 Martin Whitaker.
* Copyright (C) 2020-2022 Martin Whitaker.
*/
#include <stdbool.h>
@@ -34,7 +34,7 @@ extern cpu_mode_t cpu_mode;
extern error_mode_t error_mode;
extern cpu_state_t pcpu_state[MAX_PCPUS];
extern cpu_state_t cpu_state[MAX_CPUS];
extern bool enable_temperature;
extern bool enable_trace;
+3 -3
View File
@@ -229,17 +229,17 @@ void scroll(void)
}
}
void do_tick(int my_vcpu)
void do_tick(int my_cpu)
{
barrier_wait(run_barrier);
if (master_vcpu == my_vcpu) {
if (master_cpu == my_cpu) {
check_input();
error_update();
}
barrier_wait(run_barrier);
// Only the master CPU does the update.
if (master_vcpu != my_vcpu) {
if (master_cpu != my_cpu) {
return;
}
+4 -4
View File
@@ -59,9 +59,9 @@
#define display_cpu_mode(str) \
prints(8, 11, str)
#define display_active_cpu(pcpu_num) \
#define display_active_cpu(cpu_num) \
prints(8, 25, "core #"); \
printi(8, 31, pcpu_num, 3, false, true)
printi(8, 31, cpu_num, 3, false, true)
#define display_all_active \
prints(8, 25, "all cores")
@@ -188,8 +188,8 @@ void toggle_scroll_lock(void);
void scroll(void);
void do_tick(int my_vcpu);
void do_tick(int my_cpu);
void do_trace(int my_vcpu, const char *fmt, ...);
void do_trace(int my_cpu, const char *fmt, ...);
#endif // DISPLAY_H
+3 -3
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from memtest86+ error.c
//
@@ -268,7 +268,7 @@ static void common_err(error_type_t type, uintptr_t addr, testword_t good, testw
set_foreground_colour(YELLOW);
display_scrolled_message(0, " %2i %4i %2i %09x%03x (%kB)",
smp_my_pcpu_num(), pass_num, test_num, page, offset, page << 2);
smp_my_cpu_num(), pass_num, test_num, page, offset, page << 2);
if (type == PARITY_ERROR) {
display_scrolled_message(41, "%s", "Parity error detected near this address");
} else {
@@ -349,7 +349,7 @@ void parity_error(void)
{
// We don't know the real address that caused the parity error,
// so use the last recorded test address.
common_err(PARITY_ERROR, test_addr[my_vcpu_num()], 0, 0, false);
common_err(PARITY_ERROR, test_addr[my_cpu_num()], 0, 0, false);
}
#endif
+2 -2
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from extract of memtest86+ lib.c:
//
@@ -119,7 +119,7 @@ void interrupt(struct trap_regs *trap_regs)
clear_message_area();
display_pinned_message(0, 0, "Unexpected interrupt on CPU %i", smp_my_pcpu_num());
display_pinned_message(0, 0, "Unexpected interrupt on CPU %i", smp_my_cpu_num());
if (trap_regs->vect <= 19) {
display_pinned_message(2, 0, "Type: %s", codes[trap_regs->vect]);
} else {
+46 -49
View File
@@ -62,11 +62,11 @@
static volatile int init_state = 0;
static int num_enabled_cpus = 1;
static barrier_t *start_barrier = NULL;
static spinlock_t *start_mutex = NULL;
static int8_t pcpu_num_to_vcpu_num[MAX_PCPUS];
static volatile bool start_run = false;
static volatile bool start_pass = false;
static volatile bool start_test = false;
@@ -86,9 +86,9 @@ static volatile int test_stage = 0;
// These are exposed in test.h.
int num_vcpus = 1;
volatile int num_active_cpus = 1;
volatile int master_vcpu = 0;
volatile int master_cpu = 0;
barrier_t *run_barrier = NULL;
@@ -103,7 +103,7 @@ volatile int test_num = 0;
volatile bool restart = false;
volatile bool bail = false;
volatile uintptr_t test_addr[MAX_VCPUS];
volatile uintptr_t test_addr[MAX_CPUS];
//------------------------------------------------------------------------------
// Private Functions
@@ -112,16 +112,16 @@ volatile uintptr_t test_addr[MAX_VCPUS];
#define BARRIER(enabled) \
if (enabled) { \
if (TRACE_BARRIERS) { \
trace(my_pcpu, "Start barrier wait at %s line %i", __FILE__, __LINE__); \
trace(my_cpu, "Start barrier wait at %s line %i", __FILE__, __LINE__); \
} \
barrier_wait(start_barrier); \
}
static void run_at(uintptr_t addr, int my_pcpu)
static void run_at(uintptr_t addr, int my_cpu)
{
uintptr_t *new_start_addr = (uintptr_t *)(addr + startup - _start);
if (my_pcpu == 0) {
if (my_cpu == 0) {
memmove((void *)addr, &_start, _end - _start);
}
BARRIER(true);
@@ -164,18 +164,17 @@ static void global_init(void)
clear_message_area();
display_available_cpus(num_pcpus);
display_available_cpus(num_available_cpus);
num_vcpus = 0;
for (int i = 0; i < num_pcpus; i++) {
if (pcpu_state[i] == CPU_STATE_ENABLED) {
pcpu_num_to_vcpu_num[i] = num_vcpus;
num_vcpus++;
num_enabled_cpus = 0;
for (int i = 0; i < num_available_cpus; i++) {
if (cpu_state[i] == CPU_STATE_ENABLED) {
num_enabled_cpus++;
}
}
display_enabled_cpus(num_vcpus);
display_enabled_cpus(num_enabled_cpus);
master_vcpu = 0;
master_cpu = 0;
if (enable_temperature) {
int temp = get_cpu_temperature();
@@ -199,13 +198,13 @@ static void global_init(void)
trace(0, "ACPI RSDP found in %s at %0*x", rsdp_source, 2*sizeof(uintptr_t), rsdp_addr);
}
start_barrier = smp_alloc_barrier(num_vcpus);
run_barrier = smp_alloc_barrier(num_vcpus);
start_barrier = smp_alloc_barrier(num_enabled_cpus);
run_barrier = smp_alloc_barrier(num_enabled_cpus);
start_mutex = smp_alloc_mutex();
error_mutex = smp_alloc_mutex();
int failed = smp_start(pcpu_state);
int failed = smp_start(cpu_state);
if (failed) {
const char *message = "Failed to start CPU core %i. Press any key to reboot...";
display_notice_with_args(strlen(message), message, failed);
@@ -253,22 +252,22 @@ static void setup_vm_map(uintptr_t win_start, uintptr_t win_end)
}
}
static void test_all_windows(int my_pcpu, int my_vcpu)
static void test_all_windows(int my_cpu)
{
int active_cpus = 1;
bool i_am_master = (my_vcpu == master_vcpu) || dummy_run;
num_active_cpus = 1;
bool i_am_master = (my_cpu == master_cpu) || dummy_run;
bool i_am_active = i_am_master;
if (!dummy_run) {
if (cpu_mode == PAR && test_list[test_num].cpu_mode == PAR) {
active_cpus = num_vcpus;
num_active_cpus = num_enabled_cpus;
i_am_active = true;
}
}
if (i_am_master) {
barrier_init(run_barrier, active_cpus);
barrier_init(run_barrier, num_active_cpus);
if (!dummy_run) {
if (active_cpus == 1) {
display_active_cpu(my_pcpu);
if (num_active_cpus == 1) {
display_active_cpu(my_cpu);
} else {
display_all_active;
}
@@ -304,16 +303,16 @@ static void test_all_windows(int my_pcpu, int my_vcpu)
// Relocate if necessary.
if (window_num > 0) {
if (!dummy_run && (uintptr_t)&_start != LOW_LOAD_ADDR) {
run_at(LOW_LOAD_ADDR, my_pcpu);
run_at(LOW_LOAD_ADDR, my_cpu);
}
} else {
if (!dummy_run && (uintptr_t)&_start != HIGH_LOAD_ADDR) {
run_at(HIGH_LOAD_ADDR, my_pcpu);
run_at(HIGH_LOAD_ADDR, my_cpu);
}
}
if (i_am_master) {
trace(my_vcpu, "start window %i", window_num);
trace(my_cpu, "start window %i", window_num);
switch (window_num) {
case 0:
window_start = 0;
@@ -352,7 +351,7 @@ static void test_all_windows(int my_pcpu, int my_vcpu)
// Either there is no PAE or we are at the PAE limit.
break;
}
run_test(my_vcpu, test_num, test_stage, iterations);
run_test(my_cpu, test_num, test_stage, iterations);
}
if (i_am_master) {
@@ -369,42 +368,40 @@ static void test_all_windows(int my_pcpu, int my_vcpu)
void main(void)
{
int my_pcpu;
int my_cpu;
if (init_state == 0) {
// If this is the first time here, we must be CPU 0, as the APs haven't been started yet.
my_pcpu = 0;
my_cpu = 0;
} else {
my_pcpu = smp_my_pcpu_num();
my_cpu = smp_my_cpu_num();
}
if (init_state < 2) {
// Global initialisation is done by the boot CPU.
if (my_pcpu == 0) {
if (my_cpu == 0) {
init_state = 1;
global_init();
} else {
pcpu_state[my_pcpu] = CPU_STATE_RUNNING;
cpu_state[my_cpu] = CPU_STATE_RUNNING;
}
}
BARRIER(true);
init_state = 2;
#if TEST_INTERRUPT
if (my_pcpu == 0) {
if (my_cpu == 0) {
__asm__ __volatile__ ("int $1");
}
#endif
int my_vcpu = pcpu_num_to_vcpu_num[my_pcpu];
// Due to the need to relocate ourselves in the middle of tests, the following
// code cannot be written in the natural way as a set of nested loops. So we
// have a single loop and use global state variables to allow us to restart
// where we left off after each relocation.
while (1) {
BARRIER((my_vcpu != 0) || !dummy_run);
if (my_vcpu == 0) {
BARRIER((my_cpu != 0) || !dummy_run);
if (my_cpu == 0) {
if (start_run) {
pass_num = 0;
start_pass = true;
@@ -424,7 +421,7 @@ void main(void)
}
}
if (start_test) {
trace(my_vcpu, "start test %i", test_num);
trace(my_cpu, "start test %i", test_num);
test_stage = 0;
rerun_test = true;
if (dummy_run) {
@@ -446,17 +443,17 @@ void main(void)
}
BARRIER(!dummy_run);
if (test_list[test_num].enabled) {
test_all_windows(my_pcpu, my_vcpu);
test_all_windows(my_cpu);
}
BARRIER(!dummy_run);
if (my_vcpu != 0) {
if (my_cpu != 0) {
continue;
}
check_input();
if (restart) {
// The configuration has been changed.
master_vcpu = 0;
master_cpu = 0;
start_run = true;
dummy_run = true;
restart = false;
@@ -474,19 +471,19 @@ void main(void)
switch (cpu_mode) {
case PAR:
if (test_list[test_num].cpu_mode == SEQ) {
master_vcpu = (master_vcpu + 1) % num_vcpus;
if (master_vcpu != 0) {
master_cpu = (master_cpu + 1) % num_enabled_cpus;
if (master_cpu != 0) {
rerun_test = true;
continue;
}
}
break;
case ONE:
master_vcpu = (master_vcpu + 1) % num_vcpus;
master_cpu = (master_cpu + 1) % num_enabled_cpus;
break;
case SEQ:
master_vcpu = (master_vcpu + 1) % num_vcpus;
if (master_vcpu != 0) {
master_cpu = (master_cpu + 1) % num_enabled_cpus;
if (master_cpu != 0) {
rerun_test = true;
continue;
}
+7 -12
View File
@@ -4,32 +4,27 @@
/*
* Provides types and variables used when performing the memory tests.
*
* Copyright (C) 2020-2021 Martin Whitaker.
* Copyright (C) 2020-2022 Martin Whitaker.
*/
#include <stdbool.h>
#include <stdint.h>
#include "pmem.h"
#include "smp.h"
#include "barrier.h"
#include "spinlock.h"
/*
* The maximum number of virtual CPUs supported. Note that the display can
* only show the state of a maximum of 32 vCPUs.
* The number of CPU cores being used for the current test.
*/
#define MAX_VCPUS 32
extern volatile int num_active_cpus;
/*
* The number of activated virtual CPUs.
* The current master CPU.
*/
extern int num_vcpus;
/*
* The current master virtual CPU.
*/
extern volatile int master_vcpu;
extern volatile int master_cpu;
/*
* A barrier used when running tests.
@@ -100,6 +95,6 @@ extern volatile bool bail;
/*
* The base address of the block of memory currently being tested.
*/
extern volatile uintptr_t test_addr[MAX_VCPUS];
extern volatile uintptr_t test_addr[MAX_CPUS];
#endif // TEST_H
+1 -1
View File
@@ -101,7 +101,7 @@ startup:
# Pick the correct stack. The stacks are allocated immediately
# after the end of the loaded program, BSP first, then APs.
call smp_my_pcpu_num
call smp_my_cpu_num
movl $AP_STACK_SIZE, %edx
mul %edx
addl $BSP_STACK_SIZE, %eax
+1 -1
View File
@@ -153,7 +153,7 @@ startup:
# after the end of the loaded program, BSP first, then APs.
xorq %rax, %rax
call smp_my_pcpu_num
call smp_my_cpu_num
movl $AP_STACK_SIZE, %edx
mul %edx
addq $BSP_STACK_SIZE, %rax
+4 -4
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from memtest86+ cpuid.h
// (original contained no copyright statement)
@@ -25,7 +25,7 @@ void cpuid_init(void)
// Get the max standard cpuid & vendor ID.
cpuid(0x0, 0,
&cpuid_info.max_vcpuid,
&cpuid_info.max_cpuid,
&cpuid_info.vendor_id.raw[0],
&cpuid_info.vendor_id.raw[2],
&cpuid_info.vendor_id.raw[1]
@@ -33,7 +33,7 @@ void cpuid_init(void)
cpuid_info.vendor_id.str[CPUID_VENDOR_STR_LENGTH - 1] = '\0';
// Get the processor family information & feature flags.
if (cpuid_info.max_vcpuid >= 1) {
if (cpuid_info.max_cpuid >= 1) {
cpuid(0x1, 0,
&cpuid_info.version.raw,
&cpuid_info.proc_info.raw,
@@ -43,7 +43,7 @@ void cpuid_init(void)
}
// Get the digital thermal sensor & power management status bits.
if (cpuid_info.max_vcpuid >= 6) {
if (cpuid_info.max_cpuid >= 6) {
cpuid(0x6, 0,
&cpuid_info.dts_pmp,
&dummy[0],
+2 -2
View File
@@ -4,7 +4,7 @@
/*
* Provides access to the CPUID information.
*
* Copyright (C) 2020 Martin Whitaker.
* Copyright (C) 2020-2022 Martin Whitaker.
*
* Derived from memtest86+ cpuid.h
* (original contained no copyright statement)
@@ -129,7 +129,7 @@ typedef union {
} cpuid_custom_features;
typedef struct {
uint32_t max_vcpuid;
uint32_t max_cpuid;
uint32_t max_xcpuid;
uint32_t dts_pmp;
cpuid_version_t version;
+2 -2
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ init.c:
//
@@ -65,7 +65,7 @@ static void determine_cache_size()
l3_cache = 0;
// Use CPUID(4) if it is available.
if (cpuid_info.max_vcpuid > 3) {
if (cpuid_info.max_cpuid > 3) {
cpuid4_eax_t eax;
cpuid4_ebx_t ebx;
cpuid4_ecx_t ecx;
+36 -36
View File
@@ -236,9 +236,9 @@ static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0x
static volatile apic_register_t *apic = NULL;
static int8_t apic_id_to_pcpu_num[MAX_APIC_IDS];
static int8_t apic_id_to_cpu_num[MAX_APIC_IDS];
static uint8_t pcpu_num_to_apic_id[MAX_PCPUS];
static uint8_t cpu_num_to_apic_id[MAX_CPUS];
static uintptr_t smp_heap_page = 0;
@@ -248,7 +248,7 @@ static uintptr_t alloc_addr = 0;
// Variables
//------------------------------------------------------------------------------
int num_pcpus = 1; // There is always at least one CPU, the BSP
int num_available_cpus = 1; // There is always at least one CPU, the BSP
const char *rsdp_source = "";
@@ -345,15 +345,15 @@ static bool read_mp_config_table(uintptr_t addr)
if (entry->cpu_flag & CPU_BOOTPROCESSOR) {
// BSP is CPU 0
pcpu_num_to_apic_id[0] = entry->apic_id;
} else if (num_pcpus < MAX_PCPUS) {
pcpu_num_to_apic_id[num_pcpus] = entry->apic_id;
num_pcpus++;
cpu_num_to_apic_id[0] = entry->apic_id;
} else if (num_available_cpus < MAX_CPUS) {
cpu_num_to_apic_id[num_available_cpus] = entry->apic_id;
num_available_cpus++;
}
// we cannot handle non-local 82489DX apics
if ((entry->apic_ver & 0xf0) != 0x10) {
num_pcpus = 1; // reset to initial value
num_available_cpus = 1; // reset to initial value
return false;
}
@@ -375,7 +375,7 @@ static bool read_mp_config_table(uintptr_t addr)
tab_entry_ptr += sizeof(mp_local_interrupt_entry_t);
break;
default:
num_pcpus = 1; // reset to initial value
num_available_cpus = 1; // reset to initial value
return false;
}
}
@@ -407,9 +407,9 @@ static bool find_cpus_in_floating_mp_struct(void)
if (fp->feature[0] > 0 && fp->feature[0] <= 7) {
// This is a default config, so plug in the numbers.
apic = (volatile apic_register_t *)0xFEE00000;
pcpu_num_to_apic_id[0] = 0;
pcpu_num_to_apic_id[1] = 1;
num_pcpus = 2;
cpu_num_to_apic_id[0] = 0;
cpu_num_to_apic_id[1] = 1;
num_available_cpus = 2;
return true;
}
@@ -459,11 +459,11 @@ static bool parse_madt(void *addr)
madt_processor_entry_t *entry = (madt_processor_entry_t *)tab_entry_ptr;
if (entry->type == MP_PROCESSOR) {
if (entry->flags & (MADT_PF_ENABLED|MADT_PF_ONLINE_CAPABLE)) {
if (num_pcpus < MAX_PCPUS) {
pcpu_num_to_apic_id[found_cpus] = entry->apic_id;
if (num_available_cpus < MAX_CPUS) {
cpu_num_to_apic_id[found_cpus] = entry->apic_id;
// The first CPU is the BSP, don't increment.
if (found_cpus > 0) {
num_pcpus++;
num_available_cpus++;
}
}
found_cpus++;
@@ -611,11 +611,11 @@ static bool find_cpus_in_rsdp(void)
return false;
}
static bool start_cpu(int pcpu_num)
static bool start_cpu(int cpu_num)
{
// This implements the universal algorithm described in section B.4 of the Intel Multiprocessor specification.
int apic_id = pcpu_num_to_apic_id[pcpu_num];
int apic_id = cpu_num_to_apic_id[cpu_num];
// Pulse the INIT IPI.
apic_write(APICR_ESR, 0);
@@ -647,21 +647,21 @@ static bool start_cpu(int pcpu_num)
void smp_init(bool smp_enable)
{
for (int i = 0; i < MAX_APIC_IDS; i++) {
apic_id_to_pcpu_num[i] = 0;
apic_id_to_cpu_num[i] = 0;
}
for (int i = 0; i < MAX_PCPUS; i++) {
pcpu_num_to_apic_id[i] = 0;
for (int i = 0; i < MAX_CPUS; i++) {
cpu_num_to_apic_id[i] = 0;
}
num_pcpus = 1;
num_available_cpus = 1;
if (smp_enable) {
(void)(find_cpus_in_rsdp() || find_cpus_in_floating_mp_struct());
}
for (int i = 0; i < num_pcpus; i++) {
apic_id_to_pcpu_num[pcpu_num_to_apic_id[i]] = i;
for (int i = 0; i < num_available_cpus; i++) {
apic_id_to_cpu_num[cpu_num_to_apic_id[i]] = i;
}
// Reserve last page of first segment for AP trampoline and sync objects.
@@ -676,37 +676,37 @@ void smp_init(bool smp_enable)
alloc_addr = HEAP_BASE_ADDR + ap_trampoline_size;
}
int smp_start(cpu_state_t pcpu_state[MAX_PCPUS])
int smp_start(cpu_state_t cpu_state[MAX_CPUS])
{
int pcpu_num;
int cpu_num;
pcpu_state[0] = CPU_STATE_RUNNING; // we don't support disabling the boot CPU
cpu_state[0] = CPU_STATE_RUNNING; // we don't support disabling the boot CPU
for (pcpu_num = 1; pcpu_num < num_pcpus; pcpu_num++) {
if (pcpu_state[pcpu_num] == CPU_STATE_ENABLED) {
if (!start_cpu(pcpu_num)) {
return pcpu_num;
for (cpu_num = 1; cpu_num < num_available_cpus; cpu_num++) {
if (cpu_state[cpu_num] == CPU_STATE_ENABLED) {
if (!start_cpu(cpu_num)) {
return cpu_num;
}
}
}
int timeout = 100000;
while (timeout > 0) {
for (pcpu_num = 1; pcpu_num < num_pcpus; pcpu_num++) {
if (pcpu_state[pcpu_num] == CPU_STATE_ENABLED) break;
for (cpu_num = 1; cpu_num < num_available_cpus; cpu_num++) {
if (cpu_state[cpu_num] == CPU_STATE_ENABLED) break;
}
if (pcpu_num == num_pcpus) {
if (cpu_num == num_available_cpus) {
return 0;
}
usleep(10);
timeout--;
}
return pcpu_num;
return cpu_num;
}
int smp_my_pcpu_num(void)
int smp_my_cpu_num(void)
{
return num_pcpus > 1 ? apic_id_to_pcpu_num[my_apic_id()] : 0;
return num_available_cpus > 1 ? apic_id_to_cpu_num[my_apic_id()] : 0;
}
barrier_t *smp_alloc_barrier(int num_threads)
+12 -12
View File
@@ -16,11 +16,11 @@
#include "spinlock.h"
/*
* The maximum number of active CPU cores. In the current implementation this
* is limited to 256 both by the number of available APIC IDs and the need to
* fit both the program and the CPU stacks in low memory.
* The maximum number of CPU cores that can be used. Currently this is limited
* to 256 both by the number of available APIC IDs and the need to fit both
* the program and the CPU stacks in low memory.
*/
#define MAX_PCPUS 256
#define MAX_CPUS 256
/*
* The current state of a CPU core.
@@ -32,10 +32,10 @@ typedef enum __attribute__ ((packed)) {
} cpu_state_t;
/*
* The number of available physical CPU cores. Initially this is 1, but may
* increase after calling smp_init().
* The number of available CPU cores. Initially this is 1, but may increase
* after calling smp_init().
*/
extern int num_pcpus;
extern int num_available_cpus;
/*
* The search step that located the ACPI RSDP (for debug).
@@ -47,20 +47,20 @@ extern const char *rsdp_source;
extern uintptr_t rsdp_addr;
/*
* Initialises the SMP state and detects the number of physical CPUs.
* Initialises the SMP state and detects the number of available CPUs.
*/
void smp_init(bool smp_enable);
/*
* Starts the APs listed as enabled in pcpu_state. Returns 0 on success
* Starts the APs listed as enabled in cpu_state. Returns 0 on success
* or the index number of the lowest-numbered AP that failed to start.
*/
int smp_start(cpu_state_t pcpu_state[MAX_PCPUS]);
int smp_start(cpu_state_t cpu_state[MAX_CPUS]);
/*
* Returns the ordinal number of the calling PCPU.
* Returns the ordinal number of the calling CPU.
*/
int smp_my_pcpu_num(void);
int smp_my_cpu_num(void);
/*
* Allocates and initialises a barrier object in pinned memory.
+2 -2
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ init.c:
//
@@ -32,7 +32,7 @@ int get_cpu_temperature(void)
}
// Intel CPU
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_vcpuid >= 6) {
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) {
if (cpuid_info.dts_pmp & 1) {
uint32_t msrl, msrh;
+6 -6
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -26,20 +26,20 @@
// Public Functions
//------------------------------------------------------------------------------
int test_addr_walk1(int my_vcpu)
int test_addr_walk1(int my_cpu)
{
int ticks = 0;
// There isn't a meaningful address for this test.
test_addr[my_vcpu] = 0;
test_addr[my_cpu] = 0;
testword_t invert = 0;
for (int i = 0; i < 2; i++) {
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_value(invert);
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
@@ -83,7 +83,7 @@ int test_addr_walk1(int my_vcpu)
invert = ~invert;
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
}
+22 -22
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -29,11 +29,11 @@
// Private Functions
//------------------------------------------------------------------------------
static int pattern_fill(int my_vcpu, testword_t pattern)
static int pattern_fill(int my_cpu, testword_t pattern)
{
int ticks = 0;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_value(pattern);
}
@@ -54,24 +54,24 @@ static int pattern_fill(int my_vcpu, testword_t pattern)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
write_word(p, pattern);
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
return ticks;
}
static int pattern_check(int my_vcpu, testword_t pattern)
static int pattern_check(int my_cpu, testword_t pattern)
{
int ticks = 0;
@@ -92,17 +92,17 @@ static int pattern_check(int my_vcpu, testword_t pattern)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t actual = read_word(p);
if (unlikely(actual != pattern)) {
data_error(p, pattern, actual, true);
}
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
@@ -110,21 +110,21 @@ static int pattern_check(int my_vcpu, testword_t pattern)
return ticks;
}
static int fade_delay(int my_vcpu, int sleep_secs)
static int fade_delay(int my_cpu, int sleep_secs)
{
int ticks = 0;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_stage_description("fade over %i seconds", sleep_secs);
}
while (sleep_secs > 0) {
sleep_secs--;
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
sleep(1);
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
}
@@ -135,7 +135,7 @@ static int fade_delay(int my_vcpu, int sleep_secs)
// Public Functions
//------------------------------------------------------------------------------
int test_bit_fade(int my_vcpu, int stage, int sleep_secs)
int test_bit_fade(int my_cpu, int stage, int sleep_secs)
{
const testword_t all_zero = 0;
const testword_t all_ones = ~all_zero;
@@ -146,28 +146,28 @@ int test_bit_fade(int my_vcpu, int stage, int sleep_secs)
switch (stage) {
case 0:
ticks = pattern_fill(my_vcpu, all_zero);
ticks = pattern_fill(my_cpu, all_zero);
break;
case 1:
// Only sleep once.
if (stage != last_stage) {
ticks = fade_delay(my_vcpu, sleep_secs);
ticks = fade_delay(my_cpu, sleep_secs);
}
break;
case 2:
ticks = pattern_check(my_vcpu, all_zero);
ticks = pattern_check(my_cpu, all_zero);
break;
case 3:
ticks = pattern_fill(my_vcpu, all_ones);
ticks = pattern_fill(my_cpu, all_ones);
break;
case 4:
// Only sleep once.
if (stage != last_stage) {
ticks = fade_delay(my_vcpu, sleep_secs);
ticks = fade_delay(my_cpu, sleep_secs);
}
break;
case 5:
ticks = pattern_check(my_vcpu, all_ones);
ticks = pattern_check(my_cpu, all_ones);
break;
default:
break;
+17 -17
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -27,18 +27,18 @@
// Public Functions
//------------------------------------------------------------------------------
int test_block_move(int my_vcpu, int iterations)
int test_block_move(int my_cpu, int iterations)
{
int ticks = 0;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_name("block move");
}
// Initialize memory with the initial pattern.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, 16 * sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
testword_t *p = start;
testword_t *pe = start;
@@ -53,10 +53,10 @@ int test_block_move(int my_vcpu, int iterations)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
testword_t pattern1 = 1;
do {
testword_t pattern2 = ~pattern1;
@@ -78,17 +78,17 @@ int test_block_move(int my_vcpu, int iterations)
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);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
// Now move the data around. First move the data up half of the segment size
// we are testing. Then move the data to the original location + 32 bytes.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, 16 * sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
testword_t *p = start;
testword_t *pe = start;
@@ -107,10 +107,10 @@ int test_block_move(int my_vcpu, int iterations)
for (int j = 0; j < iterations; j++) {
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
#ifdef __x86_64__
__asm__ __volatile__ (
"cld\n"
@@ -188,19 +188,19 @@ int test_block_move(int my_vcpu, int iterations)
: "edi", "esi", "ecx"
);
#endif
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
}
} while (!at_end && ++pe); // advance pe to next start point
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
// Now check the data. The error checking is rather crude. We just check that the
// adjacent words are the same.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, 16 * sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
testword_t *p = start;
testword_t *pe = start;
@@ -215,10 +215,10 @@ int test_block_move(int my_vcpu, int iterations)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t p0 = read_word(p + 0);
testword_t p1 = read_word(p + 1);
@@ -226,7 +226,7 @@ int test_block_move(int my_vcpu, int iterations)
data_error(p, p0, p1, false);
}
} while (p <= (pe - 2) && (p += 2)); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
+16 -16
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -27,18 +27,18 @@
// Public Functions
//------------------------------------------------------------------------------
int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t pattern2, int n, int offset)
int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pattern2, int n, int offset)
{
int ticks = 0;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_values(pattern1, offset);
}
// Write every nth location with pattern1.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
end -= n; // avoids pointer overflow when incrementing p
testword_t *p = start + offset; // we assume each chunk has at least 'n' words, so this won't overflow
@@ -54,14 +54,14 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
write_word(p, pattern1);
} while (p <= (pe - n) && (p += n)); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
@@ -70,7 +70,7 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
for (int i = 0; i < iterations; i++) {
for (int j = 0; j < vm_map_size; j++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, j, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
int k = 0;
testword_t *p = start;
@@ -86,10 +86,10 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
if (k != offset) {
write_word(p, pattern2);
@@ -99,18 +99,18 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
k = 0;
}
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
// Now check every nth location.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
end -= n; // avoids pointer overflow when incrementing p
testword_t *p = start + offset; // we assume each chunk has at least 'offset' words, so this won't overflow
@@ -126,17 +126,17 @@ int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t p
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t actual = read_word(p);
if (unlikely(actual != pattern1)) {
data_error(p, pattern1, actual, true);
}
} while (p <= (pe - n) && (p += n)); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
+17 -17
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -29,18 +29,18 @@
// Public Functions
//------------------------------------------------------------------------------
int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testword_t pattern2)
int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword_t pattern2)
{
int ticks = 0;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_value(pattern1);
}
// Initialize memory with the initial pattern.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
volatile testword_t *p = start;
volatile testword_t *pe = start;
@@ -55,10 +55,10 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
#if HAND_OPTIMISED
#ifdef __x86_64__
uint64_t length = pe - p + 1;
@@ -86,7 +86,7 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
write_word(p, pattern1);
} while (p++ < pe); // test before increment in case pointer overflows
#endif
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
@@ -94,11 +94,11 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
// Check for the current pattern and then write the alternate pattern for
// each memory location. Test from the bottom up and then from the top down.
for (int i = 0; i < iterations; i++) {
flush_caches(my_vcpu);
flush_caches(my_cpu);
for (int j = 0; j < vm_map_size; j++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, j, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
volatile testword_t *p = start;
volatile testword_t *pe = start;
@@ -113,10 +113,10 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t actual = read_word(p);
if (unlikely(actual != pattern1)) {
@@ -124,16 +124,16 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
}
write_word(p, pattern2);
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
for (int j = vm_map_size - 1; j >= 0; j--) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, j, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
volatile testword_t *p = end;
volatile testword_t *ps = end;
@@ -148,10 +148,10 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
ps = start;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t actual = read_word(p);
if (unlikely(actual != pattern2)) {
@@ -159,7 +159,7 @@ int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testwor
}
write_word(p, pattern1);
} while (p-- > ps); // test before decrement in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_start && --ps); // advance ps to next start point
}
+16 -16
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -30,7 +30,7 @@
// Public Functions
//------------------------------------------------------------------------------
int test_mov_inv_random(int my_vcpu)
int test_mov_inv_random(int my_cpu)
{
int ticks = 0;
@@ -41,15 +41,15 @@ int test_mov_inv_random(int my_vcpu)
seed = UINT64_C(0x12345678) * (1 + pass_num);
}
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_value(seed);
}
// Initialize memory with the initial pattern.
random_seed(my_vcpu, seed);
random_seed(my_cpu, seed);
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
volatile testword_t *p = start;
volatile testword_t *pe = start;
@@ -64,14 +64,14 @@ int test_mov_inv_random(int my_vcpu)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
write_word(p, random(my_vcpu));
write_word(p, random(my_cpu));
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
@@ -80,12 +80,12 @@ int test_mov_inv_random(int my_vcpu)
// memory location. Repeat.
testword_t invert = 0;
for (int i = 0; i < 2; i++) {
flush_caches(my_vcpu);
flush_caches(my_cpu);
random_seed(my_vcpu, seed);
random_seed(my_cpu, seed);
for (int j = 0; j < vm_map_size; j++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, j, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
volatile testword_t *p = start;
volatile testword_t *pe = start;
@@ -100,19 +100,19 @@ int test_mov_inv_random(int my_vcpu)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t expect = random(my_vcpu) ^ invert;
testword_t expect = random(my_cpu) ^ invert;
testword_t actual = read_word(p);
if (unlikely(actual != expect)) {
data_error(p, expect, actual, true);
}
write_word(p, ~expect);
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
+17 -17
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -27,20 +27,20 @@
// Public Functions
//------------------------------------------------------------------------------
int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse)
{
int ticks = 0;
testword_t pattern = (testword_t)1 << offset;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_value(inverse ? ~pattern : pattern);
}
// Initialize memory with the initial pattern.
for (int i = 0; i < vm_map_size; i++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, i, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
volatile testword_t *p = start;
volatile testword_t *pe = start;
@@ -55,15 +55,15 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
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);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
@@ -73,11 +73,11 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
for (int i = 0; i < iterations; i++) {
pattern = (testword_t)1 << offset;
flush_caches(my_vcpu);
flush_caches(my_cpu);
for (int j = 0; j < vm_map_size; j++) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, j, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
volatile testword_t *p = start;
volatile testword_t *pe = start;
@@ -92,10 +92,10 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t expect = inverse ? ~pattern : pattern;
testword_t actual = read_word(p);
@@ -105,16 +105,16 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
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);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
for (int j = vm_map_size - 1; j >= 0; j--) {
testword_t *start, *end;
calculate_chunk(&start, &end, my_vcpu, j, sizeof(testword_t));
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
volatile testword_t *p = end;
volatile testword_t *ps = end;
@@ -129,10 +129,10 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
ps = start;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)ps;
test_addr[my_cpu] = (uintptr_t)ps;
do {
pattern = pattern >> 1 | pattern << (TESTWORD_WIDTH - 1); // rotate right
testword_t expect = inverse ? pattern : ~pattern;
@@ -142,7 +142,7 @@ int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse)
}
write_word(p, ~expect);
} while (p-- > ps); // test before decrement in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_start && --ps); // advance ps to next start point
}
+17 -17
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ test.c:
//
@@ -27,11 +27,11 @@
// Private Functions
//------------------------------------------------------------------------------
static int pattern_fill(int my_vcpu, testword_t offset)
static int pattern_fill(int my_cpu, testword_t offset)
{
int ticks = 0;
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
display_test_pattern_name("own address");
}
@@ -53,24 +53,24 @@ static int pattern_fill(int my_vcpu, testword_t offset)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
write_word(p, (testword_t)p + offset);
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
flush_caches(my_vcpu);
flush_caches(my_cpu);
return ticks;
}
static int pattern_check(int my_vcpu, testword_t offset)
static int pattern_check(int my_cpu, testword_t offset)
{
int ticks = 0;
@@ -92,10 +92,10 @@ static int pattern_check(int my_vcpu, testword_t offset)
pe = end;
}
ticks++;
if (my_vcpu < 0) {
if (my_cpu < 0) {
continue;
}
test_addr[my_vcpu] = (uintptr_t)p;
test_addr[my_cpu] = (uintptr_t)p;
do {
testword_t expect = (testword_t)p + offset;
testword_t actual = read_word(p);
@@ -103,7 +103,7 @@ static int pattern_check(int my_vcpu, testword_t offset)
data_error(p, expect, actual, true);
}
} while (p++ < pe); // test before increment in case pointer overflows
do_tick(my_vcpu);
do_tick(my_cpu);
BAILOUT;
} while (!at_end && ++pe); // advance pe to next start point
}
@@ -115,17 +115,17 @@ static int pattern_check(int my_vcpu, testword_t offset)
// Public Functions
//------------------------------------------------------------------------------
int test_own_addr1(int my_vcpu)
int test_own_addr1(int my_cpu)
{
int ticks = 0;
ticks += pattern_fill(my_vcpu, 0);
ticks += pattern_check(my_vcpu, 0);
ticks += pattern_fill(my_cpu, 0);
ticks += pattern_check(my_cpu, 0);
return ticks;
}
int test_own_addr2(int my_vcpu, int stage)
int test_own_addr2(int my_cpu, int stage)
{
static testword_t offset = 0;
static int last_stage = -1;
@@ -136,10 +136,10 @@ int test_own_addr2(int my_vcpu, int stage)
switch (stage) {
case 0:
ticks = pattern_fill(my_vcpu, offset);
ticks = pattern_fill(my_cpu, offset);
break;
case 1:
ticks = pattern_check(my_vcpu, offset);
ticks = pattern_check(my_cpu, offset);
break;
default:
break;
+10 -10
View File
@@ -5,29 +5,29 @@
* Provides the prototypes for the basic test functions used to implement
* the tests.
*
* Copyright (C) 2020-2021 Martin Whitaker.
* Copyright (C) 2020-2022 Martin Whitaker.
*/
#include <stdbool.h>
#include "test.h"
int test_addr_walk1(int my_vcpu);
int test_addr_walk1(int my_cpu);
int test_own_addr1(int my_vcpu);
int test_own_addr1(int my_cpu);
int test_own_addr2(int my_vcpu, int stage);
int test_own_addr2(int my_cpu, int stage);
int test_mov_inv_fixed(int my_vcpu, int iterations, testword_t pattern1, testword_t pattern2);
int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword_t pattern2);
int test_mov_inv_walk1(int my_vcpu, int iterations, int offset, bool inverse);
int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse);
int test_mov_inv_random(int my_vcpu);
int test_mov_inv_random(int my_cpu);
int test_modulo_n(int my_vcpu, int iterations, testword_t pattern1, testword_t pattern2, int n, int offset);
int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pattern2, int n, int offset);
int test_block_move(int my_vcpu, int iterations);
int test_block_move(int my_cpu, int iterations);
int test_bit_fade(int my_vcpu, int stage, int sleep_secs);
int test_bit_fade(int my_cpu, int stage, int sleep_secs);
#endif // TEST_FUNCS_H
+22 -21
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020-2021 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Partly derived from an extract of memtest86+ test.c:
//
@@ -16,6 +16,7 @@
#include <stdint.h>
#include "cache.h"
#include "smp.h"
#include "barrier.h"
@@ -40,22 +41,22 @@ typedef struct {
// Private Variables
//------------------------------------------------------------------------------
static prsg_state_t prsg_state[MAX_VCPUS];
static prsg_state_t prsg_state[MAX_CPUS];
//------------------------------------------------------------------------------
// Private Functions
//------------------------------------------------------------------------------
static inline uint32_t prsg(int my_vcpu)
static inline uint32_t prsg(int my_cpu)
{
// This implements a 64 bit linear feedback shift register with XNOR
// feedback from taps 64, 63, 61, 60. It generates 32 new bits each
// time the function is called. Because the feedback taps are all in
// the upper 32 bits, we can generate the new bits in parallel.
uint64_t lfsr = prsg_state[my_vcpu].lfsr;
uint64_t lfsr = prsg_state[my_cpu].lfsr;
uint32_t feedback = ~((lfsr >> 32) ^ (lfsr >> 31) ^ (lfsr >> 29) ^ (lfsr >> 28));
prsg_state[my_vcpu].lfsr = (lfsr << 32) | feedback;
prsg_state[my_cpu].lfsr = (lfsr << 32) | feedback;
return feedback;
}
@@ -63,9 +64,9 @@ static inline uint32_t prsg(int my_vcpu)
// Public Functions
//------------------------------------------------------------------------------
void random_seed(int my_vcpu, uint64_t seed)
void random_seed(int my_cpu, uint64_t seed)
{
if (my_vcpu < 0) {
if (my_cpu < 0) {
return;
}
@@ -73,38 +74,38 @@ void random_seed(int my_vcpu, uint64_t seed)
if (~seed == 0) {
seed = 0;
}
prsg_state[my_vcpu].lfsr = seed;
prsg_state[my_cpu].lfsr = seed;
}
testword_t random(int my_vcpu)
testword_t random(int my_cpu)
{
if (my_vcpu < 0) {
if (my_cpu < 0) {
return 0;
}
testword_t value = prsg(my_vcpu);
testword_t value = prsg(my_cpu);
#if TESTWORD_WIDTH > 32
value = value << 32 | prsg(my_vcpu);
value = value << 32 | prsg(my_cpu);
#endif
return value;
}
void calculate_chunk(testword_t **start, testword_t **end, int my_vcpu, int segment, size_t chunk_align)
void calculate_chunk(testword_t **start, testword_t **end, int my_cpu, int segment, size_t chunk_align)
{
if (my_vcpu < 0) {
my_vcpu = 0;
if (my_cpu < 0) {
my_cpu = 0;
}
// If we are only running 1 CPU then test the whole segment.
if (num_vcpus == 1) {
if (num_active_cpus == 1) {
*start = vm_map[segment].start;
*end = vm_map[segment].end;
} else {
uintptr_t segment_size = (vm_map[segment].end - vm_map[segment].start + 1) * sizeof(testword_t);
uintptr_t chunk_size = round_down(segment_size / num_vcpus, chunk_align);
uintptr_t chunk_size = round_down(segment_size / num_active_cpus, chunk_align);
// Calculate chunk boundaries.
*start = (testword_t *)((uintptr_t)vm_map[segment].start + chunk_size * my_vcpu);
*start = (testword_t *)((uintptr_t)vm_map[segment].start + chunk_size * my_cpu);
*end = (testword_t *)((uintptr_t)(*start) + chunk_size) - 1;
if (*end > vm_map[segment].end) {
@@ -113,11 +114,11 @@ void calculate_chunk(testword_t **start, testword_t **end, int my_vcpu, int segm
}
}
void flush_caches(int my_vcpu)
void flush_caches(int my_cpu)
{
if (my_vcpu >= 0) {
if (my_cpu >= 0) {
barrier_wait(run_barrier);
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
cache_flush();
}
barrier_wait(run_barrier);
+8 -8
View File
@@ -5,7 +5,7 @@
* Provides some common definitions and helper functions for the memory
* tests.
*
* Copyright (C) 2020-2021 Martin Whitaker.
* Copyright (C) 2020-2022 Martin Whitaker.
*/
#include <stddef.h>
@@ -60,28 +60,28 @@ static inline uintptr_t round_up(uintptr_t value, size_t align_size)
}
/*
* Seeds the psuedo-random number generator for my_vcpu.
* Seeds the psuedo-random number generator for my_cpu.
*/
void random_seed(int my_vcpu, uint64_t seed);
void random_seed(int my_cpu, uint64_t seed);
/*
* Returns a psuedo-random number for my_vcpu. The sequence of numbers returned
* Returns a psuedo-random number for my_cpu. The sequence of numbers returned
* is repeatable for a given starting seed. The sequence repeats after 2^64 - 1
* numbers. Within that period, no number is repeated.
*/
testword_t random(int my_vcpu);
testword_t random(int my_cpu);
/*
* Calculates the start and end word address for the chunk of segment that is
* to be tested by my_vcpu. The chunk start will be aligned to a multiple of
* to be tested by my_cpu. The chunk start will be aligned to a multiple of
* chunk_align.
*/
void calculate_chunk(testword_t **start, testword_t **end, int my_vcpu, int segment, size_t chunk_align);
void calculate_chunk(testword_t **start, testword_t **end, int my_cpu, int segment, size_t chunk_align);
/*
* Flushes the CPU caches. If SMP is enabled, synchronises the threads before
* and after issuing the cache flush instruction.
*/
void flush_caches(int my_vcpu);
void flush_caches(int my_cpu);
#endif // TEST_HELPER_H
+26 -26
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2022 Martin Whitaker.
//
// Derived from an extract of memtest86+ main.c:
//
@@ -74,16 +74,16 @@ int ticks_per_test[NUM_PASS_TYPES][NUM_TEST_PATTERNS];
//------------------------------------------------------------------------------
#define BARRIER \
if (my_vcpu >= 0) { \
if (my_cpu >= 0) { \
if (TRACE_BARRIERS) { \
trace(my_vcpu, "Run barrier wait at %s line %i", __FILE__, __LINE__); \
trace(my_cpu, "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)
int run_test(int my_cpu, int test, int stage, int iterations)
{
if (my_vcpu == master_vcpu) {
if (my_cpu == master_cpu) {
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);
@@ -107,20 +107,20 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
// Address test, walking ones.
case 0:
cache_off();
ticks += test_addr_walk1(my_vcpu);
ticks += test_addr_walk1(my_cpu);
cache_on();
BAILOUT;
break;
// Address test, own address in window.
case 1:
ticks += test_own_addr1(my_vcpu);
ticks += test_own_addr1(my_cpu);
BAILOUT;
break;
// Address test, own address + window.
case 2:
ticks += test_own_addr2(my_vcpu, stage);
ticks += test_own_addr2(my_cpu, stage);
BAILOUT;
break;
@@ -130,11 +130,11 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
testword_t pattern2 = ~pattern1;
BARRIER;
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern1, pattern2);
ticks += test_mov_inv_fixed(my_cpu, iterations, pattern1, pattern2);
BAILOUT;
BARRIER;
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern2, pattern1);
ticks += test_mov_inv_fixed(my_cpu, iterations, pattern2, pattern1);
BAILOUT;
} break;
@@ -149,11 +149,11 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
testword_t pattern2 = ~pattern1;
BARRIER;
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern1, pattern2);
ticks += test_mov_inv_fixed(my_cpu, iterations, pattern1, pattern2);
BAILOUT;
BARRIER;
ticks += test_mov_inv_fixed(my_vcpu, iterations, pattern2, pattern1);
ticks += test_mov_inv_fixed(my_cpu, iterations, pattern2, pattern1);
BAILOUT;
pattern1 >>= 1;
@@ -163,16 +163,16 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
// Moving inversions, fixed random pattern.
case 5:
if (cpuid_info.flags.rdtsc) {
random_seed(my_vcpu, get_tsc());
random_seed(my_cpu, get_tsc());
} else {
random_seed(my_vcpu, UINT64_C(0x12345678) * (1 + pass_num));
random_seed(my_cpu, UINT64_C(0x12345678) * (1 + pass_num));
}
for (int i = 0; i < iterations; i++) {
testword_t pattern1 = random(my_vcpu);
testword_t pattern1 = random(my_cpu);
testword_t pattern2 = ~pattern1;
BARRIER;
ticks += test_mov_inv_fixed(my_vcpu, 2, pattern1, pattern2);
ticks += test_mov_inv_fixed(my_cpu, 2, pattern1, pattern2);
BAILOUT;
}
break;
@@ -181,18 +181,18 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
case 6:
for (int offset = 0; offset < TESTWORD_WIDTH; offset++) {
BARRIER;
ticks += test_mov_inv_walk1(my_vcpu, iterations, offset, false);
ticks += test_mov_inv_walk1(my_cpu, iterations, offset, false);
BAILOUT;
BARRIER;
ticks += test_mov_inv_walk1(my_vcpu, iterations, offset, true);
ticks += test_mov_inv_walk1(my_cpu, iterations, offset, true);
BAILOUT;
}
break;
// Block move.
case 7:
ticks += test_block_move(my_vcpu, iterations);
ticks += test_block_move(my_cpu, iterations);
BAILOUT;
break;
@@ -200,7 +200,7 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
case 8:
for (int i = 0; i < iterations; i++) {
BARRIER;
ticks += test_mov_inv_random(my_vcpu);
ticks += test_mov_inv_random(my_cpu);
BAILOUT;
}
break;
@@ -208,21 +208,21 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
// Modulo 20 check, fixed random pattern.
case 9:
if (cpuid_info.flags.rdtsc) {
random_seed(my_vcpu, get_tsc());
random_seed(my_cpu, get_tsc());
} else {
random_seed(my_vcpu, UINT64_C(0x12345678) * (1 + pass_num));
random_seed(my_cpu, 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 pattern1 = random(my_cpu);
testword_t pattern2 = ~pattern1;
BARRIER;
ticks += test_modulo_n(my_vcpu, 2, pattern1, pattern2, MODULO_N, offset);
ticks += test_modulo_n(my_cpu, 2, pattern1, pattern2, MODULO_N, offset);
BAILOUT;
BARRIER;
ticks += test_modulo_n(my_vcpu, 2, pattern2, pattern1, MODULO_N, offset);
ticks += test_modulo_n(my_cpu, 2, pattern2, pattern1, MODULO_N, offset);
BAILOUT;
}
}
@@ -230,7 +230,7 @@ int run_test(int my_vcpu, int test, int stage, int iterations)
// Bit fade test.
case 10:
ticks += test_bit_fade(my_vcpu, stage, iterations);
ticks += test_bit_fade(my_cpu, stage, iterations);
BAILOUT;
break;
}
+2 -2
View File
@@ -4,7 +4,7 @@
/*
* Provides support for identifying and running the memory tests.
*
* Copyright (C) 2020 Martin Whitaker.
* Copyright (C) 2020-2022 Martin Whitaker.
*/
#include <stdbool.h>
@@ -29,6 +29,6 @@ typedef enum { FAST_PASS, FULL_PASS, NUM_PASS_TYPES } pass_type_t;
extern int ticks_per_pass[NUM_PASS_TYPES];
extern int ticks_per_test[NUM_PASS_TYPES][NUM_TEST_PATTERNS];
int run_test(int my_vcpu, int test, int stage, int iterations);
int run_test(int my_cpu, int test, int stage, int iterations);
#endif // TESTS_H