162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2017, Michael Neuling, IBM Corp.
462306a36Sopenharmony_ci * Original: Breno Leitao <brenohl@br.ibm.com> &
562306a36Sopenharmony_ci *           Gustavo Bueno Romero <gromero@br.ibm.com>
662306a36Sopenharmony_ci * Edited: Michael Neuling
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Force VMX unavailable during a transaction and see if it corrupts
962306a36Sopenharmony_ci * the checkpointed VMX register state after the abort.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <inttypes.h>
1362306a36Sopenharmony_ci#include <htmintrin.h>
1462306a36Sopenharmony_ci#include <string.h>
1562306a36Sopenharmony_ci#include <stdlib.h>
1662306a36Sopenharmony_ci#include <stdio.h>
1762306a36Sopenharmony_ci#include <pthread.h>
1862306a36Sopenharmony_ci#include <sys/mman.h>
1962306a36Sopenharmony_ci#include <unistd.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "tm.h"
2262306a36Sopenharmony_ci#include "utils.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciint passed;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_civoid *worker(void *unused)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	__int128 vmx0;
2962306a36Sopenharmony_ci	uint64_t texasr;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	asm goto (
3262306a36Sopenharmony_ci		"li       3, 1;"  /* Stick non-zero value in VMX0 */
3362306a36Sopenharmony_ci		"std      3, 0(%[vmx0_ptr]);"
3462306a36Sopenharmony_ci		"lvx      0, 0, %[vmx0_ptr];"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci		/* Wait here a bit so we get scheduled out 255 times */
3762306a36Sopenharmony_ci		"lis      3, 0x3fff;"
3862306a36Sopenharmony_ci		"1: ;"
3962306a36Sopenharmony_ci		"addi     3, 3, -1;"
4062306a36Sopenharmony_ci		"cmpdi    3, 0;"
4162306a36Sopenharmony_ci		"bne      1b;"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci		/* Kernel will hopefully turn VMX off now */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		"tbegin. ;"
4662306a36Sopenharmony_ci		"beq      failure;"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci		/* Cause VMX unavail. Any VMX instruction */
4962306a36Sopenharmony_ci		"vaddcuw  0,0,0;"
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		"tend. ;"
5262306a36Sopenharmony_ci		"b        %l[success];"
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		/* Check VMX0 sanity after abort */
5562306a36Sopenharmony_ci		"failure: ;"
5662306a36Sopenharmony_ci		"lvx       1,  0, %[vmx0_ptr];"
5762306a36Sopenharmony_ci		"vcmpequb. 2,  0, 1;"
5862306a36Sopenharmony_ci		"bc        4, 24, %l[value_mismatch];"
5962306a36Sopenharmony_ci		"b        %l[value_match];"
6062306a36Sopenharmony_ci		:
6162306a36Sopenharmony_ci		: [vmx0_ptr] "r"(&vmx0)
6262306a36Sopenharmony_ci		: "r3"
6362306a36Sopenharmony_ci		: success, value_match, value_mismatch
6462306a36Sopenharmony_ci		);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* HTM aborted and VMX0 is corrupted */
6762306a36Sopenharmony_civalue_mismatch:
6862306a36Sopenharmony_ci	texasr = __builtin_get_texasr();
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	printf("\n\n==============\n\n");
7162306a36Sopenharmony_ci	printf("Failure with error: %lx\n",   _TEXASR_FAILURE_CODE(texasr));
7262306a36Sopenharmony_ci	printf("Summary error     : %lx\n",   _TEXASR_FAILURE_SUMMARY(texasr));
7362306a36Sopenharmony_ci	printf("TFIAR exact       : %lx\n\n", _TEXASR_TFIAR_EXACT(texasr));
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	passed = 0;
7662306a36Sopenharmony_ci	return NULL;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* HTM aborted but VMX0 is correct */
7962306a36Sopenharmony_civalue_match:
8062306a36Sopenharmony_ci//	printf("!");
8162306a36Sopenharmony_ci	return NULL;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cisuccess:
8462306a36Sopenharmony_ci//	printf(".");
8562306a36Sopenharmony_ci	return NULL;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciint tm_vmx_unavail_test()
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int threads;
9162306a36Sopenharmony_ci	pthread_t *thread;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	SKIP_IF(!have_htm());
9462306a36Sopenharmony_ci	SKIP_IF(htm_is_synthetic());
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	passed = 1;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	threads = sysconf(_SC_NPROCESSORS_ONLN) * 4;
9962306a36Sopenharmony_ci	thread = malloc(sizeof(pthread_t)*threads);
10062306a36Sopenharmony_ci	if (!thread)
10162306a36Sopenharmony_ci		return EXIT_FAILURE;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	for (uint64_t i = 0; i < threads; i++)
10462306a36Sopenharmony_ci		pthread_create(&thread[i], NULL, &worker, NULL);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	for (uint64_t i = 0; i < threads; i++)
10762306a36Sopenharmony_ci		pthread_join(thread[i], NULL);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	free(thread);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return passed ? EXIT_SUCCESS : EXIT_FAILURE;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciint main(int argc, char **argv)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	return test_harness(tm_vmx_unavail_test, "tm_vmx_unavail_test");
11862306a36Sopenharmony_ci}
119