1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Snippet definitions 4 * 5 * Copyright IBM Corp. 2021 6 * Author: Janosch Frank <frankja@linux.ibm.com> 7 */ 8 9 #ifndef _S390X_SNIPPET_H_ 10 #define _S390X_SNIPPET_H_ 11 12 #include <sie.h> 13 #include <uv.h> 14 #include <asm/uv.h> 15 16 /* This macro cuts down the length of the pointers to snippets */ 17 #define SNIPPET_NAME_START(type, file) \ 18 _binary_s390x_snippets_##type##_##file##_gbin_start 19 #define SNIPPET_NAME_END(type, file) \ 20 _binary_s390x_snippets_##type##_##file##_gbin_end 21 #define SNIPPET_HDR_START(type, file) \ 22 _binary_s390x_snippets_##type##_##file##_hdr_start 23 #define SNIPPET_HDR_END(type, file) \ 24 _binary_s390x_snippets_##type##_##file##_hdr_end 25 26 27 /* Returns the length of the snippet */ 28 #define SNIPPET_LEN(type, file) \ 29 ((uintptr_t)SNIPPET_NAME_END(type, file) - (uintptr_t)SNIPPET_NAME_START(type, file)) 30 #define SNIPPET_HDR_LEN(type, file) \ 31 ((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file)) 32 33 #define SNIPPET_PV_TWEAK0 0x42UL 34 #define SNIPPET_PV_TWEAK1 0UL 35 #define SNIPPET_UNPACK_OFF 0 36 37 38 /* 39 * C snippet instructions start at 0x4000 due to the prefix and the 40 * stack being before that. ASM snippets don't strictly need a stack 41 * but keeping the starting address the same means less code. 42 */ 43 #define SNIPPET_ENTRY_ADDR 0x4000 44 45 /* Standard entry PSWs for snippets which can simply be copied into the guest PSW */ 46 static const struct psw snippet_psw = { 47 .mask = PSW_MASK_64, 48 .addr = SNIPPET_ENTRY_ADDR, 49 }; 50 51 /* 52 * Sets up a snippet guest on top of an existing and initialized SIE 53 * vm struct. 54 * Once this function has finished without errors the guest can be started. 55 * 56 * @vm: VM that this function will populated, has to be initialized already 57 * @gbin: Snippet gbin data pointer 58 * @gbin_len: Length of the gbin data 59 * @off: Offset from guest absolute 0x0 where snippet is copied to 60 */ 61 static inline void snippet_init(struct vm *vm, const char *gbin, 62 uint64_t gbin_len, uint64_t off) 63 { 64 uint64_t mso = vm->sblk->mso; 65 66 /* Copy test image to guest memory */ 67 memcpy((void *)mso + off, gbin, gbin_len); 68 69 /* Setup guest PSW */ 70 vm->sblk->gpsw = snippet_psw; 71 72 /* 73 * We want to exit on PGM exceptions so we don't need 74 * exception handlers in the guest. 75 */ 76 vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT; 77 } 78 79 /* 80 * Sets up a snippet UV/PV guest on top of an existing and initialized 81 * SIE vm struct. 82 * Once this function has finished without errors the guest can be started. 83 * 84 * @vm: VM that this function will populated, has to be initialized already 85 * @gbin: Snippet gbin data pointer 86 * @hdr: Snippet SE header data pointer 87 * @gbin_len: Length of the gbin data 88 * @hdr_len: Length of the hdr data 89 * @off: Offset from guest absolute 0x0 where snippet is copied to 90 */ 91 static inline void snippet_pv_init(struct vm *vm, const char *gbin, 92 const char *hdr, uint64_t gbin_len, 93 uint64_t hdr_len, uint64_t off) 94 { 95 uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1}; 96 uint64_t mso = vm->sblk->mso; 97 int i; 98 99 snippet_init(vm, gbin, gbin_len, off); 100 101 uv_create_guest(vm); 102 uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len); 103 104 /* Unpack works on guest addresses so we only need off */ 105 uv_unpack(vm, off, gbin_len, tweak[0]); 106 uv_verify_load(vm); 107 108 /* 109 * Manually import: 110 * - lowcore 0x0 - 0x1000 (asm) 111 * - stack 0x3000 (C) 112 */ 113 for (i = 0; i < 4; i++) { 114 uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i); 115 } 116 } 117 118 /* Allocates and sets up a snippet based guest */ 119 static inline void snippet_setup_guest(struct vm *vm, bool is_pv) 120 { 121 u8 *guest; 122 123 /* Allocate 1MB as guest memory */ 124 guest = alloc_pages(8); 125 memset(guest, 0, HPAGE_SIZE); 126 127 /* Initialize the vm struct and allocate control blocks */ 128 sie_guest_create(vm, (uint64_t)guest, HPAGE_SIZE); 129 130 if (is_pv) { 131 /* FMT4 needs a ESCA */ 132 sie_guest_sca_create(vm); 133 134 /* 135 * Initialize UV and setup the address spaces needed 136 * to run a PV guest. 137 */ 138 uv_init(); 139 uv_setup_asces(); 140 } 141 } 142 143 #endif 144