xref: /kvm-unit-tests/powerpc/tm.c (revision adb87bc4356a7a15083ba48852d342bd27dc426b)
1*adb87bc4SSuraj Jitindar Singh /*
2*adb87bc4SSuraj Jitindar Singh  * Transactional Memory Unit Tests
3*adb87bc4SSuraj Jitindar Singh  *
4*adb87bc4SSuraj Jitindar Singh  * Copyright 2016 Suraj Jitindar Singh, IBM.
5*adb87bc4SSuraj Jitindar Singh  *
6*adb87bc4SSuraj Jitindar Singh  * This work is licensed under the terms of the GNU LGPL, version 2.
7*adb87bc4SSuraj Jitindar Singh  */
8*adb87bc4SSuraj Jitindar Singh #include <libcflat.h>
9*adb87bc4SSuraj Jitindar Singh #include <asm/hcall.h>
10*adb87bc4SSuraj Jitindar Singh #include <asm/processor.h>
11*adb87bc4SSuraj Jitindar Singh #include <asm/handlers.h>
12*adb87bc4SSuraj Jitindar Singh #include <asm/smp.h>
13*adb87bc4SSuraj Jitindar Singh 
14*adb87bc4SSuraj Jitindar Singh static int h_cede(void)
15*adb87bc4SSuraj Jitindar Singh {
16*adb87bc4SSuraj Jitindar Singh 	register uint64_t r3 asm("r3") = H_CEDE;
17*adb87bc4SSuraj Jitindar Singh 
18*adb87bc4SSuraj Jitindar Singh 	asm volatile ("sc 1" : "+r"(r3) :
19*adb87bc4SSuraj Jitindar Singh 			     : "r0", "r4", "r5", "r6", "r7", "r8", "r9",
20*adb87bc4SSuraj Jitindar Singh 			       "r10", "r11", "r12", "xer", "ctr", "cc");
21*adb87bc4SSuraj Jitindar Singh 
22*adb87bc4SSuraj Jitindar Singh 	return r3;
23*adb87bc4SSuraj Jitindar Singh }
24*adb87bc4SSuraj Jitindar Singh 
25*adb87bc4SSuraj Jitindar Singh /*
26*adb87bc4SSuraj Jitindar Singh  * Enable transactional memory
27*adb87bc4SSuraj Jitindar Singh  * Returns:	FALSE - Failure
28*adb87bc4SSuraj Jitindar Singh  *		TRUE - Success
29*adb87bc4SSuraj Jitindar Singh  */
30*adb87bc4SSuraj Jitindar Singh static bool enable_tm(void)
31*adb87bc4SSuraj Jitindar Singh {
32*adb87bc4SSuraj Jitindar Singh 	uint64_t msr = 0;
33*adb87bc4SSuraj Jitindar Singh 
34*adb87bc4SSuraj Jitindar Singh 	asm volatile ("mfmsr %[msr]" : [msr] "=r" (msr));
35*adb87bc4SSuraj Jitindar Singh 
36*adb87bc4SSuraj Jitindar Singh 	msr |= (((uint64_t) 1) << 32);
37*adb87bc4SSuraj Jitindar Singh 
38*adb87bc4SSuraj Jitindar Singh 	asm volatile ("mtmsrd %[msr]\n\t"
39*adb87bc4SSuraj Jitindar Singh 		      "mfmsr %[msr]" : [msr] "+r" (msr));
40*adb87bc4SSuraj Jitindar Singh 
41*adb87bc4SSuraj Jitindar Singh 	return !!(msr & (((uint64_t) 1) << 32));
42*adb87bc4SSuraj Jitindar Singh }
43*adb87bc4SSuraj Jitindar Singh 
44*adb87bc4SSuraj Jitindar Singh /*
45*adb87bc4SSuraj Jitindar Singh  * Test H_CEDE call while transactional memory transaction is suspended
46*adb87bc4SSuraj Jitindar Singh  *
47*adb87bc4SSuraj Jitindar Singh  * WARNING: This tests for a known vulnerability in which the host may go down.
48*adb87bc4SSuraj Jitindar Singh  * Probably best not to run this if your host going down is going to cause
49*adb87bc4SSuraj Jitindar Singh  * problems.
50*adb87bc4SSuraj Jitindar Singh  *
51*adb87bc4SSuraj Jitindar Singh  * If the test passes then your kernel probably has the necessary patch.
52*adb87bc4SSuraj Jitindar Singh  * If the test fails then the H_CEDE call was unsuccessful and the
53*adb87bc4SSuraj Jitindar Singh  * vulnerability wasn't tested.
54*adb87bc4SSuraj Jitindar Singh  * If the test hits the vulnerability then it will never complete or report and
55*adb87bc4SSuraj Jitindar Singh  * the qemu process will block indefinitely. RCU stalls will be detected on the
56*adb87bc4SSuraj Jitindar Singh  * cpu and any process scheduled on the lost cpu will also block indefinitely.
57*adb87bc4SSuraj Jitindar Singh  */
58*adb87bc4SSuraj Jitindar Singh static void test_h_cede_tm(int argc, char **argv)
59*adb87bc4SSuraj Jitindar Singh {
60*adb87bc4SSuraj Jitindar Singh 	int i;
61*adb87bc4SSuraj Jitindar Singh 
62*adb87bc4SSuraj Jitindar Singh 	if (argc > 2)
63*adb87bc4SSuraj Jitindar Singh 		report_abort("Unsupported argument: '%s'", argv[2]);
64*adb87bc4SSuraj Jitindar Singh 
65*adb87bc4SSuraj Jitindar Singh 	handle_exception(0x900, &dec_except_handler, NULL);
66*adb87bc4SSuraj Jitindar Singh 
67*adb87bc4SSuraj Jitindar Singh 	if (!start_all_cpus(halt, 0))
68*adb87bc4SSuraj Jitindar Singh 		report_abort("Failed to start secondary cpus");
69*adb87bc4SSuraj Jitindar Singh 
70*adb87bc4SSuraj Jitindar Singh 	if (!enable_tm())
71*adb87bc4SSuraj Jitindar Singh 		report_abort("Failed to enable tm");
72*adb87bc4SSuraj Jitindar Singh 
73*adb87bc4SSuraj Jitindar Singh 	/*
74*adb87bc4SSuraj Jitindar Singh 	 * Begin a transaction and guarantee we are in the suspend state
75*adb87bc4SSuraj Jitindar Singh 	 * before continuing
76*adb87bc4SSuraj Jitindar Singh 	 */
77*adb87bc4SSuraj Jitindar Singh 	asm volatile ("1: .long 0x7c00051d\n\t"	/* tbegin. */
78*adb87bc4SSuraj Jitindar Singh 		      "beq 2f\n\t"
79*adb87bc4SSuraj Jitindar Singh 		      ".long 0x7c0005dd\n\t"	/* tsuspend. */
80*adb87bc4SSuraj Jitindar Singh 		      "2: .long 0x7c00059c\n\t"	/* tcheck cr0 */
81*adb87bc4SSuraj Jitindar Singh 		      "bf 2,1b" : : : "cr0");
82*adb87bc4SSuraj Jitindar Singh 
83*adb87bc4SSuraj Jitindar Singh 	for (i = 0; i < 500; i++) {
84*adb87bc4SSuraj Jitindar Singh 		uint64_t rval = h_cede();
85*adb87bc4SSuraj Jitindar Singh 
86*adb87bc4SSuraj Jitindar Singh 		if (rval != H_SUCCESS)
87*adb87bc4SSuraj Jitindar Singh 			break;
88*adb87bc4SSuraj Jitindar Singh 		mdelay(5);
89*adb87bc4SSuraj Jitindar Singh 	}
90*adb87bc4SSuraj Jitindar Singh 
91*adb87bc4SSuraj Jitindar Singh 	report("H_CEDE TM", i == 500);
92*adb87bc4SSuraj Jitindar Singh }
93*adb87bc4SSuraj Jitindar Singh 
94*adb87bc4SSuraj Jitindar Singh struct {
95*adb87bc4SSuraj Jitindar Singh 	const char *name;
96*adb87bc4SSuraj Jitindar Singh 	void (*func)(int argc, char **argv);
97*adb87bc4SSuraj Jitindar Singh } hctests[] = {
98*adb87bc4SSuraj Jitindar Singh 	{ "h_cede_tm", test_h_cede_tm },
99*adb87bc4SSuraj Jitindar Singh 	{ NULL, NULL }
100*adb87bc4SSuraj Jitindar Singh };
101*adb87bc4SSuraj Jitindar Singh 
102*adb87bc4SSuraj Jitindar Singh int main(int argc, char **argv)
103*adb87bc4SSuraj Jitindar Singh {
104*adb87bc4SSuraj Jitindar Singh 	bool all;
105*adb87bc4SSuraj Jitindar Singh 	int i;
106*adb87bc4SSuraj Jitindar Singh 
107*adb87bc4SSuraj Jitindar Singh 	report_prefix_push("tm");
108*adb87bc4SSuraj Jitindar Singh 
109*adb87bc4SSuraj Jitindar Singh 	all = argc == 1 || !strcmp(argv[1], "all");
110*adb87bc4SSuraj Jitindar Singh 
111*adb87bc4SSuraj Jitindar Singh 	for (i = 0; hctests[i].name != NULL; i++) {
112*adb87bc4SSuraj Jitindar Singh 		if (all || strcmp(argv[1], hctests[i].name) == 0) {
113*adb87bc4SSuraj Jitindar Singh 			report_prefix_push(hctests[i].name);
114*adb87bc4SSuraj Jitindar Singh 			hctests[i].func(argc, argv);
115*adb87bc4SSuraj Jitindar Singh 			report_prefix_pop();
116*adb87bc4SSuraj Jitindar Singh 		}
117*adb87bc4SSuraj Jitindar Singh 	}
118*adb87bc4SSuraj Jitindar Singh 
119*adb87bc4SSuraj Jitindar Singh 	return report_summary();
120*adb87bc4SSuraj Jitindar Singh }
121