Skip to content

Commit

Permalink
KVM: Add memory coherency test case for TD and Non-TD
Browse files Browse the repository at this point in the history
Signed-off-by: Xudong Hao <[email protected]>
  • Loading branch information
xhao22 committed Jan 13, 2025
1 parent a2e739f commit b814353
Show file tree
Hide file tree
Showing 3 changed files with 347 additions and 0 deletions.
255 changes: 255 additions & 0 deletions KVM/qemu/deps/mem_coh/mem_coh.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2025 Intel Corporation. All rights reserved. */
/*
* This test case check the memory coherency in SMP system.
* userage:
* ./mem_co seed_file1 & ./mem_coh seed_file2 & ..
*/


#include <stdio.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

/*#define _DEBUG */
#ifdef _DEBUG
#define DEBUG(fmt, args...) printf("%s: "fmt, __func__, ##args)
#else
#define DEBUG(args...)
#endif

#ifdef CONFIG_SMP
#define LOCK "lock ; "
#else
#define LOCK ""
#endif

#define CHK(x) do { if ((x) == -1) { perror("x"); exit(1); } } while (0)

#define BLKSIZE (1024 * 1024) // 1M bytes

int fd, CK = 8, PNUM = 0;
struct stat sbuf;
void *ADDR;

#ifdef ARCH_64
static inline void atomic_sub(int i, void *v)
{
int old, new, ia64_intri_res;

do {
old = *(int *)v;
new = old - i;
__asm__ __volatile__(
"mov ar.ccv=%0;;"
::"rO" (old));
__asm__ __volatile__(
"cmpxchg8.acq %0=[%1],%2,ar.ccv"
: "=r" (ia64_intri_res)
: "r" (v), "r" (new)
: "memory");
} while (ia64_intri_res != old);

}
#else
static inline void atomic_sub(int i, void *v)
{
__asm__ __volatile__(
LOCK "subl %1,%0"
: "=m" (*(int *)v)
: "ir" (i), "m" (*(int *)v));
}
#endif

int get_p_num(void)
{
int nb_cpu;
char line[1024];
FILE *f;

f = fopen("/proc/cpuinfo", "r");
if (f == NULL) {
perror(" [-] fopen /proc/cpuinfo");
return 1;
}

nb_cpu = 0;

while (fgets(line, sizeof(line) - 1, f) != NULL) {
line[1023] = 0;
if (memcmp(line, "processor", 9) == 0)
nb_cpu++;
}
fclose(f);
return nb_cpu;

}

int get_system_mem(void)
{
char mem_info[1024], *cp;
FILE *fd;
int i;

fd = fopen("/proc/meminfo", "r");
if (fd == NULL) {
perror(" Can not open file /proc/cpuinfo:");
return -1;
}

if (fgets(mem_info, 1023, fd) != NULL) {
mem_info[1023] = 0;
if (strstr(mem_info, "MemTotal:") != NULL) {
cp = mem_info + strlen("MemTotal:");
i = atoi(cp);
DEBUG("this system have %d K memory\n", i);
} else {
printf("can not find MemTotal charcters in /proc/mem_info file\n");
return -1;
}
}
fclose(fd);
return i;
}

void *threadfunc1(void *arg)
{
int i, pgsize, fsize;
int *ip;

i = *(int *) arg;
DEBUG("thread num is %d, thread pid is %u sbuf.st_size is %u\n", i, pthread_self(), sbuf.st_size);
fsize = sbuf.st_size;

//sleep(10);
pgsize = getpagesize();
for (i = 0; i < CK; i++) {
for (ip = ADDR, fsize = sbuf.st_size; fsize > 0; fsize -= sizeof(int)) {
atomic_sub(1, ip);
ip++;
}
//msync(ADDR, BLKSIZE, MS_ASYNC);
usleep(10000);
}
}


void *threadfunc2(void *arg)
{
int i, j, k, l, t_num, memtotal, pgsize;
int *ip, **mp;

t_num = *(int *) arg;
mp = malloc(sizeof(int *)*1024*1024*4);
if (mp == NULL) {
perror("malloc fail ");
return NULL;
}
memtotal = get_system_mem();
DEBUG("thread num is %d, thread pid is %u system memory is %d KB\n", t_num, pthread_self(), memtotal);
if (memtotal < 0)
memtotal = 512000;

pgsize = getpagesize();
for (i = 0; i < memtotal/1024/PNUM; i++) {
mp[i] = (int *)malloc(BLKSIZE);
if (mp[i] == 0) {
perror("malloc");
break;
}
ip = mp[i];
for (j = 0; j < BLKSIZE/pgsize/2; j++) {
*ip = 'A';
ip += pgsize/sizeof(int);
}

}
}


int main(int argc, char *argv[])
{
pthread_t pid1[1024];
pthread_t pid2[1024];
int i, fsize, thr_num[1024];
//int i, fsize;
int *ip, initv = 0x7fffffff;

if (argc < 2) {
printf("no seed file\n");
exit(1);
}
PNUM = get_p_num();
if (PNUM <= 1) {
printf("it is not a SMP system; exit\n");
exit(1);
}

CHK(fd = open(argv[1], O_RDWR));
CHK(fstat(fd, &sbuf));

fsize = sbuf.st_size;
DEBUG("pagesize is %d, file size is %ud\n", getpagesize(), sbuf.st_size);
if (fsize < BLKSIZE) {
printf("%s size is too small\n", argv[1]);
return -1;
}

ADDR = mmap(0, fsize, PROT_WRITE, MAP_SHARED, fd, 0);
if (ADDR == (void *)-1) {
perror("mmap ");
return -1;
}
for (fsize = sbuf.st_size, ip = ADDR; fsize > 0; fsize -= sizeof(int)) {
*ip = initv;
ip++;
}

for (fsize = sbuf.st_size, ip = ADDR; fsize > 0; fsize -= sizeof(int)) {
// DEBUG("cp value is %d initv is %d\n", *cp, initv);
if (*ip != initv)
break;
ip++;
}
if (fsize == 0)
DEBUG("set mem is OK\n");
else {
printf("set mem fail\n test failed\n");
return -1;
}
for (i = 0; i < PNUM; i++) {
thr_num[i] = i;
if (pthread_create(&pid2[i], NULL, threadfunc2, &i) != 0)
perror("phread_create");
}
sleep(8);
for (i = 0; i < PNUM; i++) {
thr_num[i] = i;
if (pthread_create(&pid1[i], NULL, threadfunc1, &i) != 0)
perror("phread_create");
}

for (i = 0; i < PNUM; i++)
pthread_join(pid1[i], NULL);
for (i = 0; i < PNUM; i++)
pthread_join(pid2[i], NULL);

for (fsize = sbuf.st_size, ip = ADDR; fsize > 0; fsize -= sizeof(int)) {
if (*ip != (initv - PNUM * CK)) {
printf("cp value is %d initv is %d\n", *ip, initv-PNUM * CK);
printf("test FAIL\n");
return -1;
}
ip++;
}
printf("PASS\n");
DEBUG("test PASS\n init value is 0x%x final value is 0x%x\n", initv, initv-PNUM * CK);
return 0;
}

16 changes: 16 additions & 0 deletions KVM/qemu/mem_coh.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- mem_coh:
no Windows
type = mem_coh
virt_test_type = qemu
vm_accelerator = kvm
force_create_image = no
remove_image = no
start_vm = yes
kill_vm = yes
auto_cpu_model = "no"
cpu_model = host
variants:
- vm:
- tdvm:
machine_type_extra_params = "kernel-irqchip=split"
vm_secure_guest_type = tdx
76 changes: 76 additions & 0 deletions KVM/qemu/tests/mem_coh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/python3

# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2025 Intel Corporation

# Author: Xudong Hao <[email protected]>
#
# History: Jan. 2025 - Xudong Hao - creation

import os

from virttest import data_dir, utils_package, utils_misc


def compile_mem_coh(test, vm, session):
"""
Copy and compile mem_coh on guest
:param test: QEMU test object
:param vm: Object qemu_vm.VM
:param session: vm session
:return: Path to binary mem_coh or None if compile failed
"""
mem_coh_dir = "/home/"
mem_coh_bin = "mem_coh"
mem_coh_c = "mem_coh.c"
src_file = os.path.join(data_dir.get_deps_dir("mem_coh"), mem_coh_c)
exec_bin = os.path.join(mem_coh_dir, mem_coh_bin)
rm_cmd = "rm -rf %s*" % exec_bin
session.cmd(rm_cmd)
vm.copy_files_to(src_file, mem_coh_dir)

if not utils_package.package_install("gcc", session):
test.cancel("Failed to install package gcc.")
compile_cmd = "cd %s && gcc -O2 -lpthread -DCONFIG_SMP -o %s %s" % (mem_coh_dir, mem_coh_bin, mem_coh_c)
guest_status = session.cmd_status(compile_cmd)
if guest_status:
session.cmd_output_safe(rm_cmd)
session.close()
test.fail("Compile mem_coh failed")
return exec_bin


def run(test, params, env):
"""
Memory coherency function test
1. Boot guest with multiple vCPUs
2. Download and compile mem_coh on guest
3. Run memory coherency test inside guest
4. Shutdown guest
:param test: QEMU test object
:param params: Dictionary with the test parameters
:param env: Dictionary with test environment
"""

def clean(tool_bin):
"""Clean the environment"""
cmd_rm = "rm -rf %s" % tool_bin
cmd_rm += "; rm -rf %s" % tmp_file
session.cmd_output_safe(cmd_rm)
session.close()

vm = env.get_vm(params["main_vm"])
tmp_file = "/tmp/smp-test-flag1_%s" % utils_misc.generate_random_string(6)
vm.verify_alive()
session = vm.wait_for_login()

tool_bin = compile_mem_coh(test, vm, session)
cmd_generate = "dd if=/dev/zero of=%s bs=1M count=10 && %s %s" % (tmp_file, tool_bin, tmp_file)
chk_status = session.cmd_status(cmd_generate)
if chk_status:
clean(tool_bin)
test.fail("Run mem_coh in guest with fail result")
clean(tool_bin)

0 comments on commit b814353

Please sign in to comment.