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