xref: /kvm-unit-tests/s390x/sclp.c (revision 9cab58249f98adc451933530fd7e618e1856eb94)
1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
21cbda07cSClaudio Imbrenda /*
31cbda07cSClaudio Imbrenda  * Service Call tests
41cbda07cSClaudio Imbrenda  *
51cbda07cSClaudio Imbrenda  * Copyright (c) 2020 IBM Corp
61cbda07cSClaudio Imbrenda  *
71cbda07cSClaudio Imbrenda  * Authors:
81cbda07cSClaudio Imbrenda  *  Claudio Imbrenda <imbrenda@linux.ibm.com>
91cbda07cSClaudio Imbrenda  */
101cbda07cSClaudio Imbrenda 
111cbda07cSClaudio Imbrenda #include <libcflat.h>
121cbda07cSClaudio Imbrenda #include <asm/page.h>
131cbda07cSClaudio Imbrenda #include <asm/asm-offsets.h>
141cbda07cSClaudio Imbrenda #include <asm/interrupt.h>
151cbda07cSClaudio Imbrenda #include <sclp.h>
161cbda07cSClaudio Imbrenda 
171cbda07cSClaudio Imbrenda #define PGM_NONE	1
181cbda07cSClaudio Imbrenda #define PGM_BIT_SPEC	(1ULL << PGM_INT_CODE_SPECIFICATION)
191cbda07cSClaudio Imbrenda #define PGM_BIT_ADDR	(1ULL << PGM_INT_CODE_ADDRESSING)
201cbda07cSClaudio Imbrenda #define PGM_BIT_PRIV	(1ULL << PGM_INT_CODE_PRIVILEGED_OPERATION)
211cbda07cSClaudio Imbrenda #define MKPTR(x) ((void *)(uint64_t)(x))
221cbda07cSClaudio Imbrenda 
231cbda07cSClaudio Imbrenda #define LC_SIZE (2 * PAGE_SIZE)
241cbda07cSClaudio Imbrenda 
251cbda07cSClaudio Imbrenda static uint8_t pagebuf[LC_SIZE] __attribute__((aligned(LC_SIZE)));	/* scratch pages used for some tests */
261cbda07cSClaudio Imbrenda static uint8_t prefix_buf[LC_SIZE] __attribute__((aligned(LC_SIZE)));	/* temporary lowcore for test_sccb_prefix */
271cbda07cSClaudio Imbrenda /* SCCB template to be used */
281cbda07cSClaudio Imbrenda static union {
291cbda07cSClaudio Imbrenda 	uint8_t raw[PAGE_SIZE];
301cbda07cSClaudio Imbrenda 	SCCBHeader header;
311cbda07cSClaudio Imbrenda 	WriteEventData data;
321cbda07cSClaudio Imbrenda } sccb_template;
331cbda07cSClaudio Imbrenda static uint32_t valid_code;						/* valid command code for READ SCP INFO */
341cbda07cSClaudio Imbrenda 
35df04e7f9SNico Boehr /*
361cbda07cSClaudio Imbrenda  * Perform one service call, handling exceptions and interrupts.
371cbda07cSClaudio Imbrenda  */
sclp_service_call_test(unsigned int command,void * sccb)381cbda07cSClaudio Imbrenda static int sclp_service_call_test(unsigned int command, void *sccb)
391cbda07cSClaudio Imbrenda {
401cbda07cSClaudio Imbrenda 	int cc;
411cbda07cSClaudio Imbrenda 
421cbda07cSClaudio Imbrenda 	sclp_mark_busy();
431cbda07cSClaudio Imbrenda 	sclp_setup_int();
441cbda07cSClaudio Imbrenda 	cc = servc(command, __pa(sccb));
45cd719531SJanis Schoetterl-Glausch 	if (lowcore.pgm_int_code) {
461cbda07cSClaudio Imbrenda 		sclp_handle_ext();
471cbda07cSClaudio Imbrenda 		return 0;
481cbda07cSClaudio Imbrenda 	}
491cbda07cSClaudio Imbrenda 	if (!cc)
501cbda07cSClaudio Imbrenda 		sclp_wait_busy();
511cbda07cSClaudio Imbrenda 	return cc;
521cbda07cSClaudio Imbrenda }
531cbda07cSClaudio Imbrenda 
54df04e7f9SNico Boehr /*
551cbda07cSClaudio Imbrenda  * Perform one test at the given address, optionally using the SCCB template,
561cbda07cSClaudio Imbrenda  * checking for the expected program interrupts and return codes.
571cbda07cSClaudio Imbrenda  *
581cbda07cSClaudio Imbrenda  * The parameter buf_len indicates the number of bytes of the template that
591cbda07cSClaudio Imbrenda  * should be copied to the test address, and should be 0 when the test
601cbda07cSClaudio Imbrenda  * address is invalid, in which case nothing is copied.
611cbda07cSClaudio Imbrenda  *
621cbda07cSClaudio Imbrenda  * The template is used to simplify tests where the same buffer content is
631cbda07cSClaudio Imbrenda  * used many times in a row, at different addresses.
641cbda07cSClaudio Imbrenda  *
651cbda07cSClaudio Imbrenda  * Returns true in case of success or false in case of failure
661cbda07cSClaudio Imbrenda  */
test_one_sccb(uint32_t cmd,uint8_t * addr,uint16_t buf_len,uint64_t exp_pgm,uint16_t exp_rc)671cbda07cSClaudio Imbrenda static bool test_one_sccb(uint32_t cmd, uint8_t *addr, uint16_t buf_len, uint64_t exp_pgm, uint16_t exp_rc)
681cbda07cSClaudio Imbrenda {
691cbda07cSClaudio Imbrenda 	SCCBHeader *h = (SCCBHeader *)addr;
701cbda07cSClaudio Imbrenda 	int res, pgm;
711cbda07cSClaudio Imbrenda 
721cbda07cSClaudio Imbrenda 	/* Copy the template to the test address if needed */
731cbda07cSClaudio Imbrenda 	if (buf_len)
741cbda07cSClaudio Imbrenda 		memcpy(addr, sccb_template.raw, buf_len);
751cbda07cSClaudio Imbrenda 	if (exp_pgm != PGM_NONE)
761cbda07cSClaudio Imbrenda 		expect_pgm_int();
771cbda07cSClaudio Imbrenda 	/* perform the actual call */
781cbda07cSClaudio Imbrenda 	res = sclp_service_call_test(cmd, h);
791cbda07cSClaudio Imbrenda 	if (res) {
801cbda07cSClaudio Imbrenda 		report_info("SCLP not ready (command %#x, address %p, cc %d)", cmd, addr, res);
811cbda07cSClaudio Imbrenda 		return false;
821cbda07cSClaudio Imbrenda 	}
831cbda07cSClaudio Imbrenda 	pgm = clear_pgm_int();
841cbda07cSClaudio Imbrenda 	/* Check if the program exception was one of the expected ones */
851cbda07cSClaudio Imbrenda 	if (!((1ULL << pgm) & exp_pgm)) {
861cbda07cSClaudio Imbrenda 		report_info("First failure at addr %p, buf_len %d, cmd %#x, pgm code %d",
871cbda07cSClaudio Imbrenda 				addr, buf_len, cmd, pgm);
881cbda07cSClaudio Imbrenda 		return false;
891cbda07cSClaudio Imbrenda 	}
901cbda07cSClaudio Imbrenda 	/* Check if the response code is the one expected */
911cbda07cSClaudio Imbrenda 	if (exp_rc && exp_rc != h->response_code) {
921cbda07cSClaudio Imbrenda 		report_info("First failure at addr %p, buf_len %d, cmd %#x, resp code %#x",
931cbda07cSClaudio Imbrenda 				addr, buf_len, cmd, h->response_code);
941cbda07cSClaudio Imbrenda 		return false;
951cbda07cSClaudio Imbrenda 	}
961cbda07cSClaudio Imbrenda 	return true;
971cbda07cSClaudio Imbrenda }
981cbda07cSClaudio Imbrenda 
99df04e7f9SNico Boehr /*
1001cbda07cSClaudio Imbrenda  * Wrapper for test_one_sccb to be used when the template should not be
1011cbda07cSClaudio Imbrenda  * copied and the memory address should not be touched.
1021cbda07cSClaudio Imbrenda  */
test_one_ro(uint32_t cmd,uint8_t * addr,uint64_t exp_pgm,uint16_t exp_rc)1031cbda07cSClaudio Imbrenda static bool test_one_ro(uint32_t cmd, uint8_t *addr, uint64_t exp_pgm, uint16_t exp_rc)
1041cbda07cSClaudio Imbrenda {
1051cbda07cSClaudio Imbrenda 	return test_one_sccb(cmd, addr, 0, exp_pgm, exp_rc);
1061cbda07cSClaudio Imbrenda }
1071cbda07cSClaudio Imbrenda 
108df04e7f9SNico Boehr /*
1091cbda07cSClaudio Imbrenda  * Wrapper for test_one_sccb to set up a simple SCCB template.
1101cbda07cSClaudio Imbrenda  *
1111cbda07cSClaudio Imbrenda  * The parameter sccb_len indicates the value that will be saved in the SCCB
1121cbda07cSClaudio Imbrenda  * length field of the SCCB, buf_len indicates the number of bytes of
1131cbda07cSClaudio Imbrenda  * template that need to be copied to the actual test address. In many cases
1141cbda07cSClaudio Imbrenda  * it's enough to clear/copy the first 8 bytes of the buffer, while the SCCB
1151cbda07cSClaudio Imbrenda  * itself can be larger.
1161cbda07cSClaudio Imbrenda  *
1171cbda07cSClaudio Imbrenda  * Returns true in case of success or false in case of failure
1181cbda07cSClaudio Imbrenda  */
test_one_simple(uint32_t cmd,uint8_t * addr,uint16_t sccb_len,uint16_t buf_len,uint64_t exp_pgm,uint16_t exp_rc)1191cbda07cSClaudio Imbrenda static bool test_one_simple(uint32_t cmd, uint8_t *addr, uint16_t sccb_len,
1201cbda07cSClaudio Imbrenda 			uint16_t buf_len, uint64_t exp_pgm, uint16_t exp_rc)
1211cbda07cSClaudio Imbrenda {
1221cbda07cSClaudio Imbrenda 	memset(sccb_template.raw, 0, sizeof(sccb_template.raw));
1231cbda07cSClaudio Imbrenda 	sccb_template.header.length = sccb_len;
1241cbda07cSClaudio Imbrenda 	return test_one_sccb(cmd, addr, buf_len, exp_pgm, exp_rc);
1251cbda07cSClaudio Imbrenda }
1261cbda07cSClaudio Imbrenda 
127df04e7f9SNico Boehr /*
1281cbda07cSClaudio Imbrenda  * Test SCCB lengths < 8.
1291cbda07cSClaudio Imbrenda  */
test_sccb_too_short(void)1301cbda07cSClaudio Imbrenda static void test_sccb_too_short(void)
1311cbda07cSClaudio Imbrenda {
1321cbda07cSClaudio Imbrenda 	int len;
1331cbda07cSClaudio Imbrenda 
1341cbda07cSClaudio Imbrenda 	for (len = 0; len < 8; len++)
1351cbda07cSClaudio Imbrenda 		if (!test_one_simple(valid_code, pagebuf, len, 8, PGM_BIT_SPEC, 0))
1361cbda07cSClaudio Imbrenda 			break;
1371cbda07cSClaudio Imbrenda 
1381cbda07cSClaudio Imbrenda 	report(len == 8, "SCCB too short");
1391cbda07cSClaudio Imbrenda }
1401cbda07cSClaudio Imbrenda 
141df04e7f9SNico Boehr /*
1421cbda07cSClaudio Imbrenda  * Test SCCBs that are not 64-bit aligned.
1431cbda07cSClaudio Imbrenda  */
test_sccb_unaligned(void)1441cbda07cSClaudio Imbrenda static void test_sccb_unaligned(void)
1451cbda07cSClaudio Imbrenda {
1461cbda07cSClaudio Imbrenda 	int offset;
1471cbda07cSClaudio Imbrenda 
1481cbda07cSClaudio Imbrenda 	for (offset = 1; offset < 8; offset++)
1491cbda07cSClaudio Imbrenda 		if (!test_one_simple(valid_code, offset + pagebuf, 8, 8, PGM_BIT_SPEC, 0))
1501cbda07cSClaudio Imbrenda 			break;
1511cbda07cSClaudio Imbrenda 	report(offset == 8, "SCCB unaligned");
1521cbda07cSClaudio Imbrenda }
1531cbda07cSClaudio Imbrenda 
154df04e7f9SNico Boehr /*
1551cbda07cSClaudio Imbrenda  * Test SCCBs whose address is in the lowcore or prefix area.
1561cbda07cSClaudio Imbrenda  */
test_sccb_prefix(void)1571cbda07cSClaudio Imbrenda static void test_sccb_prefix(void)
1581cbda07cSClaudio Imbrenda {
1591cbda07cSClaudio Imbrenda 	uint8_t scratch[LC_SIZE];
1601cbda07cSClaudio Imbrenda 	uint32_t prefix, new_prefix;
1611cbda07cSClaudio Imbrenda 	int offset;
1621cbda07cSClaudio Imbrenda 
1631cbda07cSClaudio Imbrenda 	/*
1641cbda07cSClaudio Imbrenda 	 * copy the current lowcore to the future new location, otherwise we
1651cbda07cSClaudio Imbrenda 	 * will not have a valid lowcore after setting the new prefix.
1661cbda07cSClaudio Imbrenda 	 */
1671cbda07cSClaudio Imbrenda 	memcpy(prefix_buf, 0, LC_SIZE);
1681cbda07cSClaudio Imbrenda 	/* save the current prefix (it's probably going to be 0) */
1691cbda07cSClaudio Imbrenda 	prefix = get_prefix();
1701cbda07cSClaudio Imbrenda 	/*
1711cbda07cSClaudio Imbrenda 	 * save the current content of absolute pages 0 and 1, so we can
1721cbda07cSClaudio Imbrenda 	 * restore them after we trash them later on
1731cbda07cSClaudio Imbrenda 	 */
1741cbda07cSClaudio Imbrenda 	memcpy(scratch, (void *)(intptr_t)prefix, LC_SIZE);
1751cbda07cSClaudio Imbrenda 	/* set the new prefix to prefix_buf */
1761cbda07cSClaudio Imbrenda 	new_prefix = (uint32_t)(intptr_t)prefix_buf;
1771cbda07cSClaudio Imbrenda 	set_prefix(new_prefix);
1781cbda07cSClaudio Imbrenda 
1791cbda07cSClaudio Imbrenda 	/*
1801cbda07cSClaudio Imbrenda 	 * testing with SCCB addresses in the lowcore; since we can't
1811cbda07cSClaudio Imbrenda 	 * actually trash the lowcore (unsurprisingly, things break if we
1821cbda07cSClaudio Imbrenda 	 * do), this will be a read-only test.
1831cbda07cSClaudio Imbrenda 	 */
1841cbda07cSClaudio Imbrenda 	for (offset = 0; offset < LC_SIZE; offset += 8)
1851cbda07cSClaudio Imbrenda 		if (!test_one_ro(valid_code, MKPTR(offset), PGM_BIT_SPEC, 0))
1861cbda07cSClaudio Imbrenda 			break;
1871cbda07cSClaudio Imbrenda 	report(offset == LC_SIZE, "SCCB low pages");
1881cbda07cSClaudio Imbrenda 
1891cbda07cSClaudio Imbrenda 	/*
1901cbda07cSClaudio Imbrenda 	 * the SCLP should not even touch the memory, but we will write the
1911cbda07cSClaudio Imbrenda 	 * SCCBs all over the two pages starting at absolute address 0, thus
1921cbda07cSClaudio Imbrenda 	 * trashing them; we will need to restore them later.
1931cbda07cSClaudio Imbrenda 	 */
1941cbda07cSClaudio Imbrenda 	for (offset = 0; offset < LC_SIZE; offset += 8)
1951cbda07cSClaudio Imbrenda 		if (!test_one_simple(valid_code, MKPTR(new_prefix + offset), 8, 8, PGM_BIT_SPEC, 0))
1961cbda07cSClaudio Imbrenda 			break;
1971cbda07cSClaudio Imbrenda 	report(offset == LC_SIZE, "SCCB prefix pages");
1981cbda07cSClaudio Imbrenda 
1991cbda07cSClaudio Imbrenda 	/* restore the previous contents of absolute pages 0 and 1 */
2001cbda07cSClaudio Imbrenda 	memcpy(prefix_buf, 0, LC_SIZE);
2011cbda07cSClaudio Imbrenda 	/* restore the prefix to the original value */
2021cbda07cSClaudio Imbrenda 	set_prefix(prefix);
2031cbda07cSClaudio Imbrenda }
2041cbda07cSClaudio Imbrenda 
205df04e7f9SNico Boehr /*
2061cbda07cSClaudio Imbrenda  * Test SCCBs that are above 2GB. If outside of memory, an addressing
2071cbda07cSClaudio Imbrenda  * exception is also allowed.
2081cbda07cSClaudio Imbrenda  */
test_sccb_high(void)2091cbda07cSClaudio Imbrenda static void test_sccb_high(void)
2101cbda07cSClaudio Imbrenda {
2111cbda07cSClaudio Imbrenda 	SCCBHeader *h = (SCCBHeader *)pagebuf;
2121cbda07cSClaudio Imbrenda 	uintptr_t a[33 * 4 * 2 + 2];	/* for the list of addresses to test */
2131cbda07cSClaudio Imbrenda 
2141cbda07cSClaudio Imbrenda 	uint64_t maxram;
2151cbda07cSClaudio Imbrenda 	int i, pgm, len = 0;
2161cbda07cSClaudio Imbrenda 
2171cbda07cSClaudio Imbrenda 	h->length = 8;
2181cbda07cSClaudio Imbrenda 	/* addresses with 1 bit set in the first 33 bits */
2191cbda07cSClaudio Imbrenda 	for (i = 0; i < 33; i++)
2201cbda07cSClaudio Imbrenda 		a[len++] = 1UL << (i + 31);
2211cbda07cSClaudio Imbrenda 	/* addresses with 2 consecutive bits set in the first 33 bits */
2221cbda07cSClaudio Imbrenda 	for (i = 0; i < 33; i++)
2231cbda07cSClaudio Imbrenda 		a[len++] = 3UL << (i + 31);
2241cbda07cSClaudio Imbrenda 	/* addresses with all bits set in bits 0..N */
2251cbda07cSClaudio Imbrenda 	for (i = 0; i < 33; i++)
2261cbda07cSClaudio Imbrenda 		a[len++] = 0xffffffff80000000UL << i;
2271cbda07cSClaudio Imbrenda 	/* addresses with all bits set in bits N..33 */
2281cbda07cSClaudio Imbrenda 	a[len++] = 0x80000000;
2291cbda07cSClaudio Imbrenda 	for (i = 1; i < 33; i++, len++)
2301cbda07cSClaudio Imbrenda 		a[len] = a[len - 1] | (1UL << (i + 31));
2311cbda07cSClaudio Imbrenda 	/* all the addresses above, but adding the offset of a valid buffer */
2321cbda07cSClaudio Imbrenda 	for (i = 0; i < len; i++)
2331cbda07cSClaudio Imbrenda 		a[len + i] = a[i] + (intptr_t)h;
2341cbda07cSClaudio Imbrenda 	len += i;
2351cbda07cSClaudio Imbrenda 	/* two more hand-crafted addresses */
2361cbda07cSClaudio Imbrenda 	a[len++] = 0xdeadbeef00000000;
2371cbda07cSClaudio Imbrenda 	a[len++] = 0xdeaddeadbeef0000;
2381cbda07cSClaudio Imbrenda 
2391cbda07cSClaudio Imbrenda 	maxram = get_ram_size();
2401cbda07cSClaudio Imbrenda 	for (i = 0; i < len; i++) {
2411cbda07cSClaudio Imbrenda 		pgm = PGM_BIT_SPEC | (a[i] >= maxram ? PGM_BIT_ADDR : 0);
2421cbda07cSClaudio Imbrenda 		if (!test_one_ro(valid_code, (void *)a[i], pgm, 0))
2431cbda07cSClaudio Imbrenda 			break;
2441cbda07cSClaudio Imbrenda 	}
2451cbda07cSClaudio Imbrenda 	report(i == len, "SCCB high addresses");
2461cbda07cSClaudio Imbrenda }
2471cbda07cSClaudio Imbrenda 
248df04e7f9SNico Boehr /*
2491cbda07cSClaudio Imbrenda  * Test invalid commands, both invalid command detail codes and valid
2501cbda07cSClaudio Imbrenda  * ones with invalid command class code.
2511cbda07cSClaudio Imbrenda  */
test_inval(void)2521cbda07cSClaudio Imbrenda static void test_inval(void)
2531cbda07cSClaudio Imbrenda {
2541cbda07cSClaudio Imbrenda 	const uint16_t res = SCLP_RC_INVALID_SCLP_COMMAND;
2551cbda07cSClaudio Imbrenda 	uint32_t cmd;
2561cbda07cSClaudio Imbrenda 	int i;
2571cbda07cSClaudio Imbrenda 
2581cbda07cSClaudio Imbrenda 	report_prefix_push("Invalid command");
2591cbda07cSClaudio Imbrenda 	for (i = 0; i < 65536; i++) {
2601cbda07cSClaudio Imbrenda 		cmd = 0xdead0000 | i;
2611cbda07cSClaudio Imbrenda 		if (!test_one_simple(cmd, pagebuf, PAGE_SIZE, PAGE_SIZE, PGM_NONE, res))
2621cbda07cSClaudio Imbrenda 			break;
2631cbda07cSClaudio Imbrenda 	}
2641cbda07cSClaudio Imbrenda 	report(i == 65536, "Command detail code");
2651cbda07cSClaudio Imbrenda 
2661cbda07cSClaudio Imbrenda 	for (i = 0; i < 256; i++) {
2671cbda07cSClaudio Imbrenda 		cmd = (valid_code & ~0xff) | i;
2681cbda07cSClaudio Imbrenda 		if (cmd == valid_code)
2691cbda07cSClaudio Imbrenda 			continue;
2701cbda07cSClaudio Imbrenda 		if (!test_one_simple(cmd, pagebuf, PAGE_SIZE, PAGE_SIZE, PGM_NONE, res))
2711cbda07cSClaudio Imbrenda 			break;
2721cbda07cSClaudio Imbrenda 	}
2731cbda07cSClaudio Imbrenda 	report(i == 256, "Command class code");
2741cbda07cSClaudio Imbrenda 	report_prefix_pop();
2751cbda07cSClaudio Imbrenda }
2761cbda07cSClaudio Imbrenda 
2771cbda07cSClaudio Imbrenda 
278df04e7f9SNico Boehr /*
2791cbda07cSClaudio Imbrenda  * Test short SCCBs (but larger than 8).
2801cbda07cSClaudio Imbrenda  */
test_short(void)2811cbda07cSClaudio Imbrenda static void test_short(void)
2821cbda07cSClaudio Imbrenda {
2831cbda07cSClaudio Imbrenda 	const uint16_t res = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
2841cbda07cSClaudio Imbrenda 	int len;
2851cbda07cSClaudio Imbrenda 
2861cbda07cSClaudio Imbrenda 	for (len = 8; len < 144; len++)
2871cbda07cSClaudio Imbrenda 		if (!test_one_simple(valid_code, pagebuf, len, len, PGM_NONE, res))
2881cbda07cSClaudio Imbrenda 			break;
2891cbda07cSClaudio Imbrenda 	report(len == 144, "Insufficient SCCB length (Read SCP info)");
2901cbda07cSClaudio Imbrenda 
2911cbda07cSClaudio Imbrenda 	for (len = 8; len < 40; len++)
2921cbda07cSClaudio Imbrenda 		if (!test_one_simple(SCLP_READ_CPU_INFO, pagebuf, len, len, PGM_NONE, res))
2931cbda07cSClaudio Imbrenda 			break;
2941cbda07cSClaudio Imbrenda 	report(len == 40, "Insufficient SCCB length (Read CPU info)");
2951cbda07cSClaudio Imbrenda }
2961cbda07cSClaudio Imbrenda 
297df04e7f9SNico Boehr /*
2981cbda07cSClaudio Imbrenda  * Test SCCB page boundary violations.
2991cbda07cSClaudio Imbrenda  */
test_boundary(void)3001cbda07cSClaudio Imbrenda static void test_boundary(void)
3011cbda07cSClaudio Imbrenda {
3021cbda07cSClaudio Imbrenda 	const uint32_t cmd = SCLP_CMD_WRITE_EVENT_DATA;
3031cbda07cSClaudio Imbrenda 	const uint16_t res = SCLP_RC_SCCB_BOUNDARY_VIOLATION;
3041cbda07cSClaudio Imbrenda 	WriteEventData *sccb = &sccb_template.data;
3051cbda07cSClaudio Imbrenda 	int len, offset;
3061cbda07cSClaudio Imbrenda 
3071cbda07cSClaudio Imbrenda 	memset(sccb_template.raw, 0, sizeof(sccb_template.raw));
3081cbda07cSClaudio Imbrenda 	sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
3091cbda07cSClaudio Imbrenda 	for (len = 32; len <= 4096; len++) {
3101cbda07cSClaudio Imbrenda 		offset = len & 7 ? len & ~7 : len - 8;
3111cbda07cSClaudio Imbrenda 		for (offset = 4096 - offset; offset < 4096; offset += 8) {
3121cbda07cSClaudio Imbrenda 			sccb->h.length = len;
3131cbda07cSClaudio Imbrenda 			if (!test_one_sccb(cmd, offset + pagebuf, len, PGM_NONE, res))
3141cbda07cSClaudio Imbrenda 				goto out;
3151cbda07cSClaudio Imbrenda 		}
3161cbda07cSClaudio Imbrenda 	}
3171cbda07cSClaudio Imbrenda out:
3181cbda07cSClaudio Imbrenda 	report(len > 4096 && offset == 4096, "SCCB page boundary violation");
3191cbda07cSClaudio Imbrenda }
3201cbda07cSClaudio Imbrenda 
321df04e7f9SNico Boehr /*
3221cbda07cSClaudio Imbrenda  * Test excessively long SCCBs.
3231cbda07cSClaudio Imbrenda  */
test_toolong(void)3241cbda07cSClaudio Imbrenda static void test_toolong(void)
3251cbda07cSClaudio Imbrenda {
3261cbda07cSClaudio Imbrenda 	const uint32_t cmd = SCLP_CMD_WRITE_EVENT_DATA;
3271cbda07cSClaudio Imbrenda 	const uint16_t res = SCLP_RC_SCCB_BOUNDARY_VIOLATION;
3281cbda07cSClaudio Imbrenda 	WriteEventData *sccb = &sccb_template.data;
3291cbda07cSClaudio Imbrenda 	int len;
3301cbda07cSClaudio Imbrenda 
3311cbda07cSClaudio Imbrenda 	memset(sccb_template.raw, 0, sizeof(sccb_template.raw));
3321cbda07cSClaudio Imbrenda 	sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
3331cbda07cSClaudio Imbrenda 	for (len = 4097; len < 8192; len++) {
3341cbda07cSClaudio Imbrenda 		sccb->h.length = len;
3351cbda07cSClaudio Imbrenda 		if (!test_one_sccb(cmd, pagebuf, PAGE_SIZE, PGM_NONE, res))
3361cbda07cSClaudio Imbrenda 			break;
3371cbda07cSClaudio Imbrenda 	}
3381cbda07cSClaudio Imbrenda 	report(len == 8192, "SCCB bigger than 4k");
3391cbda07cSClaudio Imbrenda }
3401cbda07cSClaudio Imbrenda 
341df04e7f9SNico Boehr /*
3421cbda07cSClaudio Imbrenda  * Test privileged operation.
3431cbda07cSClaudio Imbrenda  */
test_priv(void)3441cbda07cSClaudio Imbrenda static void test_priv(void)
3451cbda07cSClaudio Imbrenda {
3461cbda07cSClaudio Imbrenda 	SCCBHeader *h = (SCCBHeader *)pagebuf;
3471cbda07cSClaudio Imbrenda 
3481cbda07cSClaudio Imbrenda 	report_prefix_push("Privileged operation");
3491cbda07cSClaudio Imbrenda 	h->length = 8;
3501cbda07cSClaudio Imbrenda 	expect_pgm_int();
3511cbda07cSClaudio Imbrenda 	enter_pstate();
3521cbda07cSClaudio Imbrenda 	servc(valid_code, __pa(h));
3531cbda07cSClaudio Imbrenda 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
3541cbda07cSClaudio Imbrenda 	report_prefix_pop();
3551cbda07cSClaudio Imbrenda }
3561cbda07cSClaudio Imbrenda 
357df04e7f9SNico Boehr /*
3581cbda07cSClaudio Imbrenda  * Test addressing exceptions. We need to test SCCB addresses between the
3591cbda07cSClaudio Imbrenda  * end of available memory and 2GB, because after 2GB a specification
3601cbda07cSClaudio Imbrenda  * exception is also allowed.
3611cbda07cSClaudio Imbrenda  * Only applicable if the VM has less than 2GB of memory
3621cbda07cSClaudio Imbrenda  */
test_addressing(void)3631cbda07cSClaudio Imbrenda static void test_addressing(void)
3641cbda07cSClaudio Imbrenda {
3651cbda07cSClaudio Imbrenda 	unsigned long i, maxram = get_ram_size();
3661cbda07cSClaudio Imbrenda 
3671cbda07cSClaudio Imbrenda 	/* the VM has more than 2GB of memory */
3681cbda07cSClaudio Imbrenda 	if (maxram >= 0x80000000) {
3691cbda07cSClaudio Imbrenda 		report_skip("Invalid SCCB address");
3701cbda07cSClaudio Imbrenda 		return;
3711cbda07cSClaudio Imbrenda 	}
3721cbda07cSClaudio Imbrenda 	/* test all possible valid addresses immediately after the end of memory
3731cbda07cSClaudio Imbrenda 	 * up to 64KB after the end of memory
3741cbda07cSClaudio Imbrenda 	 */
3751cbda07cSClaudio Imbrenda 	for (i = 0; i < 0x10000 && i + maxram < 0x80000000; i += 8)
3761cbda07cSClaudio Imbrenda 		if (!test_one_ro(valid_code, MKPTR(i + maxram), PGM_BIT_ADDR, 0))
3771cbda07cSClaudio Imbrenda 			goto out;
3781cbda07cSClaudio Imbrenda 	/* test more addresses until we reach 1MB after end of memory;
3791cbda07cSClaudio Imbrenda 	 * increment by a prime number (times 8) in order to test all
3801cbda07cSClaudio Imbrenda 	 * possible valid offsets inside pages
3811cbda07cSClaudio Imbrenda 	 */
3821cbda07cSClaudio Imbrenda 	for (; i < 0x100000 && i + maxram < 0x80000000 ; i += 808)
3831cbda07cSClaudio Imbrenda 		if (!test_one_ro(valid_code, MKPTR(i + maxram), PGM_BIT_ADDR, 0))
3841cbda07cSClaudio Imbrenda 			goto out;
3851cbda07cSClaudio Imbrenda 	/* test the remaining addresses until we reach address 2GB;
3861cbda07cSClaudio Imbrenda 	 * increment by a prime number (times 8) in order to test all
3871cbda07cSClaudio Imbrenda 	 * possible valid offsets inside pages
3881cbda07cSClaudio Imbrenda 	 */
3891cbda07cSClaudio Imbrenda 	for (; i + maxram < 0x80000000; i += 800024)
3901cbda07cSClaudio Imbrenda 		if (!test_one_ro(valid_code, MKPTR(i + maxram), PGM_BIT_ADDR, 0))
3911cbda07cSClaudio Imbrenda 			goto out;
3921cbda07cSClaudio Imbrenda out:
3931cbda07cSClaudio Imbrenda 	report(i + maxram >= 0x80000000, "Invalid SCCB address");
3941cbda07cSClaudio Imbrenda }
3951cbda07cSClaudio Imbrenda 
396df04e7f9SNico Boehr /*
3971cbda07cSClaudio Imbrenda  * Test some bits in the instruction format that are specified to be ignored.
3981cbda07cSClaudio Imbrenda  */
test_instbits(void)3991cbda07cSClaudio Imbrenda static void test_instbits(void)
4001cbda07cSClaudio Imbrenda {
4011cbda07cSClaudio Imbrenda 	SCCBHeader *h = (SCCBHeader *)pagebuf;
402*7dcf1fcfSJanosch Frank 	uint64_t bogus_cc = 1;
4031cbda07cSClaudio Imbrenda 	int cc;
4041cbda07cSClaudio Imbrenda 
4051cbda07cSClaudio Imbrenda 	sclp_mark_busy();
4061cbda07cSClaudio Imbrenda 	h->length = 8;
4071cbda07cSClaudio Imbrenda 	sclp_setup_int();
4081cbda07cSClaudio Imbrenda 
4091cbda07cSClaudio Imbrenda 	asm volatile(
410*7dcf1fcfSJanosch Frank 		"	tmll	%[bogus_cc],3\n"
4111cbda07cSClaudio Imbrenda 		"       .insn   rre,0xb2204200,%1,%2\n"  /* servc %1,%2 */
4121cbda07cSClaudio Imbrenda 		"       ipm     %0\n"
4131cbda07cSClaudio Imbrenda 		"       srl     %0,28"
414*7dcf1fcfSJanosch Frank 		: "=&d" (cc)
415*7dcf1fcfSJanosch Frank 		: "d" (valid_code), "a" (__pa(pagebuf)), [bogus_cc] "d" (bogus_cc)
4161cbda07cSClaudio Imbrenda 		: "cc", "memory");
4171cbda07cSClaudio Imbrenda 	/* No exception, but also no command accepted, so no interrupt is
4181cbda07cSClaudio Imbrenda 	 * expected. We need to clear the flag manually otherwise we will
4191cbda07cSClaudio Imbrenda 	 * loop forever when we try to report failure.
4201cbda07cSClaudio Imbrenda 	 */
4211cbda07cSClaudio Imbrenda 	if (cc)
4221cbda07cSClaudio Imbrenda 		sclp_handle_ext();
4231cbda07cSClaudio Imbrenda 	else
4241cbda07cSClaudio Imbrenda 		sclp_wait_busy();
4251cbda07cSClaudio Imbrenda 	report(cc == 0, "Instruction format ignored bits");
4261cbda07cSClaudio Imbrenda }
4271cbda07cSClaudio Imbrenda 
428df04e7f9SNico Boehr /*
4291cbda07cSClaudio Imbrenda  * Find a valid READ INFO command code; not all codes are always allowed, and
4301cbda07cSClaudio Imbrenda  * probing should be performed in the right order.
4311cbda07cSClaudio Imbrenda  */
find_valid_sclp_code(void)4321cbda07cSClaudio Imbrenda static void find_valid_sclp_code(void)
4331cbda07cSClaudio Imbrenda {
4341cbda07cSClaudio Imbrenda 	const unsigned int commands[] = { SCLP_CMDW_READ_SCP_INFO_FORCED,
4351cbda07cSClaudio Imbrenda 					  SCLP_CMDW_READ_SCP_INFO };
4361cbda07cSClaudio Imbrenda 	SCCBHeader *h = (SCCBHeader *)pagebuf;
4371cbda07cSClaudio Imbrenda 	int i, cc;
4381cbda07cSClaudio Imbrenda 
4391cbda07cSClaudio Imbrenda 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
4401cbda07cSClaudio Imbrenda 		sclp_mark_busy();
4411cbda07cSClaudio Imbrenda 		memset(h, 0, sizeof(*h));
4421cbda07cSClaudio Imbrenda 		h->length = 4096;
4431cbda07cSClaudio Imbrenda 
4441cbda07cSClaudio Imbrenda 		valid_code = commands[i];
4451cbda07cSClaudio Imbrenda 		cc = sclp_service_call(commands[i], h);
4461cbda07cSClaudio Imbrenda 		if (cc)
4471cbda07cSClaudio Imbrenda 			break;
4481cbda07cSClaudio Imbrenda 		if (h->response_code == SCLP_RC_NORMAL_READ_COMPLETION)
4491cbda07cSClaudio Imbrenda 			return;
4501cbda07cSClaudio Imbrenda 		if (h->response_code != SCLP_RC_INVALID_SCLP_COMMAND)
4511cbda07cSClaudio Imbrenda 			break;
4521cbda07cSClaudio Imbrenda 	}
4531cbda07cSClaudio Imbrenda 	report_abort("READ_SCP_INFO failed");
4541cbda07cSClaudio Imbrenda }
4551cbda07cSClaudio Imbrenda 
main(void)4561cbda07cSClaudio Imbrenda int main(void)
4571cbda07cSClaudio Imbrenda {
4581cbda07cSClaudio Imbrenda 	report_prefix_push("sclp");
4591cbda07cSClaudio Imbrenda 	find_valid_sclp_code();
4601cbda07cSClaudio Imbrenda 
4611cbda07cSClaudio Imbrenda 	/* Test some basic things */
4621cbda07cSClaudio Imbrenda 	test_instbits();
4631cbda07cSClaudio Imbrenda 	test_priv();
4641cbda07cSClaudio Imbrenda 	test_addressing();
4651cbda07cSClaudio Imbrenda 
4661cbda07cSClaudio Imbrenda 	/* Test the specification exceptions */
4671cbda07cSClaudio Imbrenda 	test_sccb_too_short();
4681cbda07cSClaudio Imbrenda 	test_sccb_unaligned();
4691cbda07cSClaudio Imbrenda 	test_sccb_prefix();
4701cbda07cSClaudio Imbrenda 	test_sccb_high();
4711cbda07cSClaudio Imbrenda 
4721cbda07cSClaudio Imbrenda 	/* Test the expected response codes */
4731cbda07cSClaudio Imbrenda 	test_inval();
4741cbda07cSClaudio Imbrenda 	test_short();
4751cbda07cSClaudio Imbrenda 	test_boundary();
4761cbda07cSClaudio Imbrenda 	test_toolong();
4771cbda07cSClaudio Imbrenda 
4781cbda07cSClaudio Imbrenda 	return report_summary();
4791cbda07cSClaudio Imbrenda }
480