1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
2e2db2954SJanosch Frank /*
3e2db2954SJanosch Frank * Tests exceptions and data validity for the emulated sthyi
4e2db2954SJanosch Frank * instruction.
5e2db2954SJanosch Frank *
6e2db2954SJanosch Frank * Copyright 2018 IBM Corp.
7e2db2954SJanosch Frank *
8e2db2954SJanosch Frank * Authors:
9e2db2954SJanosch Frank * Janosch Frank <frankja@linux.vnet.ibm.com>
10e2db2954SJanosch Frank */
11e2db2954SJanosch Frank #include <libcflat.h>
12e2db2954SJanosch Frank #include <asm/asm-offsets.h>
13e2db2954SJanosch Frank #include <asm/interrupt.h>
14e2db2954SJanosch Frank #include <asm/page.h>
15e2db2954SJanosch Frank #include <asm/facility.h>
16e2db2954SJanosch Frank
17e2db2954SJanosch Frank #include "sthyi.h"
18e2db2954SJanosch Frank
19e2db2954SJanosch Frank static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
20e2db2954SJanosch Frank static char null_buf[32] = {};
21e2db2954SJanosch Frank
sthyi(uint64_t vaddr,uint64_t fcode,uint64_t * rc,unsigned int r1,unsigned int r2)22e2db2954SJanosch Frank static inline int sthyi(uint64_t vaddr, uint64_t fcode, uint64_t *rc,
23e2db2954SJanosch Frank unsigned int r1, unsigned int r2)
24e2db2954SJanosch Frank {
25e2db2954SJanosch Frank register uint64_t code asm("0") = fcode;
26e2db2954SJanosch Frank register uint64_t addr asm("2") = vaddr;
27*b3546acfSJanosch Frank register uint64_t rc3 asm("3") = 42;
28e2db2954SJanosch Frank int cc = 0;
29e2db2954SJanosch Frank
30*b3546acfSJanosch Frank asm volatile(
31*b3546acfSJanosch Frank ".insn rre,0xB2560000,%[r1],%[r2]\n"
32e2db2954SJanosch Frank "ipm %[cc]\n"
33e2db2954SJanosch Frank "srl %[cc],28\n"
34*b3546acfSJanosch Frank : [cc] "=d" (cc), "+d" (rc3)
35*b3546acfSJanosch Frank : [code] "d" (code), [addr] "a" (addr), [r1] "i" (r1), [r2] "i" (r2)
36*b3546acfSJanosch Frank : "memory", "cc");
37e2db2954SJanosch Frank if (rc)
38e2db2954SJanosch Frank *rc = rc3;
39e2db2954SJanosch Frank return cc;
40e2db2954SJanosch Frank }
41e2db2954SJanosch Frank
test_exception_addr(void)42e2db2954SJanosch Frank static void test_exception_addr(void)
43e2db2954SJanosch Frank {
44e2db2954SJanosch Frank report_prefix_push("Illegal address check");
45e2db2954SJanosch Frank expect_pgm_int();
46e2db2954SJanosch Frank sthyi(42042, 0, NULL, 0, 2);
47e2db2954SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
48e2db2954SJanosch Frank report_prefix_pop();
49e2db2954SJanosch Frank }
50e2db2954SJanosch Frank
test_exception_reg_odd(void)51e2db2954SJanosch Frank static void test_exception_reg_odd(void)
52e2db2954SJanosch Frank {
5392c5b9c0SJanosch Frank report_prefix_push("Register check odd R1");
54e2db2954SJanosch Frank expect_pgm_int();
55e2db2954SJanosch Frank sthyi((uint64_t)pagebuf, 0, NULL, 1, 2);
56e2db2954SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
5792c5b9c0SJanosch Frank report_prefix_pop();
5892c5b9c0SJanosch Frank report_prefix_push("Register check odd R2");
59e2db2954SJanosch Frank expect_pgm_int();
60e2db2954SJanosch Frank sthyi((uint64_t)pagebuf, 0, NULL, 0, 3);
61e2db2954SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
62e2db2954SJanosch Frank report_prefix_pop();
63e2db2954SJanosch Frank }
64e2db2954SJanosch Frank
test_exception_reg_equal(void)65e2db2954SJanosch Frank static void test_exception_reg_equal(void)
66e2db2954SJanosch Frank {
67e2db2954SJanosch Frank report_prefix_push("Register check equal");
68e2db2954SJanosch Frank expect_pgm_int();
69e2db2954SJanosch Frank sthyi((uint64_t)pagebuf, 0, NULL, 0, 0);
70e2db2954SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
71e2db2954SJanosch Frank report_prefix_pop();
72e2db2954SJanosch Frank }
73e2db2954SJanosch Frank
test_function_code(uint64_t addr)74e2db2954SJanosch Frank static void test_function_code(uint64_t addr)
75e2db2954SJanosch Frank {
76e2db2954SJanosch Frank uint64_t urc = 0;
77e2db2954SJanosch Frank int cc = sthyi((uint64_t)pagebuf, 42, &urc, 0, 2);
78e2db2954SJanosch Frank
79a299895bSThomas Huth report(cc == 3 && urc == CODE_UNSUPP, "Illegal fcode");
80e2db2954SJanosch Frank }
81e2db2954SJanosch Frank
test_fcode0_hdr(struct sthyi_hdr_sctn * hdr)82e2db2954SJanosch Frank static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr)
83e2db2954SJanosch Frank {
8492c5b9c0SJanosch Frank report_prefix_push("Header");
8592c5b9c0SJanosch Frank
86a299895bSThomas Huth report(hdr->INFHDLN >= sizeof(*hdr) && !(hdr->INFHDLN % 8), "length");
87a299895bSThomas Huth report((hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn) && !(hdr->INFMLEN % 8)),
88a299895bSThomas Huth "Machine sctn length");
89a299895bSThomas Huth report((hdr->INFPLEN >= sizeof(struct sthyi_par_sctn) && !(hdr->INFPLEN % 8)),
90a299895bSThomas Huth "Partition section length");
91e2db2954SJanosch Frank
92a299895bSThomas Huth report(hdr->INFMOFF >= hdr->INFHDLN, "Machine offset");
93a299895bSThomas Huth report(hdr->INFPOFF >= hdr->INFHDLN, "Partition offset");
9492c5b9c0SJanosch Frank report_prefix_pop();
95e2db2954SJanosch Frank }
96e2db2954SJanosch Frank
test_fcode0_mach(struct sthyi_mach_sctn * mach)97e2db2954SJanosch Frank static void test_fcode0_mach(struct sthyi_mach_sctn *mach)
98e2db2954SJanosch Frank {
99e2db2954SJanosch Frank int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL;
100e2db2954SJanosch Frank
10192c5b9c0SJanosch Frank report_prefix_push("Machine");
102e2db2954SJanosch Frank if (mach->INFMVAL1 & MACH_ID_VLD) {
103a299895bSThomas Huth report(memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE)),
104a299895bSThomas Huth "type");
105a299895bSThomas Huth report(memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU)),
106a299895bSThomas Huth "manufacturer");
107a299895bSThomas Huth report(memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ)),
108a299895bSThomas Huth "sequence");
109a299895bSThomas Huth report(memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN)),
110a299895bSThomas Huth "plant");
111e2db2954SJanosch Frank }
112e2db2954SJanosch Frank
113e2db2954SJanosch Frank if (mach->INFMVAL1 & MACH_NAME_VLD)
114a299895bSThomas Huth report(memcmp(mach->INFMNAME, null_buf, sizeof(mach->INFMNAME)),
115a299895bSThomas Huth "name");
116e2db2954SJanosch Frank
117e2db2954SJanosch Frank if (mach->INFMVAL1 & MACH_CNT_VLD)
118a299895bSThomas Huth report(sum, "core counts");
11992c5b9c0SJanosch Frank report_prefix_pop();
120e2db2954SJanosch Frank }
121e2db2954SJanosch Frank
test_fcode0_par(struct sthyi_par_sctn * par)122e2db2954SJanosch Frank static void test_fcode0_par(struct sthyi_par_sctn *par)
123e2db2954SJanosch Frank {
124e2db2954SJanosch Frank int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL;
125e2db2954SJanosch Frank
12692c5b9c0SJanosch Frank report_prefix_push("Partition");
127e2db2954SJanosch Frank if (par->INFPVAL1 & PART_CNT_VLD)
128a299895bSThomas Huth report(sum, "core counts");
129e2db2954SJanosch Frank
130e2db2954SJanosch Frank if (par->INFPVAL1 & PART_STSI_SUC) {
131a299895bSThomas Huth report(memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM)),
132a299895bSThomas Huth "name");
133e2db2954SJanosch Frank }
13492c5b9c0SJanosch Frank report_prefix_pop();
135e2db2954SJanosch Frank }
136e2db2954SJanosch Frank
test_fcode0(void)137e2db2954SJanosch Frank static void test_fcode0(void)
138e2db2954SJanosch Frank {
139e2db2954SJanosch Frank struct sthyi_hdr_sctn *hdr;
140e2db2954SJanosch Frank struct sthyi_mach_sctn *mach;
141e2db2954SJanosch Frank struct sthyi_par_sctn *par;
142*b3546acfSJanosch Frank uint64_t rc = 42;
143*b3546acfSJanosch Frank int cc;
144e2db2954SJanosch Frank
145e2db2954SJanosch Frank /* Zero destination memory. */
146e2db2954SJanosch Frank memset(pagebuf, 0, PAGE_SIZE);
147e2db2954SJanosch Frank
14892c5b9c0SJanosch Frank report_prefix_push("fcode 0");
149*b3546acfSJanosch Frank cc = sthyi((uint64_t)pagebuf, 0, &rc, 0, 2);
150e2db2954SJanosch Frank hdr = (void *)pagebuf;
151e2db2954SJanosch Frank mach = (void *)pagebuf + hdr->INFMOFF;
152e2db2954SJanosch Frank par = (void *)pagebuf + hdr->INFPOFF;
153e2db2954SJanosch Frank
154*b3546acfSJanosch Frank report(cc == 0 && rc == CODE_SUCCES, "r2 + 1 == 0");
155e2db2954SJanosch Frank test_fcode0_hdr(hdr);
156e2db2954SJanosch Frank test_fcode0_mach(mach);
157e2db2954SJanosch Frank test_fcode0_par(par);
15892c5b9c0SJanosch Frank report_prefix_pop();
159e2db2954SJanosch Frank }
160e2db2954SJanosch Frank
main(void)161e2db2954SJanosch Frank int main(void)
162e2db2954SJanosch Frank {
163e2db2954SJanosch Frank bool has_sthyi = test_facility(74);
164e2db2954SJanosch Frank
165e2db2954SJanosch Frank report_prefix_push("sthyi");
166e2db2954SJanosch Frank
167e2db2954SJanosch Frank /* Test for availability */
16890016cc5SThomas Huth if (!has_sthyi) {
16990016cc5SThomas Huth report_skip("STHYI is not available");
170e2db2954SJanosch Frank goto done;
17190016cc5SThomas Huth }
172e2db2954SJanosch Frank
173e2db2954SJanosch Frank /* Test register/argument checking. */
17492c5b9c0SJanosch Frank report_prefix_push("Instruction");
175e2db2954SJanosch Frank test_exception_addr();
176e2db2954SJanosch Frank test_exception_reg_odd();
177e2db2954SJanosch Frank test_exception_reg_equal();
178e2db2954SJanosch Frank test_function_code((uint64_t) pagebuf);
17992c5b9c0SJanosch Frank report_prefix_pop();
180e2db2954SJanosch Frank
181e2db2954SJanosch Frank /* Test function code 0 - CP and IFL Capacity Information */
182e2db2954SJanosch Frank test_fcode0();
183e2db2954SJanosch Frank
184e2db2954SJanosch Frank done:
185e2db2954SJanosch Frank report_prefix_pop();
186e2db2954SJanosch Frank return report_summary();
187e2db2954SJanosch Frank }
188