xref: /kvm-unit-tests/lib/s390x/sie.c (revision 1d0f08f40d53daa39566842ec46a112db5f7e524)
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 <bitops.h>
13 #include <libcflat.h>
14 #include <sie.h>
15 #include <asm/page.h>
16 #include <libcflat.h>
17 #include <alloc_page.h>
18 
19 void sie_expect_validity(struct vm *vm)
20 {
21 	vm->validity_expected = true;
22 }
23 
24 uint16_t sie_get_validity(struct vm *vm)
25 {
26 	/*
27 	 * 0xffff will never be returned by SIE, so we can indicate a
28 	 * missing validity via this value.
29 	 */
30 	if (vm->sblk->icptcode != ICPT_VALIDITY)
31 		return 0xffff;
32 
33 	return vm->sblk->ipb >> 16;
34 }
35 
36 void sie_check_validity(struct vm *vm, uint16_t vir_exp)
37 {
38 	uint16_t vir = sie_get_validity(vm);
39 
40 	report(vir_exp == vir, "VALIDITY: %x", vir);
41 }
42 
43 void sie_handle_validity(struct vm *vm)
44 {
45 	if (vm->sblk->icptcode != ICPT_VALIDITY)
46 		return;
47 
48 	if (!vm->validity_expected)
49 		report_abort("VALIDITY: %x", sie_get_validity(vm));
50 	vm->validity_expected = false;
51 }
52 
53 void sie(struct vm *vm)
54 {
55 	if (vm->sblk->sdf == 2)
56 		memcpy(vm->sblk->pv_grregs, vm->save_area.guest.grs,
57 		       sizeof(vm->save_area.guest.grs));
58 
59 	/* Reset icptcode so we don't trip over it below */
60 	vm->sblk->icptcode = 0;
61 
62 	while (vm->sblk->icptcode == 0) {
63 		sie64a(vm->sblk, &vm->save_area);
64 		sie_handle_validity(vm);
65 	}
66 	vm->save_area.guest.grs[14] = vm->sblk->gg14;
67 	vm->save_area.guest.grs[15] = vm->sblk->gg15;
68 
69 	if (vm->sblk->sdf == 2)
70 		memcpy(vm->save_area.guest.grs, vm->sblk->pv_grregs,
71 		       sizeof(vm->save_area.guest.grs));
72 }
73 
74 void sie_guest_sca_create(struct vm *vm)
75 {
76 	vm->sca = (struct esca_block *)alloc_page();
77 
78 	/* Let's start out with one page of ESCA for now */
79 	vm->sblk->scaoh = ((uint64_t)vm->sca >> 32);
80 	vm->sblk->scaol = (uint64_t)vm->sca & ~0x3fU;
81 	vm->sblk->ecb2 |= ECB2_ESCA;
82 
83 	/* Enable SIGP sense running interpretation */
84 	vm->sblk->ecb |= ECB_SRSI;
85 
86 	/* We assume that cpu 0 is always part of the vm */
87 	vm->sca->mcn[0] = BIT(63);
88 	vm->sca->cpu[0].sda = (uint64_t)vm->sblk;
89 }
90 
91 /* Initializes the struct vm members like the SIE control block. */
92 void sie_guest_create(struct vm *vm, uint64_t guest_mem, uint64_t guest_mem_len)
93 {
94 	vm->sblk = alloc_page();
95 	memset(vm->sblk, 0, PAGE_SIZE);
96 	vm->sblk->cpuflags = CPUSTAT_ZARCH | CPUSTAT_RUNNING;
97 	vm->sblk->ihcpu = 0xffff;
98 	vm->sblk->prefix = 0;
99 
100 	/* Guest memory chunks are always 1MB */
101 	assert(!(guest_mem_len & ~HPAGE_MASK));
102 	vm->guest_mem = (uint8_t *)guest_mem;
103 	/* For non-PV guests we re-use the host's ASCE for ease of use */
104 	vm->save_area.guest.asce = stctg(1);
105 	/* Currently MSO/MSL is the easiest option */
106 	vm->sblk->mso = (uint64_t)guest_mem;
107 	vm->sblk->msl = (uint64_t)guest_mem + ((guest_mem_len - 1) & HPAGE_MASK);
108 
109 	/* CRYCB needs to be in the first 2GB */
110 	vm->crycb = alloc_pages_flags(0, AREA_DMA31);
111 	vm->sblk->crycbd = (uint32_t)(uintptr_t)vm->crycb;
112 }
113 
114 /* Frees the memory that was gathered on initialization */
115 void sie_guest_destroy(struct vm *vm)
116 {
117 	free_page(vm->crycb);
118 	free_page(vm->sblk);
119 	if (vm->sblk->ecb2 & ECB2_ESCA)
120 		free_page(vm->sca);
121 }
122