xref: /kvm-unit-tests/s390x/skey.c (revision a299895b7abb54e7ba6bb4108f202acbb484ac65)
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 
22f6b354fbSJanosch Frank static void test_set_mb(void)
23f6b354fbSJanosch Frank {
24f6b354fbSJanosch Frank 	union skey skey, ret1, ret2;
257b9ca995SJanosch Frank 	void *addr = (void *)0x10000 - 2 * PAGE_SIZE;
267b9ca995SJanosch Frank 	void *end = (void *)0x10000;
27f6b354fbSJanosch Frank 
28f6b354fbSJanosch Frank 	/* Multi block support came with EDAT 1 */
29f6b354fbSJanosch Frank 	if (!test_facility(8))
30f6b354fbSJanosch Frank 		return;
31f6b354fbSJanosch Frank 
32f6b354fbSJanosch Frank 	skey.val = 0x30;
33f6b354fbSJanosch Frank 	while (addr < end)
34f6b354fbSJanosch Frank 		addr = set_storage_key_mb(addr, skey.val);
35f6b354fbSJanosch Frank 
36d0bfafdfSJanosch Frank 	ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP);
37d0bfafdfSJanosch Frank 	ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP);
38*a299895bSThomas Huth 	report(ret1.val == ret2.val && ret1.val == skey.val, "multi block");
39f6b354fbSJanosch Frank }
40f6b354fbSJanosch Frank 
41f6b354fbSJanosch Frank static void test_chg(void)
42f6b354fbSJanosch Frank {
43f6b354fbSJanosch Frank 	union skey skey1, skey2;
44f6b354fbSJanosch Frank 
45f6b354fbSJanosch Frank 	skey1.val = 0x30;
467b9ca995SJanosch Frank 	set_storage_key(pagebuf, skey1.val, 0);
477b9ca995SJanosch Frank 	skey1.val = get_storage_key(pagebuf);
48f6b354fbSJanosch Frank 	pagebuf[0] = 3;
497b9ca995SJanosch Frank 	skey2.val = get_storage_key(pagebuf);
50*a299895bSThomas Huth 	report(!skey1.str.ch && skey2.str.ch, "chg bit test");
51f6b354fbSJanosch Frank }
52f6b354fbSJanosch Frank 
53f6b354fbSJanosch Frank static void test_set(void)
54f6b354fbSJanosch Frank {
55f6b354fbSJanosch Frank 	union skey skey, ret;
56f6b354fbSJanosch Frank 
57f6b354fbSJanosch Frank 	skey.val = 0x30;
587b9ca995SJanosch Frank 	ret.val = get_storage_key(pagebuf);
597b9ca995SJanosch Frank 	set_storage_key(pagebuf, skey.val, 0);
607b9ca995SJanosch Frank 	ret.val = get_storage_key(pagebuf);
61d0bfafdfSJanosch Frank 	/*
62d0bfafdfSJanosch Frank 	 * For all set tests we only test the ACC and FP bits. RF and
63d0bfafdfSJanosch Frank 	 * CH are set by the machine for memory references and changes
64d0bfafdfSJanosch Frank 	 * and hence might change between a set and a get.
65d0bfafdfSJanosch Frank 	 */
66*a299895bSThomas Huth 	report(skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp,
67*a299895bSThomas Huth 	       "set key test");
68f6b354fbSJanosch Frank }
69f6b354fbSJanosch Frank 
701018ec15SThomas Huth /* Returns true if we are running under z/VM 6.x */
711018ec15SThomas Huth static bool check_for_zvm6(void)
721018ec15SThomas Huth {
731018ec15SThomas Huth 	int dcbt;	/* Descriptor block count */
741018ec15SThomas Huth 	int nr;
751018ec15SThomas Huth 	static const unsigned char zvm6[] = {
761018ec15SThomas Huth 		/* This is "z/VM    6" in EBCDIC */
771018ec15SThomas Huth 		0xa9, 0x61, 0xe5, 0xd4, 0x40, 0x40, 0x40, 0x40, 0xf6
781018ec15SThomas Huth 	};
791018ec15SThomas Huth 
801018ec15SThomas Huth 	if (stsi(pagebuf, 3, 2, 2))
811018ec15SThomas Huth 		return false;
821018ec15SThomas Huth 
831018ec15SThomas Huth 	dcbt = pagebuf[31] & 0xf;
841018ec15SThomas Huth 
851018ec15SThomas Huth 	for (nr = 0; nr < dcbt; nr++) {
861018ec15SThomas Huth 		if (!memcmp(&pagebuf[32 + nr * 64 + 24], zvm6, sizeof(zvm6)))
871018ec15SThomas Huth 			return true;
881018ec15SThomas Huth 	}
891018ec15SThomas Huth 
901018ec15SThomas Huth 	return false;
911018ec15SThomas Huth }
921018ec15SThomas Huth 
93f6b354fbSJanosch Frank static void test_priv(void)
94f6b354fbSJanosch Frank {
95f6b354fbSJanosch Frank 	union skey skey;
961018ec15SThomas Huth 	bool is_zvm6 = check_for_zvm6();
97f6b354fbSJanosch Frank 
98f6b354fbSJanosch Frank 	memset(pagebuf, 0, PAGE_SIZE * 2);
99e4654a1bSJanosch Frank 	report_prefix_push("privileged");
100e4654a1bSJanosch Frank 	report_prefix_push("sske");
101f6b354fbSJanosch Frank 	expect_pgm_int();
102f6b354fbSJanosch Frank 	enter_pstate();
1037b9ca995SJanosch Frank 	set_storage_key(pagebuf, 0x30, 0);
104f6b354fbSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
105e4654a1bSJanosch Frank 	report_prefix_pop();
106f6b354fbSJanosch Frank 
1077b9ca995SJanosch Frank 	skey.val = get_storage_key(pagebuf);
108*a299895bSThomas Huth 	report(skey.str.acc != 3, "skey did not change on exception");
109f6b354fbSJanosch Frank 
110e4654a1bSJanosch Frank 	report_prefix_push("iske");
1111018ec15SThomas Huth 	if (is_zvm6) {
1121018ec15SThomas Huth 		/* There is a known bug with z/VM 6, so skip the test there */
1131018ec15SThomas Huth 		report_skip("not working on z/VM 6");
1141018ec15SThomas Huth 	} else {
115f6b354fbSJanosch Frank 		expect_pgm_int();
116f6b354fbSJanosch Frank 		enter_pstate();
1177b9ca995SJanosch Frank 		get_storage_key(pagebuf);
118f6b354fbSJanosch Frank 		check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
1191018ec15SThomas Huth 	}
120e4654a1bSJanosch Frank 	report_prefix_pop();
121e4654a1bSJanosch Frank 
122e4654a1bSJanosch Frank 	report_prefix_pop();
123f6b354fbSJanosch Frank }
124f6b354fbSJanosch Frank 
125f6b354fbSJanosch Frank int main(void)
126f6b354fbSJanosch Frank {
127f6b354fbSJanosch Frank 	report_prefix_push("skey");
12847df95c7SJanosch Frank 	if (test_facility(169)) {
12947df95c7SJanosch Frank 		report_skip("storage key removal facility is active");
13047df95c7SJanosch Frank 		goto done;
13147df95c7SJanosch Frank 	}
132f6b354fbSJanosch Frank 	test_priv();
133f6b354fbSJanosch Frank 	test_set();
134f6b354fbSJanosch Frank 	test_set_mb();
135f6b354fbSJanosch Frank 	test_chg();
13647df95c7SJanosch Frank done:
137f6b354fbSJanosch Frank 	report_prefix_pop();
138f6b354fbSJanosch Frank 	return report_summary();
139f6b354fbSJanosch Frank }
140