| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Store System Information tests | |
| * | |
| * Copyright (c) 2019 IBM Corp | |
| * | |
| * Authors: | |
| * Janosch Frank <frankja@linux.ibm.com> | |
| */ | |
| #include <libcflat.h> | |
| #include <bitops.h> | |
| #include <asm/page.h> | |
| #include <asm/asm-offsets.h> | |
| #include <asm/interrupt.h> | |
| #include <smp.h> | |
| #include <stsi.h> | |
| static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); | |
| static void test_specs(void) | |
| { | |
| int i; | |
| int cc; | |
| report_prefix_push("specification"); | |
| for (i = 36; i <= 55; i++) { | |
| report_prefix_pushf("set invalid r0 bit %d", i); | |
| expect_pgm_int(); | |
| stsi(pagebuf, 0, BIT(63 - i), 0); | |
| check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); | |
| report_prefix_pop(); | |
| } | |
| for (i = 32; i <= 47; i++) { | |
| report_prefix_pushf("set invalid r1 bit %d", i); | |
| expect_pgm_int(); | |
| stsi(pagebuf, 1, 0, BIT(63 - i)); | |
| check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); | |
| report_prefix_pop(); | |
| } | |
| for (i = 0; i < 32; i++) { | |
| report_prefix_pushf("r0 bit %d ignored", i); | |
| cc = stsi(pagebuf, 3, 2 | BIT(63 - i), 2); | |
| report(!cc, "CC = 0"); | |
| report_prefix_pop(); | |
| } | |
| for (i = 0; i < 32; i++) { | |
| report_prefix_pushf("r1 bit %d ignored", i); | |
| cc = stsi(pagebuf, 3, 2, 2 | BIT(63 - i)); | |
| report(!cc, "CC = 0"); | |
| report_prefix_pop(); | |
| } | |
| report_prefix_push("unaligned"); | |
| expect_pgm_int(); | |
| stsi(pagebuf + 42, 1, 1, 1); | |
| check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); | |
| report_prefix_pop(); | |
| report_prefix_pop(); | |
| } | |
| static void test_priv(void) | |
| { | |
| report_prefix_push("privileged"); | |
| expect_pgm_int(); | |
| enter_pstate(); | |
| stsi(pagebuf, 0, 0, 0); | |
| check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); | |
| report_prefix_pop(); | |
| } | |
| static void test_fc(void) | |
| { | |
| report(stsi(pagebuf, 7, 0, 0) == 3, "invalid fc"); | |
| report(stsi(pagebuf, 1, 0, 1) == 3, "invalid selector 1"); | |
| report(stsi(pagebuf, 1, 1, 0) == 3, "invalid selector 2"); | |
| report(stsi_get_fc() >= 2, "query fc >= 2"); | |
| } | |
| static void test_3_2_2(void) | |
| { | |
| int rc; | |
| /* EBCDIC for "kvm-unit" */ | |
| const uint8_t vm_name[] = { 0x92, 0xa5, 0x94, 0x60, 0xa4, 0x95, 0x89, | |
| 0xa3 }; | |
| const uint8_t uuid[] = { 0x0f, 0xb8, 0x4a, 0x86, 0x72, 0x7c, | |
| 0x11, 0xea, 0xbc, 0x55, 0x02, 0x42, 0xac, 0x13, | |
| 0x00, 0x03 }; | |
| /* EBCDIC for "KVM/" */ | |
| const uint8_t cpi_kvm[] = { 0xd2, 0xe5, 0xd4, 0x61 }; | |
| const char vm_name_ext[] = "kvm-unit-test"; | |
| struct sysinfo_3_2_2 *data = (void *)pagebuf; | |
| report_prefix_push("3.2.2"); | |
| /* Is the function code available at all? */ | |
| if (stsi_get_fc() < 3) { | |
| report_skip("Running under lpar, no level 3 to test."); | |
| goto out; | |
| } | |
| rc = stsi(pagebuf, 3, 2, 2); | |
| report(!rc, "call"); | |
| /* For now we concentrate on KVM/QEMU */ | |
| if (memcmp(&data->vm[0].cpi, cpi_kvm, sizeof(cpi_kvm))) { | |
| report_skip("Not running under KVM/QEMU."); | |
| goto out; | |
| } | |
| report(!memcmp(data->vm[0].uuid, uuid, sizeof(uuid)), "uuid"); | |
| report(data->vm[0].conf_cpus == smp_query_num_cpus(), "cpu count configured"); | |
| report(data->vm[0].total_cpus == | |
| data->vm[0].reserved_cpus + data->vm[0].conf_cpus, | |
| "cpu count total == conf + reserved"); | |
| report(data->vm[0].standby_cpus == 0, "cpu count standby"); | |
| report(!memcmp(data->vm[0].name, vm_name, sizeof(data->vm[0].name)), | |
| "VM name == kvm-unit-test"); | |
| if (data->vm[0].ext_name_encoding != 2) { | |
| report_skip("Extended VM names are not UTF-8."); | |
| goto out; | |
| } | |
| report(!memcmp(data->ext_names[0], vm_name_ext, sizeof(vm_name_ext)), | |
| "ext VM name == kvm-unit-test"); | |
| out: | |
| report_prefix_pop(); | |
| } | |
| int main(void) | |
| { | |
| report_prefix_push("stsi"); | |
| test_priv(); | |
| test_specs(); | |
| test_fc(); | |
| test_3_2_2(); | |
| return report_summary(); | |
| } |