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
setup_guest(void)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
run_guest(void)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(®, res.mem, sizeof(reg));
50 res.len = (reg & 0xff) + 1;
51 res.mem += sizeof(reg);
52 return res;
53 }
54
test_stfle_format_0(void)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
parse_uint64_t(const char * arg,uint64_t * out)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
parse_args(int argc,char ** argv)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
main(int argc,char ** argv)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