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