blob: ac57fe4f07d7a9849f8f7cc728b9f24489edfecd [file] [log] [blame]
/*
* Perform Frame Management Function (pfmf) tests
*
* Copyright (c) 2018 IBM
*
* Authors:
* Janosch Frank <frankja@linux.vnet.ibm.com>
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU Library General Public License version 2.
*/
#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;
union skey skey;
report_prefix_push("4K");
if (test_facility(169)) {
report_skip("storage key removal facility is active");
goto out;
}
r1.val = 0;
r1.reg.sk = 1;
r1.reg.fsc = PFMF_FSC_4K;
r1.reg.key = 0x30;
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 pfmf_r1 r1;
union skey skey;
report_prefix_push("1M");
if (test_facility(169)) {
report_skip("storage key removal facility is active");
goto out;
}
r1.val = 0;
r1.reg.sk = 1;
r1.reg.fsc = PFMF_FSC_1M;
r1.reg.key = 0x30;
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;
r1.val = 0;
r1.reg.cf = 1;
r1.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;
unsigned long sum = 0;
r1.val = 0;
r1.reg.cf = 1;
r1.reg.fsc = PFMF_FSC_1M;
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();
}
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();
/* 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();
}