xref: /kvm-unit-tests/lib/s390x/sie.c (revision 2c96b77ec9d3b1fcec7525174e23a6240ee05949)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Library for managing various aspects of guests
4  *
5  * Copyright (c) 2021 IBM Corp
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.ibm.com>
9  */
10 
11 #include <asm/barrier.h>
12 #include <libcflat.h>
13 #include <sie.h>
14 #include <asm/page.h>
15 #include <libcflat.h>
16 #include <alloc_page.h>
17 
18 static bool validity_expected;
19 static uint16_t vir;		/* Validity interception reason */
20 
21 void sie_expect_validity(void)
22 {
23 	validity_expected = true;
24 	vir = 0;
25 }
26 
27 void sie_check_validity(uint16_t vir_exp)
28 {
29 	report(vir_exp == vir, "VALIDITY: %x", vir);
30 	vir = 0;
31 }
32 
33 void sie_handle_validity(struct vm *vm)
34 {
35 	if (vm->sblk->icptcode != ICPT_VALIDITY)
36 		return;
37 
38 	vir = vm->sblk->ipb >> 16;
39 
40 	if (!validity_expected)
41 		report_abort("VALIDITY: %x", vir);
42 	validity_expected = false;
43 }
44 
45 void sie(struct vm *vm)
46 {
47 	if (vm->sblk->sdf == 2)
48 		memcpy(vm->sblk->pv_grregs, vm->save_area.guest.grs,
49 		       sizeof(vm->save_area.guest.grs));
50 
51 	/* Reset icptcode so we don't trip over it below */
52 	vm->sblk->icptcode = 0;
53 
54 	while (vm->sblk->icptcode == 0) {
55 		sie64a(vm->sblk, &vm->save_area);
56 		sie_handle_validity(vm);
57 	}
58 	vm->save_area.guest.grs[14] = vm->sblk->gg14;
59 	vm->save_area.guest.grs[15] = vm->sblk->gg15;
60 
61 	if (vm->sblk->sdf == 2)
62 		memcpy(vm->save_area.guest.grs, vm->sblk->pv_grregs,
63 		       sizeof(vm->save_area.guest.grs));
64 }
65 
66 void sie_guest_sca_create(struct vm *vm)
67 {
68 	vm->sca = (struct esca_block *)alloc_page();
69 
70 	/* Let's start out with one page of ESCA for now */
71 	vm->sblk->scaoh = ((uint64_t)vm->sca >> 32);
72 	vm->sblk->scaol = (uint64_t)vm->sca & ~0x3fU;
73 	vm->sblk->ecb2 |= ECB2_ESCA;
74 }
75 
76 /* Initializes the struct vm members like the SIE control block. */
77 void sie_guest_create(struct vm *vm, uint64_t guest_mem, uint64_t guest_mem_len)
78 {
79 	vm->sblk = alloc_page();
80 	memset(vm->sblk, 0, PAGE_SIZE);
81 	vm->sblk->cpuflags = CPUSTAT_ZARCH | CPUSTAT_RUNNING;
82 	vm->sblk->ihcpu = 0xffff;
83 	vm->sblk->prefix = 0;
84 
85 	/* Guest memory chunks are always 1MB */
86 	assert(!(guest_mem_len & ~HPAGE_MASK));
87 	/* Currently MSO/MSL is the easiest option */
88 	vm->sblk->mso = (uint64_t)guest_mem;
89 	vm->sblk->msl = (uint64_t)guest_mem + ((guest_mem_len - 1) & HPAGE_MASK);
90 
91 	/* CRYCB needs to be in the first 2GB */
92 	vm->crycb = alloc_pages_flags(0, AREA_DMA31);
93 	vm->sblk->crycbd = (uint32_t)(uintptr_t)vm->crycb;
94 }
95 
96 /* Frees the memory that was gathered on initialization */
97 void sie_guest_destroy(struct vm *vm)
98 {
99 	free_page(vm->crycb);
100 	free_page(vm->sblk);
101 	if (vm->sblk->ecb2 & ECB2_ESCA)
102 		free_page(vm->sca);
103 }
104