1da96771eSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */ 2da96771eSJanosch Frank /* 3da96771eSJanosch Frank * Snippet definitions 4da96771eSJanosch Frank * 5da96771eSJanosch Frank * Copyright IBM Corp. 2021 6da96771eSJanosch Frank * Author: Janosch Frank <frankja@linux.ibm.com> 7da96771eSJanosch Frank */ 8da96771eSJanosch Frank 9da96771eSJanosch Frank #ifndef _S390X_SNIPPET_H_ 10da96771eSJanosch Frank #define _S390X_SNIPPET_H_ 11da96771eSJanosch Frank 1273950a25SJanosch Frank #include <sie.h> 1373950a25SJanosch Frank #include <uv.h> 1473950a25SJanosch Frank #include <asm/uv.h> 1573950a25SJanosch Frank 16da96771eSJanosch Frank /* This macro cuts down the length of the pointers to snippets */ 17da96771eSJanosch Frank #define SNIPPET_NAME_START(type, file) \ 18da96771eSJanosch Frank _binary_s390x_snippets_##type##_##file##_gbin_start 19da96771eSJanosch Frank #define SNIPPET_NAME_END(type, file) \ 20da96771eSJanosch Frank _binary_s390x_snippets_##type##_##file##_gbin_end 21dc4f7106SJanosch Frank #define SNIPPET_HDR_START(type, file) \ 22dc4f7106SJanosch Frank _binary_s390x_snippets_##type##_##file##_hdr_start 23dc4f7106SJanosch Frank #define SNIPPET_HDR_END(type, file) \ 24dc4f7106SJanosch Frank _binary_s390x_snippets_##type##_##file##_hdr_end 25dc4f7106SJanosch Frank 26da96771eSJanosch Frank 27da96771eSJanosch Frank /* Returns the length of the snippet */ 28da96771eSJanosch Frank #define SNIPPET_LEN(type, file) \ 29da96771eSJanosch Frank ((uintptr_t)SNIPPET_NAME_END(type, file) - (uintptr_t)SNIPPET_NAME_START(type, file)) 30dc4f7106SJanosch Frank #define SNIPPET_HDR_LEN(type, file) \ 31dc4f7106SJanosch Frank ((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file)) 32da96771eSJanosch Frank 3373950a25SJanosch Frank #define SNIPPET_PV_TWEAK0 0x42UL 3473950a25SJanosch Frank #define SNIPPET_PV_TWEAK1 0UL 35*b36f35a8SJanosch Frank #define SNIPPET_UNPACK_OFF 0 3673950a25SJanosch Frank 3773950a25SJanosch Frank 38da96771eSJanosch Frank /* 39da96771eSJanosch Frank * C snippet instructions start at 0x4000 due to the prefix and the 40da96771eSJanosch Frank * stack being before that. ASM snippets don't strictly need a stack 41da96771eSJanosch Frank * but keeping the starting address the same means less code. 42da96771eSJanosch Frank */ 43da96771eSJanosch Frank #define SNIPPET_ENTRY_ADDR 0x4000 44da96771eSJanosch Frank 45da96771eSJanosch Frank /* Standard entry PSWs for snippets which can simply be copied into the guest PSW */ 46da96771eSJanosch Frank static const struct psw snippet_psw = { 47da96771eSJanosch Frank .mask = PSW_MASK_64, 48da96771eSJanosch Frank .addr = SNIPPET_ENTRY_ADDR, 49da96771eSJanosch Frank }; 5073950a25SJanosch Frank 5173950a25SJanosch Frank /* 5273950a25SJanosch Frank * Sets up a snippet guest on top of an existing and initialized SIE 5373950a25SJanosch Frank * vm struct. 5473950a25SJanosch Frank * Once this function has finished without errors the guest can be started. 5573950a25SJanosch Frank * 5673950a25SJanosch Frank * @vm: VM that this function will populated, has to be initialized already 5773950a25SJanosch Frank * @gbin: Snippet gbin data pointer 5873950a25SJanosch Frank * @gbin_len: Length of the gbin data 5973950a25SJanosch Frank * @off: Offset from guest absolute 0x0 where snippet is copied to 6073950a25SJanosch Frank */ 6173950a25SJanosch Frank static inline void snippet_init(struct vm *vm, const char *gbin, 6273950a25SJanosch Frank uint64_t gbin_len, uint64_t off) 6373950a25SJanosch Frank { 6473950a25SJanosch Frank uint64_t mso = vm->sblk->mso; 6573950a25SJanosch Frank 6673950a25SJanosch Frank /* Copy test image to guest memory */ 6773950a25SJanosch Frank memcpy((void *)mso + off, gbin, gbin_len); 6873950a25SJanosch Frank 6973950a25SJanosch Frank /* Setup guest PSW */ 7073950a25SJanosch Frank vm->sblk->gpsw = snippet_psw; 7173950a25SJanosch Frank 7273950a25SJanosch Frank /* 7373950a25SJanosch Frank * We want to exit on PGM exceptions so we don't need 7473950a25SJanosch Frank * exception handlers in the guest. 7573950a25SJanosch Frank */ 7673950a25SJanosch Frank vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT; 7773950a25SJanosch Frank } 7873950a25SJanosch Frank 7973950a25SJanosch Frank /* 8073950a25SJanosch Frank * Sets up a snippet UV/PV guest on top of an existing and initialized 8173950a25SJanosch Frank * SIE vm struct. 8273950a25SJanosch Frank * Once this function has finished without errors the guest can be started. 8373950a25SJanosch Frank * 8473950a25SJanosch Frank * @vm: VM that this function will populated, has to be initialized already 8573950a25SJanosch Frank * @gbin: Snippet gbin data pointer 8673950a25SJanosch Frank * @hdr: Snippet SE header data pointer 8773950a25SJanosch Frank * @gbin_len: Length of the gbin data 8873950a25SJanosch Frank * @hdr_len: Length of the hdr data 8973950a25SJanosch Frank * @off: Offset from guest absolute 0x0 where snippet is copied to 9073950a25SJanosch Frank */ 9173950a25SJanosch Frank static inline void snippet_pv_init(struct vm *vm, const char *gbin, 9273950a25SJanosch Frank const char *hdr, uint64_t gbin_len, 9373950a25SJanosch Frank uint64_t hdr_len, uint64_t off) 9473950a25SJanosch Frank { 9573950a25SJanosch Frank uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1}; 9673950a25SJanosch Frank uint64_t mso = vm->sblk->mso; 9773950a25SJanosch Frank int i; 9873950a25SJanosch Frank 9973950a25SJanosch Frank snippet_init(vm, gbin, gbin_len, off); 10073950a25SJanosch Frank 10173950a25SJanosch Frank uv_create_guest(vm); 10273950a25SJanosch Frank uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len); 10373950a25SJanosch Frank 10473950a25SJanosch Frank /* Unpack works on guest addresses so we only need off */ 10573950a25SJanosch Frank uv_unpack(vm, off, gbin_len, tweak[0]); 10673950a25SJanosch Frank uv_verify_load(vm); 10773950a25SJanosch Frank 10873950a25SJanosch Frank /* 10973950a25SJanosch Frank * Manually import: 11073950a25SJanosch Frank * - lowcore 0x0 - 0x1000 (asm) 11173950a25SJanosch Frank * - stack 0x3000 (C) 11273950a25SJanosch Frank */ 11373950a25SJanosch Frank for (i = 0; i < 4; i++) { 11473950a25SJanosch Frank uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i); 11573950a25SJanosch Frank } 11673950a25SJanosch Frank } 11773950a25SJanosch Frank 11873950a25SJanosch Frank /* Allocates and sets up a snippet based guest */ 11973950a25SJanosch Frank static inline void snippet_setup_guest(struct vm *vm, bool is_pv) 12073950a25SJanosch Frank { 12173950a25SJanosch Frank u8 *guest; 12273950a25SJanosch Frank 12373950a25SJanosch Frank /* Allocate 1MB as guest memory */ 12473950a25SJanosch Frank guest = alloc_pages(8); 12573950a25SJanosch Frank memset(guest, 0, HPAGE_SIZE); 12673950a25SJanosch Frank 12773950a25SJanosch Frank /* Initialize the vm struct and allocate control blocks */ 12873950a25SJanosch Frank sie_guest_create(vm, (uint64_t)guest, HPAGE_SIZE); 12973950a25SJanosch Frank 13073950a25SJanosch Frank if (is_pv) { 13173950a25SJanosch Frank /* FMT4 needs a ESCA */ 13273950a25SJanosch Frank sie_guest_sca_create(vm); 13373950a25SJanosch Frank 13473950a25SJanosch Frank /* 13573950a25SJanosch Frank * Initialize UV and setup the address spaces needed 13673950a25SJanosch Frank * to run a PV guest. 13773950a25SJanosch Frank */ 13873950a25SJanosch Frank uv_init(); 13973950a25SJanosch Frank uv_setup_asces(); 14073950a25SJanosch Frank } 14173950a25SJanosch Frank } 14273950a25SJanosch Frank 143da96771eSJanosch Frank #endif 144