xref: /kvm-unit-tests/s390x/skey.c (revision d0bfafdfce9a88700b8330883861d77eb2789ebb)
1f6b354fbSJanosch Frank /*
2f6b354fbSJanosch Frank  * Storage key tests
3f6b354fbSJanosch Frank  *
4f6b354fbSJanosch Frank  * Copyright (c) 2018 IBM Corp
5f6b354fbSJanosch Frank  *
6f6b354fbSJanosch Frank  * Authors:
7f6b354fbSJanosch Frank  *  Janosch Frank <frankja@linux.vnet.ibm.com>
8f6b354fbSJanosch Frank  *
9f6b354fbSJanosch Frank  * This code is free software; you can redistribute it and/or modify it
10f6b354fbSJanosch Frank  * under the terms of the GNU Library General Public License version 2.
11f6b354fbSJanosch Frank  */
12f6b354fbSJanosch Frank #include <libcflat.h>
13f6b354fbSJanosch Frank #include <asm/asm-offsets.h>
14f6b354fbSJanosch Frank #include <asm/interrupt.h>
15f6b354fbSJanosch Frank #include <asm/page.h>
16f6b354fbSJanosch Frank #include <asm/facility.h>
17f6b354fbSJanosch Frank #include <asm/mem.h>
18f6b354fbSJanosch Frank 
19f6b354fbSJanosch Frank 
20f6b354fbSJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
21f6b354fbSJanosch Frank const unsigned long page0 = (unsigned long)pagebuf;
22f6b354fbSJanosch Frank const unsigned long page1 = (unsigned long)(pagebuf + PAGE_SIZE);
23f6b354fbSJanosch Frank 
24f6b354fbSJanosch Frank static void test_set_mb(void)
25f6b354fbSJanosch Frank {
26f6b354fbSJanosch Frank 	union skey skey, ret1, ret2;
27f6b354fbSJanosch Frank 	unsigned long addr = 0x10000 - 2 * PAGE_SIZE;
28f6b354fbSJanosch Frank 	unsigned long end = 0x10000;
29f6b354fbSJanosch Frank 
30f6b354fbSJanosch Frank 	/* Multi block support came with EDAT 1 */
31f6b354fbSJanosch Frank 	if (!test_facility(8))
32f6b354fbSJanosch Frank 		return;
33f6b354fbSJanosch Frank 
34f6b354fbSJanosch Frank 	skey.val = 0x30;
35f6b354fbSJanosch Frank 	while (addr < end)
36f6b354fbSJanosch Frank 		addr = set_storage_key_mb(addr, skey.val);
37f6b354fbSJanosch Frank 
38*d0bfafdfSJanosch Frank 	ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP);
39*d0bfafdfSJanosch Frank 	ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP);
40*d0bfafdfSJanosch Frank 	report("multi block",
41*d0bfafdfSJanosch Frank 	       ret1.val == ret2.val && ret1.val == skey.val);
42f6b354fbSJanosch Frank }
43f6b354fbSJanosch Frank 
44f6b354fbSJanosch Frank static void test_chg(void)
45f6b354fbSJanosch Frank {
46f6b354fbSJanosch Frank 	union skey skey1, skey2;
47f6b354fbSJanosch Frank 
48f6b354fbSJanosch Frank 	skey1.val = 0x30;
49f6b354fbSJanosch Frank 	set_storage_key(page0, skey1.val, 0);
50f6b354fbSJanosch Frank 	skey1.val = get_storage_key(page0);
51f6b354fbSJanosch Frank 	pagebuf[0] = 3;
52f6b354fbSJanosch Frank 	skey2.val = get_storage_key(page0);
53f6b354fbSJanosch Frank 	report("chg bit test", !skey1.str.ch && skey2.str.ch);
54f6b354fbSJanosch Frank }
55f6b354fbSJanosch Frank 
56f6b354fbSJanosch Frank static void test_set(void)
57f6b354fbSJanosch Frank {
58f6b354fbSJanosch Frank 	union skey skey, ret;
59f6b354fbSJanosch Frank 
60f6b354fbSJanosch Frank 	skey.val = 0x30;
61f6b354fbSJanosch Frank 	ret.val = get_storage_key(page0);
62f6b354fbSJanosch Frank 	set_storage_key(page0, skey.val, 0);
63f6b354fbSJanosch Frank 	ret.val = get_storage_key(page0);
64*d0bfafdfSJanosch Frank 	/*
65*d0bfafdfSJanosch Frank 	 * For all set tests we only test the ACC and FP bits. RF and
66*d0bfafdfSJanosch Frank 	 * CH are set by the machine for memory references and changes
67*d0bfafdfSJanosch Frank 	 * and hence might change between a set and a get.
68*d0bfafdfSJanosch Frank 	 */
69*d0bfafdfSJanosch Frank 	report("set key test",
70*d0bfafdfSJanosch Frank 	       skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp);
71f6b354fbSJanosch Frank }
72f6b354fbSJanosch Frank 
73f6b354fbSJanosch Frank static void test_priv(void)
74f6b354fbSJanosch Frank {
75f6b354fbSJanosch Frank 	union skey skey;
76f6b354fbSJanosch Frank 
77f6b354fbSJanosch Frank 	memset(pagebuf, 0, PAGE_SIZE * 2);
78e4654a1bSJanosch Frank 	report_prefix_push("privileged");
79e4654a1bSJanosch Frank 	report_prefix_push("sske");
80f6b354fbSJanosch Frank 	expect_pgm_int();
81f6b354fbSJanosch Frank 	enter_pstate();
82f6b354fbSJanosch Frank 	set_storage_key(page0, 0x30, 0);
83f6b354fbSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
84e4654a1bSJanosch Frank 	report_prefix_pop();
85f6b354fbSJanosch Frank 
86f6b354fbSJanosch Frank 	skey.val = get_storage_key(page0);
87f6b354fbSJanosch Frank 	report("skey did not change on exception", skey.str.acc != 3);
88f6b354fbSJanosch Frank 
89e4654a1bSJanosch Frank 	report_prefix_push("iske");
90f6b354fbSJanosch Frank 	expect_pgm_int();
91f6b354fbSJanosch Frank 	enter_pstate();
92f6b354fbSJanosch Frank 	get_storage_key(page0);
93f6b354fbSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
94e4654a1bSJanosch Frank 	report_prefix_pop();
95e4654a1bSJanosch Frank 
96e4654a1bSJanosch Frank 	report_prefix_pop();
97f6b354fbSJanosch Frank }
98f6b354fbSJanosch Frank 
99f6b354fbSJanosch Frank int main(void)
100f6b354fbSJanosch Frank {
101f6b354fbSJanosch Frank 	report_prefix_push("skey");
102f6b354fbSJanosch Frank 	test_priv();
103f6b354fbSJanosch Frank 	test_set();
104f6b354fbSJanosch Frank 	test_set_mb();
105f6b354fbSJanosch Frank 	test_chg();
106f6b354fbSJanosch Frank 	report_prefix_pop();
107f6b354fbSJanosch Frank 	return report_summary();
108f6b354fbSJanosch Frank }
109