xref: /kvm-unit-tests/powerpc/tm.c (revision 831d679a261570d90187795222f43d33af2b6e82)
1adb87bc4SSuraj Jitindar Singh /*
2adb87bc4SSuraj Jitindar Singh  * Transactional Memory Unit Tests
3adb87bc4SSuraj Jitindar Singh  *
4adb87bc4SSuraj Jitindar Singh  * Copyright 2016 Suraj Jitindar Singh, IBM.
5adb87bc4SSuraj Jitindar Singh  *
6adb87bc4SSuraj Jitindar Singh  * This work is licensed under the terms of the GNU LGPL, version 2.
7adb87bc4SSuraj Jitindar Singh  */
8adb87bc4SSuraj Jitindar Singh #include <libcflat.h>
9adb87bc4SSuraj Jitindar Singh #include <asm/hcall.h>
10adb87bc4SSuraj Jitindar Singh #include <asm/processor.h>
11adb87bc4SSuraj Jitindar Singh #include <asm/handlers.h>
12adb87bc4SSuraj Jitindar Singh #include <asm/smp.h>
13cf54ca71SThomas Huth #include <asm/setup.h>
14cf54ca71SThomas Huth #include <devicetree.h>
15cf54ca71SThomas Huth 
16cf54ca71SThomas Huth /* Check "ibm,pa-features" property of a CPU node for the TM flag */
177a20b74eSAndrew Jones static void cpu_has_tm(int fdtnode, u64 regval __unused, void *ptr)
18cf54ca71SThomas Huth {
19cf54ca71SThomas Huth 	const struct fdt_property *prop;
20cf54ca71SThomas Huth 	int plen;
21cf54ca71SThomas Huth 
22cf54ca71SThomas Huth 	prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,pa-features", &plen);
23cf54ca71SThomas Huth 	if (!prop)	/* No features means TM is also not available */
24cf54ca71SThomas Huth 		return;
25cf54ca71SThomas Huth 	/* Sanity check for the property layout (first two bytes are header) */
26cf54ca71SThomas Huth 	assert(plen >= 8 && prop->data[1] == 0 && prop->data[0] <= plen - 2);
27cf54ca71SThomas Huth 
28cf54ca71SThomas Huth 	/*
29cf54ca71SThomas Huth 	 * The "Transactional Memory Category Support" flags are at byte
30cf54ca71SThomas Huth 	 * offset 22 and 23 of the attribute type 0, so when adding the
31cf54ca71SThomas Huth 	 * two bytes for the header, we've got to look at offset 24 for
32cf54ca71SThomas Huth 	 * the TM support bit.
33cf54ca71SThomas Huth 	 */
34cf54ca71SThomas Huth 	if (prop->data[0] >= 24 && (prop->data[24] & 0x80) != 0)
35cf54ca71SThomas Huth 		*(int *)ptr += 1;
36cf54ca71SThomas Huth }
37cf54ca71SThomas Huth 
38*831d679aSThomas Huth /* Check amount of CPUs nodes that have the TM flag */
39*831d679aSThomas Huth static int count_cpus_with_tm(void)
40cf54ca71SThomas Huth {
41cf54ca71SThomas Huth 	int ret;
42cf54ca71SThomas Huth 	int available = 0;
43cf54ca71SThomas Huth 
44cf54ca71SThomas Huth 	ret = dt_for_each_cpu_node(cpu_has_tm, &available);
45*831d679aSThomas Huth 	if (ret < 0)
46*831d679aSThomas Huth 		return ret;
47cf54ca71SThomas Huth 
48*831d679aSThomas Huth 	return available;
49cf54ca71SThomas Huth }
50adb87bc4SSuraj Jitindar Singh 
51adb87bc4SSuraj Jitindar Singh static int h_cede(void)
52adb87bc4SSuraj Jitindar Singh {
53adb87bc4SSuraj Jitindar Singh 	register uint64_t r3 asm("r3") = H_CEDE;
54adb87bc4SSuraj Jitindar Singh 
55adb87bc4SSuraj Jitindar Singh 	asm volatile ("sc 1" : "+r"(r3) :
56adb87bc4SSuraj Jitindar Singh 			     : "r0", "r4", "r5", "r6", "r7", "r8", "r9",
57adb87bc4SSuraj Jitindar Singh 			       "r10", "r11", "r12", "xer", "ctr", "cc");
58adb87bc4SSuraj Jitindar Singh 
59adb87bc4SSuraj Jitindar Singh 	return r3;
60adb87bc4SSuraj Jitindar Singh }
61adb87bc4SSuraj Jitindar Singh 
62adb87bc4SSuraj Jitindar Singh /*
63adb87bc4SSuraj Jitindar Singh  * Enable transactional memory
64adb87bc4SSuraj Jitindar Singh  * Returns:	FALSE - Failure
65adb87bc4SSuraj Jitindar Singh  *		TRUE - Success
66adb87bc4SSuraj Jitindar Singh  */
67adb87bc4SSuraj Jitindar Singh static bool enable_tm(void)
68adb87bc4SSuraj Jitindar Singh {
69adb87bc4SSuraj Jitindar Singh 	uint64_t msr = 0;
70adb87bc4SSuraj Jitindar Singh 
71adb87bc4SSuraj Jitindar Singh 	asm volatile ("mfmsr %[msr]" : [msr] "=r" (msr));
72adb87bc4SSuraj Jitindar Singh 
73adb87bc4SSuraj Jitindar Singh 	msr |= (((uint64_t) 1) << 32);
74adb87bc4SSuraj Jitindar Singh 
75adb87bc4SSuraj Jitindar Singh 	asm volatile ("mtmsrd %[msr]\n\t"
76adb87bc4SSuraj Jitindar Singh 		      "mfmsr %[msr]" : [msr] "+r" (msr));
77adb87bc4SSuraj Jitindar Singh 
78adb87bc4SSuraj Jitindar Singh 	return !!(msr & (((uint64_t) 1) << 32));
79adb87bc4SSuraj Jitindar Singh }
80adb87bc4SSuraj Jitindar Singh 
81adb87bc4SSuraj Jitindar Singh /*
82adb87bc4SSuraj Jitindar Singh  * Test H_CEDE call while transactional memory transaction is suspended
83adb87bc4SSuraj Jitindar Singh  *
84adb87bc4SSuraj Jitindar Singh  * WARNING: This tests for a known vulnerability in which the host may go down.
85adb87bc4SSuraj Jitindar Singh  * Probably best not to run this if your host going down is going to cause
86adb87bc4SSuraj Jitindar Singh  * problems.
87adb87bc4SSuraj Jitindar Singh  *
88adb87bc4SSuraj Jitindar Singh  * If the test passes then your kernel probably has the necessary patch.
89adb87bc4SSuraj Jitindar Singh  * If the test fails then the H_CEDE call was unsuccessful and the
90adb87bc4SSuraj Jitindar Singh  * vulnerability wasn't tested.
91adb87bc4SSuraj Jitindar Singh  * If the test hits the vulnerability then it will never complete or report and
92adb87bc4SSuraj Jitindar Singh  * the qemu process will block indefinitely. RCU stalls will be detected on the
93adb87bc4SSuraj Jitindar Singh  * cpu and any process scheduled on the lost cpu will also block indefinitely.
94adb87bc4SSuraj Jitindar Singh  */
95adb87bc4SSuraj Jitindar Singh static void test_h_cede_tm(int argc, char **argv)
96adb87bc4SSuraj Jitindar Singh {
97adb87bc4SSuraj Jitindar Singh 	int i;
98adb87bc4SSuraj Jitindar Singh 
99adb87bc4SSuraj Jitindar Singh 	if (argc > 2)
100adb87bc4SSuraj Jitindar Singh 		report_abort("Unsupported argument: '%s'", argv[2]);
101adb87bc4SSuraj Jitindar Singh 
102adb87bc4SSuraj Jitindar Singh 	handle_exception(0x900, &dec_except_handler, NULL);
103adb87bc4SSuraj Jitindar Singh 
104adb87bc4SSuraj Jitindar Singh 	if (!start_all_cpus(halt, 0))
105adb87bc4SSuraj Jitindar Singh 		report_abort("Failed to start secondary cpus");
106adb87bc4SSuraj Jitindar Singh 
107adb87bc4SSuraj Jitindar Singh 	if (!enable_tm())
108adb87bc4SSuraj Jitindar Singh 		report_abort("Failed to enable tm");
109adb87bc4SSuraj Jitindar Singh 
110adb87bc4SSuraj Jitindar Singh 	/*
111adb87bc4SSuraj Jitindar Singh 	 * Begin a transaction and guarantee we are in the suspend state
112adb87bc4SSuraj Jitindar Singh 	 * before continuing
113adb87bc4SSuraj Jitindar Singh 	 */
114adb87bc4SSuraj Jitindar Singh 	asm volatile ("1: .long 0x7c00051d\n\t"	/* tbegin. */
115adb87bc4SSuraj Jitindar Singh 		      "beq 2f\n\t"
116adb87bc4SSuraj Jitindar Singh 		      ".long 0x7c0005dd\n\t"	/* tsuspend. */
117adb87bc4SSuraj Jitindar Singh 		      "2: .long 0x7c00059c\n\t"	/* tcheck cr0 */
118adb87bc4SSuraj Jitindar Singh 		      "bf 2,1b" : : : "cr0");
119adb87bc4SSuraj Jitindar Singh 
120adb87bc4SSuraj Jitindar Singh 	for (i = 0; i < 500; i++) {
121adb87bc4SSuraj Jitindar Singh 		uint64_t rval = h_cede();
122adb87bc4SSuraj Jitindar Singh 
123adb87bc4SSuraj Jitindar Singh 		if (rval != H_SUCCESS)
124adb87bc4SSuraj Jitindar Singh 			break;
125adb87bc4SSuraj Jitindar Singh 		mdelay(5);
126adb87bc4SSuraj Jitindar Singh 	}
127adb87bc4SSuraj Jitindar Singh 
128adb87bc4SSuraj Jitindar Singh 	report("H_CEDE TM", i == 500);
129adb87bc4SSuraj Jitindar Singh }
130adb87bc4SSuraj Jitindar Singh 
131adb87bc4SSuraj Jitindar Singh struct {
132adb87bc4SSuraj Jitindar Singh 	const char *name;
133adb87bc4SSuraj Jitindar Singh 	void (*func)(int argc, char **argv);
134adb87bc4SSuraj Jitindar Singh } hctests[] = {
135adb87bc4SSuraj Jitindar Singh 	{ "h_cede_tm", test_h_cede_tm },
136adb87bc4SSuraj Jitindar Singh 	{ NULL, NULL }
137adb87bc4SSuraj Jitindar Singh };
138adb87bc4SSuraj Jitindar Singh 
139adb87bc4SSuraj Jitindar Singh int main(int argc, char **argv)
140adb87bc4SSuraj Jitindar Singh {
141*831d679aSThomas Huth 	bool all;
142*831d679aSThomas Huth 	int i, cpus_with_tm;
143adb87bc4SSuraj Jitindar Singh 
144adb87bc4SSuraj Jitindar Singh 	report_prefix_push("tm");
145adb87bc4SSuraj Jitindar Singh 
146*831d679aSThomas Huth 	cpus_with_tm = count_cpus_with_tm();
147*831d679aSThomas Huth 	if (cpus_with_tm == 0) {
148*831d679aSThomas Huth 		report_skip("TM is not available");
149*831d679aSThomas Huth 		goto done;
150*831d679aSThomas Huth 	}
151*831d679aSThomas Huth 	report("TM available in all 'ibm,pa-features' properties",
152*831d679aSThomas Huth 	       cpus_with_tm == nr_cpus);
153cf54ca71SThomas Huth 
154adb87bc4SSuraj Jitindar Singh 	all = argc == 1 || !strcmp(argv[1], "all");
155adb87bc4SSuraj Jitindar Singh 
156adb87bc4SSuraj Jitindar Singh 	for (i = 0; hctests[i].name != NULL; i++) {
157adb87bc4SSuraj Jitindar Singh 		if (all || strcmp(argv[1], hctests[i].name) == 0) {
158adb87bc4SSuraj Jitindar Singh 			report_prefix_push(hctests[i].name);
159adb87bc4SSuraj Jitindar Singh 			hctests[i].func(argc, argv);
160adb87bc4SSuraj Jitindar Singh 			report_prefix_pop();
161adb87bc4SSuraj Jitindar Singh 		}
162adb87bc4SSuraj Jitindar Singh 	}
163adb87bc4SSuraj Jitindar Singh 
164*831d679aSThomas Huth done:
165*831d679aSThomas Huth 	report_prefix_pop();
166adb87bc4SSuraj Jitindar Singh 	return report_summary();
167adb87bc4SSuraj Jitindar Singh }
168