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