xref: /kvm-unit-tests/s390x/stsi.c (revision 553125df6292c069377ad3351a7316dd7a68b8d6)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Store System Information tests
4  *
5  * Copyright (c) 2019 IBM Corp
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.ibm.com>
9  */
10 
11 #include <libcflat.h>
12 #include <asm/page.h>
13 #include <asm/asm-offsets.h>
14 #include <asm/interrupt.h>
15 #include <smp.h>
16 
17 struct stsi_322 {
18 	uint8_t reserved[31];
19 	uint8_t count;
20 	struct {
21 		uint8_t reserved2[4];
22 		uint16_t total_cpus;
23 		uint16_t conf_cpus;
24 		uint16_t standby_cpus;
25 		uint16_t reserved_cpus;
26 		uint8_t name[8];
27 		uint32_t caf;
28 		uint8_t cpi[16];
29 		uint8_t reserved5[3];
30 		uint8_t ext_name_encoding;
31 		uint32_t reserved3;
32 		uint8_t uuid[16];
33 	} vm[8];
34 	uint8_t reserved4[1504];
35 	uint8_t ext_names[8][256];
36 };
37 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
38 
39 static void test_specs(void)
40 {
41 	report_prefix_push("specification");
42 
43 	report_prefix_push("inv r0");
44 	expect_pgm_int();
45 	stsi(pagebuf, 0, 1 << 8, 0);
46 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
47 	report_prefix_pop();
48 
49 	report_prefix_push("inv r1");
50 	expect_pgm_int();
51 	stsi(pagebuf, 1, 0, 1 << 16);
52 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
53 	report_prefix_pop();
54 
55 	report_prefix_push("unaligned");
56 	expect_pgm_int();
57 	stsi(pagebuf + 42, 1, 1, 1);
58 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
59 	report_prefix_pop();
60 
61 	report_prefix_pop();
62 }
63 
64 static void test_priv(void)
65 {
66 	report_prefix_push("privileged");
67 	expect_pgm_int();
68 	enter_pstate();
69 	stsi(pagebuf, 0, 0, 0);
70 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
71 	report_prefix_pop();
72 }
73 
74 static inline unsigned long stsi_get_fc(void *addr)
75 {
76 	register unsigned long r0 asm("0") = 0;
77 	register unsigned long r1 asm("1") = 0;
78 	int cc;
79 
80 	asm volatile("stsi	0(%[addr])\n"
81 		     "ipm	%[cc]\n"
82 		     "srl	%[cc],28\n"
83 		     : "+d" (r0), [cc] "=d" (cc)
84 		     : "d" (r1), [addr] "a" (addr)
85 		     : "cc", "memory");
86 	assert(!cc);
87 	return r0 >> 28;
88 }
89 
90 static void test_fc(void)
91 {
92 	report(stsi(pagebuf, 7, 0, 0) == 3, "invalid fc");
93 	report(stsi(pagebuf, 1, 0, 1) == 3, "invalid selector 1");
94 	report(stsi(pagebuf, 1, 1, 0) == 3, "invalid selector 2");
95 	report(stsi_get_fc(pagebuf) >= 2, "query fc >= 2");
96 }
97 
98 static void test_3_2_2(void)
99 {
100 	int rc;
101 	/* EBCDIC for "kvm-unit" */
102 	const uint8_t vm_name[] = { 0x92, 0xa5, 0x94, 0x60, 0xa4, 0x95, 0x89,
103 				    0xa3 };
104 	const uint8_t uuid[] = { 0x0f, 0xb8, 0x4a, 0x86, 0x72, 0x7c,
105 				 0x11, 0xea, 0xbc, 0x55, 0x02, 0x42, 0xac, 0x13,
106 				 0x00, 0x03 };
107 	/* EBCDIC for "KVM/" */
108 	const uint8_t cpi_kvm[] = { 0xd2, 0xe5, 0xd4, 0x61 };
109 	const char vm_name_ext[] = "kvm-unit-test";
110 	struct stsi_322 *data = (void *)pagebuf;
111 
112 	report_prefix_push("3.2.2");
113 
114 	/* Is the function code available at all? */
115 	if (stsi_get_fc(pagebuf) < 3) {
116 		report_skip("Running under lpar, no level 3 to test.");
117 		goto out;
118 	}
119 
120 	rc = stsi(pagebuf, 3, 2, 2);
121 	report(!rc, "call");
122 
123 	/* For now we concentrate on KVM/QEMU */
124 	if (memcmp(&data->vm[0].cpi, cpi_kvm, sizeof(cpi_kvm))) {
125 		report_skip("Not running under KVM/QEMU.");
126 		goto out;
127 	}
128 
129 	report(!memcmp(data->vm[0].uuid, uuid, sizeof(uuid)), "uuid");
130 	report(data->vm[0].conf_cpus == smp_query_num_cpus(), "cpu count configured");
131 	report(data->vm[0].total_cpus ==
132 	       data->vm[0].reserved_cpus + data->vm[0].conf_cpus,
133 	       "cpu count total == conf + reserved");
134 	report(data->vm[0].standby_cpus == 0, "cpu count standby");
135 	report(!memcmp(data->vm[0].name, vm_name, sizeof(data->vm[0].name)),
136 	       "VM name == kvm-unit-test");
137 
138 	if (data->vm[0].ext_name_encoding != 2) {
139 		report_skip("Extended VM names are not UTF-8.");
140 		goto out;
141 	}
142 	report(!memcmp(data->ext_names[0], vm_name_ext, sizeof(vm_name_ext)),
143 		       "ext VM name == kvm-unit-test");
144 
145 out:
146 	report_prefix_pop();
147 }
148 
149 int main(void)
150 {
151 	report_prefix_push("stsi");
152 	test_priv();
153 	test_specs();
154 	test_fc();
155 	test_3_2_2();
156 	return report_summary();
157 }
158