blob: 4109b8d482810a87dacf41c2009f100e0ee795cf [file] [log] [blame] [edit]
/* 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 <asm/page.h>
#include <asm/asm-offsets.h>
#include <asm/interrupt.h>
#include <smp.h>
struct stsi_322 {
uint8_t reserved[31];
uint8_t count;
struct {
uint8_t reserved2[4];
uint16_t total_cpus;
uint16_t conf_cpus;
uint16_t standby_cpus;
uint16_t reserved_cpus;
uint8_t name[8];
uint32_t caf;
uint8_t cpi[16];
uint8_t reserved5[3];
uint8_t ext_name_encoding;
uint32_t reserved3;
uint8_t uuid[16];
} vm[8];
uint8_t reserved4[1504];
uint8_t ext_names[8][256];
};
static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
static void test_specs(void)
{
report_prefix_push("specification");
report_prefix_push("inv r0");
expect_pgm_int();
stsi(pagebuf, 0, 1 << 8, 0);
check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
report_prefix_pop();
report_prefix_push("inv r1");
expect_pgm_int();
stsi(pagebuf, 1, 0, 1 << 16);
check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
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 inline unsigned long stsi_get_fc(void *addr)
{
register unsigned long r0 asm("0") = 0;
register unsigned long r1 asm("1") = 0;
int cc;
asm volatile("stsi 0(%[addr])\n"
"ipm %[cc]\n"
"srl %[cc],28\n"
: "+d" (r0), [cc] "=d" (cc)
: "d" (r1), [addr] "a" (addr)
: "cc", "memory");
assert(!cc);
return r0 >> 28;
}
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(pagebuf) >= 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 stsi_322 *data = (void *)pagebuf;
report_prefix_push("3.2.2");
/* Is the function code available at all? */
if (stsi_get_fc(pagebuf) < 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();
}