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_OFF_C 0 36 #define SNIPPET_OFF_ASM 0x4000 37 38 39 /* 40 * C snippet instructions start at 0x4000 due to the prefix and the 41 * stack being before that. ASM snippets don't strictly need a stack 42 * but keeping the starting address the same means less code. 43 */ 44 #define SNIPPET_ENTRY_ADDR 0x4000 45 46 /* Standard entry PSWs for snippets which can simply be copied into the guest PSW */ 47 static const struct psw snippet_psw = { 48 .mask = PSW_MASK_64, 49 .addr = SNIPPET_ENTRY_ADDR, 50 }; 51 52 /* 53 * Sets up a snippet guest on top of an existing and initialized SIE 54 * vm struct. 55 * Once this function has finished without errors the guest can be started. 56 * 57 * @vm: VM that this function will populated, has to be initialized already 58 * @gbin: Snippet gbin data pointer 59 * @gbin_len: Length of the gbin data 60 * @off: Offset from guest absolute 0x0 where snippet is copied to 61 */ 62 static inline void snippet_init(struct vm *vm, const char *gbin, 63 uint64_t gbin_len, uint64_t off) 64 { 65 uint64_t mso = vm->sblk->mso; 66 67 /* Copy test image to guest memory */ 68 memcpy((void *)mso + off, gbin, gbin_len); 69 70 /* Setup guest PSW */ 71 vm->sblk->gpsw = snippet_psw; 72 73 /* 74 * We want to exit on PGM exceptions so we don't need 75 * exception handlers in the guest. 76 */ 77 vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT; 78 } 79 80 /* 81 * Sets up a snippet UV/PV guest on top of an existing and initialized 82 * SIE vm struct. 83 * Once this function has finished without errors the guest can be started. 84 * 85 * @vm: VM that this function will populated, has to be initialized already 86 * @gbin: Snippet gbin data pointer 87 * @hdr: Snippet SE header data pointer 88 * @gbin_len: Length of the gbin data 89 * @hdr_len: Length of the hdr data 90 * @off: Offset from guest absolute 0x0 where snippet is copied to 91 */ 92 static inline void snippet_pv_init(struct vm *vm, const char *gbin, 93 const char *hdr, uint64_t gbin_len, 94 uint64_t hdr_len, uint64_t off) 95 { 96 uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1}; 97 uint64_t mso = vm->sblk->mso; 98 int i; 99 100 snippet_init(vm, gbin, gbin_len, off); 101 102 uv_create_guest(vm); 103 uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len); 104 105 /* Unpack works on guest addresses so we only need off */ 106 uv_unpack(vm, off, gbin_len, tweak[0]); 107 uv_verify_load(vm); 108 109 /* 110 * Manually import: 111 * - lowcore 0x0 - 0x1000 (asm) 112 * - stack 0x3000 (C) 113 */ 114 for (i = 0; i < 4; i++) { 115 uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i); 116 } 117 } 118 119 /* Allocates and sets up a snippet based guest */ 120 static inline void snippet_setup_guest(struct vm *vm, bool is_pv) 121 { 122 u8 *guest; 123 124 /* Allocate 1MB as guest memory */ 125 guest = alloc_pages(8); 126 memset(guest, 0, HPAGE_SIZE); 127 128 /* Initialize the vm struct and allocate control blocks */ 129 sie_guest_create(vm, (uint64_t)guest, HPAGE_SIZE); 130 131 if (is_pv) { 132 /* FMT4 needs a ESCA */ 133 sie_guest_sca_create(vm); 134 135 /* 136 * Initialize UV and setup the address spaces needed 137 * to run a PV guest. 138 */ 139 uv_init(); 140 uv_setup_asces(); 141 } 142 } 143 144 #endif 145