xref: /kvm-unit-tests/s390x/stfle-sie.c (revision 2f3c02862e03fc1965b2bb54861a505fd4f6d1e5)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright IBM Corp. 2023
4  *
5  * SIE with STLFE interpretive execution facilities test.
6  */
7 #include <libcflat.h>
8 #include <stdlib.h>
9 #include <asm/facility.h>
10 #include <asm/time.h>
11 #include <snippet.h>
12 #include <snippet-exit.h>
13 #include <alloc_page.h>
14 #include <sclp.h>
15 #include <rand.h>
16 
17 static struct vm vm;
18 static uint64_t (*fac)[PAGE_SIZE / sizeof(uint64_t)];
19 static prng_state prng_s;
20 
21 static void setup_guest(void)
22 {
23 	extern const char SNIPPET_NAME_START(c, stfle)[];
24 	extern const char SNIPPET_NAME_END(c, stfle)[];
25 
26 	setup_vm();
27 	fac = alloc_pages_flags(0, AREA_DMA31);
28 
29 	snippet_setup_guest(&vm, false);
30 	snippet_init(&vm, SNIPPET_NAME_START(c, stfle),
31 		     SNIPPET_LEN(c, stfle), SNIPPET_UNPACK_OFF);
32 }
33 
34 struct guest_stfle_res {
35 	uint16_t len;
36 	unsigned char *mem;
37 };
38 
39 static struct guest_stfle_res run_guest(void)
40 {
41 	struct guest_stfle_res res;
42 	uint64_t guest_stfle_addr;
43 	uint64_t reg;
44 
45 	sie(&vm);
46 	assert(snippet_is_force_exit_value(&vm));
47 	guest_stfle_addr = snippet_get_force_exit_value(&vm);
48 	res.mem = &vm.guest_mem[guest_stfle_addr];
49 	memcpy(&reg, res.mem, sizeof(reg));
50 	res.len = (reg & 0xff) + 1;
51 	res.mem += sizeof(reg);
52 	return res;
53 }
54 
55 static void test_stfle_format_0(void)
56 {
57 	struct guest_stfle_res res;
58 
59 	report_prefix_push("format-0");
60 	for (int j = 0; j < stfle_size(); j++)
61 		WRITE_ONCE((*fac)[j], prng64(&prng_s));
62 	vm.sblk->fac = (uint32_t)(uint64_t)fac;
63 	res = run_guest();
64 	report(res.len == stfle_size(), "stfle len correct");
65 	report(!memcmp(*fac, res.mem, res.len * sizeof(uint64_t)),
66 	       "Guest facility list as specified");
67 	report_prefix_pop();
68 }
69 
70 struct args {
71 	uint64_t seed;
72 };
73 
74 static bool parse_uint64_t(const char *arg, uint64_t *out)
75 {
76 	char *end;
77 	uint64_t num;
78 
79 	if (arg[0] == '\0')
80 		return false;
81 	num = strtoul(arg, &end, 0);
82 	if (end[0] != '\0')
83 		return false;
84 	*out = num;
85 	return true;
86 }
87 
88 static struct args parse_args(int argc, char **argv)
89 {
90 	struct args args;
91 	const char *flag;
92 	unsigned int i;
93 	uint64_t arg;
94 	bool has_arg;
95 
96 	stck(&args.seed);
97 
98 	for (i = 1; i < argc; i++) {
99 		if (i + 1 < argc)
100 			has_arg = parse_uint64_t(argv[i + 1], &arg);
101 		else
102 			has_arg = false;
103 
104 		flag = "--seed";
105 		if (!strcmp(flag, argv[i])) {
106 			if (!has_arg)
107 				report_abort("%s needs an uint64_t parameter", flag);
108 			args.seed = arg;
109 			++i;
110 			continue;
111 		}
112 		report_abort("Unsupported parameter '%s'",
113 			     argv[i]);
114 	}
115 
116 	return args;
117 }
118 
119 int main(int argc, char **argv)
120 {
121 	struct args args = parse_args(argc, argv);
122 	bool run_format_0 = test_facility(7);
123 
124 	if (!sclp_facilities.has_sief2) {
125 		report_skip("SIEF2 facility unavailable");
126 		goto out;
127 	}
128 	if (!run_format_0)
129 		report_skip("STFLE facility not available");
130 
131 	report_info("PRNG seed: 0x%lx", args.seed);
132 	prng_s = prng_init(args.seed);
133 	setup_guest();
134 	if (run_format_0)
135 		test_stfle_format_0();
136 out:
137 	return report_summary();
138 }
139