blob: 178abb5a57339a77ebbbe2e39ea1112d701985fe [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Perform Frame Management Function (pfmf) tests
*
* Copyright (c) 2018 IBM
*
* Authors:
* Janosch Frank <frankja@linux.vnet.ibm.com>
*/
#include <libcflat.h>
#include <asm/asm-offsets.h>
#include <asm/interrupt.h>
#include <asm/page.h>
#include <asm/facility.h>
#include <asm/mem.h>
static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256)));
static void test_priv(void)
{
report_prefix_push("privileged");
expect_pgm_int();
enter_pstate();
pfmf(0, pagebuf);
check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
report_prefix_pop();
}
static void test_4k_key(void)
{
union pfmf_r1 r1 = {
.reg.sk = 1,
.reg.fsc = PFMF_FSC_4K,
.reg.key = 0x30,
};
union skey skey;
report_prefix_push("4K");
if (test_facility(169)) {
report_skip("storage key removal facility is active");
goto out;
}
pfmf(r1.val, pagebuf);
skey.val = get_storage_key(pagebuf);
skey.val &= SKEY_ACC | SKEY_FP;
report(skey.val == 0x30, "set storage keys");
out:
report_prefix_pop();
}
static void test_1m_key(void)
{
int i;
bool rp = true;
union skey skey;
union pfmf_r1 r1 = {
.reg.fsc = PFMF_FSC_1M,
.reg.key = 0x30,
.reg.sk = 1,
};
report_prefix_push("1M");
if (test_facility(169)) {
report_skip("storage key removal facility is active");
goto out;
}
pfmf(r1.val, pagebuf);
for (i = 0; i < 256; i++) {
skey.val = get_storage_key(pagebuf + i * PAGE_SIZE);
skey.val &= SKEY_ACC | SKEY_FP;
if (skey.val != 0x30) {
rp = false;
break;
}
}
report(rp, "set storage keys");
out:
report_prefix_pop();
}
static void test_4k_clear(void)
{
union pfmf_r1 r1 = {
.reg.cf = 1,
.reg.fsc = PFMF_FSC_4K,
};
report_prefix_push("4K");
memset(pagebuf, 42, PAGE_SIZE);
pfmf(r1.val, pagebuf);
report(!memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE),
"clear memory");
report_prefix_pop();
}
static void test_1m_clear(void)
{
int i;
union pfmf_r1 r1 = {
.reg.cf = 1,
.reg.fsc = PFMF_FSC_1M,
};
unsigned long sum = 0;
report_prefix_push("1M");
memset(pagebuf, 42, PAGE_SIZE * 256);
pfmf(r1.val, pagebuf);
for (i = 0; i < PAGE_SIZE * 256; i++)
sum |= pagebuf[i];
report(!sum, "clear memory");
report_prefix_pop();
}
static void test_low_addr_prot(void)
{
union pfmf_r1 r1 = {
.reg.cf = 1,
.reg.fsc = PFMF_FSC_4K
};
report_prefix_push("low-address protection");
report_prefix_push("0x1000");
expect_pgm_int();
low_prot_enable();
pfmf(r1.val, (void *)0x1000);
low_prot_disable();
check_pgm_int_code(PGM_INT_CODE_PROTECTION);
report_prefix_pop();
report_prefix_push("0x0");
expect_pgm_int();
low_prot_enable();
pfmf(r1.val, 0);
low_prot_disable();
check_pgm_int_code(PGM_INT_CODE_PROTECTION);
report_prefix_pop();
report_prefix_pop();
}
int main(void)
{
bool has_edat = test_facility(8);
report_prefix_push("pfmf");
if (!has_edat) {
report_skip("PFMF is not available");
goto done;
}
test_priv();
test_low_addr_prot();
/* Force the buffer pages in */
memset(pagebuf, 0, PAGE_SIZE * 256);
test_4k_key();
test_4k_clear();
test_1m_key();
test_1m_clear();
done:
report_prefix_pop();
return report_summary();
}