xref: /kvm-unit-tests/s390x/sck.c (revision 832e1c1596445f17d1542fc89aba81419154a4ca)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Perform Set Clock tests
4  *
5  * Copyright IBM Corp. 2022
6  *
7  * Authors:
8  *  Nico Boehr <nrb@linux.ibm.com>
9  */
10 #include <libcflat.h>
11 #include <uv.h>
12 #include <asm/interrupt.h>
13 #include <asm/time.h>
14 
15 static inline int sck(uint64_t *time)
16 {
17 	int cc;
18 
19 	asm volatile(
20 		"	sck %[time]\n"
21 		"	ipm %[cc]\n"
22 		"	srl %[cc],28\n"
23 		: [cc] "=d"(cc)
24 		: [time] "Q"(*time)
25 		: "cc"
26 	);
27 
28 	return cc;
29 }
30 
31 static inline int stck(uint64_t *time)
32 {
33 	int cc;
34 
35 	asm volatile(
36 		"	stck %[time]\n"
37 		"	ipm %[cc]\n"
38 		"	srl %[cc],28\n"
39 		: [cc] "=d" (cc), [time] "=Q" (*time)
40 		:
41 		: "cc", "memory"
42 	);
43 
44 	return cc;
45 }
46 
47 static void test_priv(void)
48 {
49 	uint64_t time_to_set_privileged = 0xfacef00dcafe0000,
50 	    time_to_set_nonprivileged = 0xcafe0000,
51 	    time_verify;
52 	int cc;
53 
54 	report_prefix_push("privileged");
55 	cc = sck(&time_to_set_privileged);
56 	report(!cc, "set clock cc=%d", cc);
57 
58 	cc = stck(&time_verify);
59 	report(!cc, "store clock cc=%d", cc);
60 	report(time_verify > time_to_set_privileged,
61 	       "privileged set affected the clock");
62 	report_prefix_pop();
63 
64 	report_prefix_push("unprivileged");
65 	expect_pgm_int();
66 	enter_pstate();
67 	sck(&time_to_set_nonprivileged);
68 	leave_pstate();
69 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
70 
71 	cc = stck(&time_verify);
72 	report(!cc, "store clock cc=%d", cc);
73 	report(time_verify > time_to_set_privileged,
74 	       "unprivileged set did not affect the clock");
75 	report_prefix_pop();
76 }
77 
78 static void test_align(void)
79 {
80 	const int align_to = 8;
81 	char unalign[sizeof(uint64_t) + align_to] __attribute__((aligned(8)));
82 
83 	report_prefix_push("Unaligned operand");
84 	for (int i = 1; i < align_to; i *= 2) {
85 		report_prefix_pushf("%d", i);
86 		expect_pgm_int();
87 		sck((uint64_t *)(unalign + i));
88 		check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
89 		report_prefix_pop();
90 	}
91 	report_prefix_pop();
92 }
93 
94 static void test_set(void)
95 {
96 	uint64_t start = 0, end = 0, time = 0xcafef00dbeef;
97 	const uint64_t ticks_per_ms = 1000 << 12, ms_to_wait = 5;
98 	int cc;
99 
100 	report_prefix_push("set");
101 
102 	cc = sck(&time);
103 	report(!cc, "set clock cc=%d", cc);
104 
105 	cc = stck(&start);
106 	report(!cc, "store start clock cc=%d", cc);
107 	report(start >= time, "start >= set value");
108 
109 	mdelay(ms_to_wait);
110 
111 	cc = stck(&end);
112 	report(!cc, "store end clock cc=%d", cc);
113 	report(end > time, "end > set value");
114 
115 	report(end - start > (ticks_per_ms * ms_to_wait), "Advances");
116 
117 	report_prefix_pop();
118 }
119 
120 int main(void)
121 {
122 	report_prefix_push("sck");
123 
124 	if (uv_os_is_guest()) {
125 		report_skip("Test unsupported under PV");
126 		goto out;
127 	}
128 
129 	test_align();
130 	test_set();
131 	test_priv();
132 
133 out:
134 	report_prefix_pop();
135 	return report_summary();
136 }
137