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