xref: /kvm-unit-tests/lib/s390x/sie.c (revision 54674bae100c6840171d9df5ba98721403a5493f)
1d75fac5fSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
2d75fac5fSJanosch Frank /*
3ab68f968SJanosch Frank  * Library for managing various aspects of guests
4d75fac5fSJanosch Frank  *
5d75fac5fSJanosch Frank  * Copyright (c) 2021 IBM Corp
6d75fac5fSJanosch Frank  *
7d75fac5fSJanosch Frank  * Authors:
8d75fac5fSJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
9d75fac5fSJanosch Frank  */
10d75fac5fSJanosch Frank 
11d75fac5fSJanosch Frank #include <asm/barrier.h>
124e53a1d0SJanosch Frank #include <bitops.h>
13d75fac5fSJanosch Frank #include <libcflat.h>
14d75fac5fSJanosch Frank #include <sie.h>
15a58e5546SJanosch Frank #include <asm/page.h>
16*54674baeSNico Boehr #include <asm/interrupt.h>
17a58e5546SJanosch Frank #include <libcflat.h>
18a58e5546SJanosch Frank #include <alloc_page.h>
19ae337a39SNico Boehr #include <vmalloc.h>
20ae337a39SNico Boehr #include <sclp.h>
21d75fac5fSJanosch Frank 
221e19c3edSJanosch Frank void sie_expect_validity(struct vm *vm)
23d75fac5fSJanosch Frank {
241e19c3edSJanosch Frank 	vm->validity_expected = true;
25d75fac5fSJanosch Frank }
26d75fac5fSJanosch Frank 
271e19c3edSJanosch Frank uint16_t sie_get_validity(struct vm *vm)
28d75fac5fSJanosch Frank {
29a680af75SJanosch Frank 	/*
30a680af75SJanosch Frank 	 * 0xffff will never be returned by SIE, so we can indicate a
31a680af75SJanosch Frank 	 * missing validity via this value.
32a680af75SJanosch Frank 	 */
33a680af75SJanosch Frank 	if (vm->sblk->icptcode != ICPT_VALIDITY)
34a680af75SJanosch Frank 		return 0xffff;
35a680af75SJanosch Frank 
361e19c3edSJanosch Frank 	return vm->sblk->ipb >> 16;
371e19c3edSJanosch Frank }
381e19c3edSJanosch Frank 
391e19c3edSJanosch Frank void sie_check_validity(struct vm *vm, uint16_t vir_exp)
401e19c3edSJanosch Frank {
411e19c3edSJanosch Frank 	uint16_t vir = sie_get_validity(vm);
421e19c3edSJanosch Frank 
43d75fac5fSJanosch Frank 	report(vir_exp == vir, "VALIDITY: %x", vir);
44d75fac5fSJanosch Frank }
45d75fac5fSJanosch Frank 
46d75fac5fSJanosch Frank void sie_handle_validity(struct vm *vm)
47d75fac5fSJanosch Frank {
48d75fac5fSJanosch Frank 	if (vm->sblk->icptcode != ICPT_VALIDITY)
49d75fac5fSJanosch Frank 		return;
50d75fac5fSJanosch Frank 
511e19c3edSJanosch Frank 	if (!vm->validity_expected)
521e19c3edSJanosch Frank 		report_abort("VALIDITY: %x", sie_get_validity(vm));
531e19c3edSJanosch Frank 	vm->validity_expected = false;
54d75fac5fSJanosch Frank }
55a58e5546SJanosch Frank 
56ab68f968SJanosch Frank void sie(struct vm *vm)
57ab68f968SJanosch Frank {
584e8880d6SNico Boehr 	uint64_t old_cr13;
594e8880d6SNico Boehr 
60*54674baeSNico Boehr 	/* When a pgm int code is set, we'll never enter SIE below. */
61*54674baeSNico Boehr 	assert(!read_pgm_int_code());
62*54674baeSNico Boehr 
63e9a5c8b6SJanosch Frank 	if (vm->sblk->sdf == 2)
64e9a5c8b6SJanosch Frank 		memcpy(vm->sblk->pv_grregs, vm->save_area.guest.grs,
65e9a5c8b6SJanosch Frank 		       sizeof(vm->save_area.guest.grs));
66e9a5c8b6SJanosch Frank 
67ab68f968SJanosch Frank 	/* Reset icptcode so we don't trip over it below */
68ab68f968SJanosch Frank 	vm->sblk->icptcode = 0;
69ab68f968SJanosch Frank 
704e8880d6SNico Boehr 	/*
714e8880d6SNico Boehr 	 * Set up home address space to match primary space. Instead of running
724e8880d6SNico Boehr 	 * in home space all the time, we switch every time in sie() because:
734e8880d6SNico Boehr 	 * - tests that depend on running in primary space mode don't need to be
744e8880d6SNico Boehr 	 *   touched
754e8880d6SNico Boehr 	 * - it avoids regressions in tests
764e8880d6SNico Boehr 	 * - switching every time makes it easier to extend this in the future,
774e8880d6SNico Boehr 	 *   for example to allow tests to run in whatever space they want
784e8880d6SNico Boehr 	 */
794e8880d6SNico Boehr 	old_cr13 = stctg(13);
804e8880d6SNico Boehr 	lctlg(13, stctg(1));
814e8880d6SNico Boehr 
824e8880d6SNico Boehr 	/* switch to home space so guest tables can be different from host */
834e8880d6SNico Boehr 	psw_mask_set_bits(PSW_MASK_HOME);
844e8880d6SNico Boehr 
854e8880d6SNico Boehr 	/* also handle all interruptions in home space while in SIE */
864e8880d6SNico Boehr 	irq_set_dat_mode(true, AS_HOME);
874e8880d6SNico Boehr 
88*54674baeSNico Boehr 	/* leave SIE when we have an intercept or an interrupt so the test can react to it */
89*54674baeSNico Boehr 	while (vm->sblk->icptcode == 0 && !read_pgm_int_code()) {
90ab68f968SJanosch Frank 		sie64a(vm->sblk, &vm->save_area);
91ab68f968SJanosch Frank 		sie_handle_validity(vm);
92ab68f968SJanosch Frank 	}
93ab68f968SJanosch Frank 	vm->save_area.guest.grs[14] = vm->sblk->gg14;
94ab68f968SJanosch Frank 	vm->save_area.guest.grs[15] = vm->sblk->gg15;
95e9a5c8b6SJanosch Frank 
964e8880d6SNico Boehr 	irq_set_dat_mode(true, AS_PRIM);
974e8880d6SNico Boehr 	psw_mask_clear_bits(PSW_MASK_HOME);
984e8880d6SNico Boehr 
994e8880d6SNico Boehr 	/* restore the old CR 13 */
1004e8880d6SNico Boehr 	lctlg(13, old_cr13);
1014e8880d6SNico Boehr 
102e9a5c8b6SJanosch Frank 	if (vm->sblk->sdf == 2)
103e9a5c8b6SJanosch Frank 		memcpy(vm->save_area.guest.grs, vm->sblk->pv_grregs,
104e9a5c8b6SJanosch Frank 		       sizeof(vm->save_area.guest.grs));
105ab68f968SJanosch Frank }
106ab68f968SJanosch Frank 
1076d1cb286SJanosch Frank void sie_guest_sca_create(struct vm *vm)
1086d1cb286SJanosch Frank {
1096d1cb286SJanosch Frank 	vm->sca = (struct esca_block *)alloc_page();
1106d1cb286SJanosch Frank 
1116d1cb286SJanosch Frank 	/* Let's start out with one page of ESCA for now */
1126d1cb286SJanosch Frank 	vm->sblk->scaoh = ((uint64_t)vm->sca >> 32);
1136d1cb286SJanosch Frank 	vm->sblk->scaol = (uint64_t)vm->sca & ~0x3fU;
1146d1cb286SJanosch Frank 	vm->sblk->ecb2 |= ECB2_ESCA;
1154e53a1d0SJanosch Frank 
1164e53a1d0SJanosch Frank 	/* Enable SIGP sense running interpretation */
1174e53a1d0SJanosch Frank 	vm->sblk->ecb |= ECB_SRSI;
1184e53a1d0SJanosch Frank 
1194e53a1d0SJanosch Frank 	/* We assume that cpu 0 is always part of the vm */
1204e53a1d0SJanosch Frank 	vm->sca->mcn[0] = BIT(63);
1214e53a1d0SJanosch Frank 	vm->sca->cpu[0].sda = (uint64_t)vm->sblk;
1226d1cb286SJanosch Frank }
1236d1cb286SJanosch Frank 
124a58e5546SJanosch Frank /* Initializes the struct vm members like the SIE control block. */
125a58e5546SJanosch Frank void sie_guest_create(struct vm *vm, uint64_t guest_mem, uint64_t guest_mem_len)
126a58e5546SJanosch Frank {
127a58e5546SJanosch Frank 	vm->sblk = alloc_page();
128a58e5546SJanosch Frank 	memset(vm->sblk, 0, PAGE_SIZE);
129a58e5546SJanosch Frank 	vm->sblk->cpuflags = CPUSTAT_ZARCH | CPUSTAT_RUNNING;
130a58e5546SJanosch Frank 	vm->sblk->ihcpu = 0xffff;
131a58e5546SJanosch Frank 	vm->sblk->prefix = 0;
132a58e5546SJanosch Frank 
133a58e5546SJanosch Frank 	/* Guest memory chunks are always 1MB */
134a58e5546SJanosch Frank 	assert(!(guest_mem_len & ~HPAGE_MASK));
13593f65abcSJanosch Frank 	vm->guest_mem = (uint8_t *)guest_mem;
1369e3cff66SJanosch Frank 	/* For non-PV guests we re-use the host's ASCE for ease of use */
1379e3cff66SJanosch Frank 	vm->save_area.guest.asce = stctg(1);
138a58e5546SJanosch Frank 	/* Currently MSO/MSL is the easiest option */
139a58e5546SJanosch Frank 	vm->sblk->mso = (uint64_t)guest_mem;
140a58e5546SJanosch Frank 	vm->sblk->msl = (uint64_t)guest_mem + ((guest_mem_len - 1) & HPAGE_MASK);
141a58e5546SJanosch Frank 
142a58e5546SJanosch Frank 	/* CRYCB needs to be in the first 2GB */
143a58e5546SJanosch Frank 	vm->crycb = alloc_pages_flags(0, AREA_DMA31);
144a58e5546SJanosch Frank 	vm->sblk->crycbd = (uint32_t)(uintptr_t)vm->crycb;
145a58e5546SJanosch Frank }
146a58e5546SJanosch Frank 
147ae337a39SNico Boehr /**
148ae337a39SNico Boehr  * sie_guest_alloc() - Allocate memory for a guest and map it in virtual address
149ae337a39SNico Boehr  * space such that it is properly aligned.
150ae337a39SNico Boehr  * @guest_size: the desired size of the guest in bytes.
151ae337a39SNico Boehr  */
152ae337a39SNico Boehr uint8_t *sie_guest_alloc(uint64_t guest_size)
153ae337a39SNico Boehr {
154ae337a39SNico Boehr 	static unsigned long guest_counter = 1;
155ae337a39SNico Boehr 	u8 *guest_phys, *guest_virt;
156ae337a39SNico Boehr 	unsigned long i;
157ae337a39SNico Boehr 	pgd_t *root;
158ae337a39SNico Boehr 
159ae337a39SNico Boehr 	setup_vm();
160ae337a39SNico Boehr 	root = (pgd_t *)(stctg(1) & PAGE_MASK);
161ae337a39SNico Boehr 
162ae337a39SNico Boehr 	/*
163ae337a39SNico Boehr 	 * Start of guest memory in host virtual space needs to be aligned to
164ae337a39SNico Boehr 	 * 2GB for some environments. It also can't be at 2GB since the memory
165ae337a39SNico Boehr 	 * allocator stores its page_states metadata there.
166ae337a39SNico Boehr 	 * Thus we use the next multiple of 4GB after the end of physical
167ae337a39SNico Boehr 	 * mapping. This also leaves space after end of physical memory so the
168ae337a39SNico Boehr 	 * page immediately after physical memory is guaranteed not to be
169ae337a39SNico Boehr 	 * present.
170ae337a39SNico Boehr 	 */
171ae337a39SNico Boehr 	guest_virt = (uint8_t *)ALIGN(get_ram_size() + guest_counter * 4UL * SZ_1G, SZ_2G);
172ae337a39SNico Boehr 	guest_counter++;
173ae337a39SNico Boehr 
174ae337a39SNico Boehr 	guest_phys = alloc_pages(get_order(guest_size) - 12);
175ae337a39SNico Boehr 	/*
176ae337a39SNico Boehr 	 * Establish a new mapping of the guest memory so it can be 2GB aligned
177ae337a39SNico Boehr 	 * without actually requiring 2GB physical memory.
178ae337a39SNico Boehr 	 */
179ae337a39SNico Boehr 	for (i = 0; i < guest_size; i += PAGE_SIZE) {
180ae337a39SNico Boehr 		install_page(root, __pa(guest_phys + i), guest_virt + i);
181ae337a39SNico Boehr 	}
182ae337a39SNico Boehr 	memset(guest_virt, 0, guest_size);
183ae337a39SNico Boehr 
184ae337a39SNico Boehr 	return guest_virt;
185ae337a39SNico Boehr }
186ae337a39SNico Boehr 
187a58e5546SJanosch Frank /* Frees the memory that was gathered on initialization */
188a58e5546SJanosch Frank void sie_guest_destroy(struct vm *vm)
189a58e5546SJanosch Frank {
190a58e5546SJanosch Frank 	free_page(vm->crycb);
191a58e5546SJanosch Frank 	free_page(vm->sblk);
1926d1cb286SJanosch Frank 	if (vm->sblk->ecb2 & ECB2_ESCA)
1936d1cb286SJanosch Frank 		free_page(vm->sca);
194a58e5546SJanosch Frank }
195