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 33ec6683adSJanosch Frank /* 34ec6683adSJanosch Frank * Some of the UV memory needs to be allocated with >31 bit 35ec6683adSJanosch Frank * addresses which means we need a lot more memory than other 36ec6683adSJanosch Frank * tests. 37ec6683adSJanosch Frank */ 38ec6683adSJanosch Frank #define SNIPPET_PV_MIN_MEM_SIZE (SZ_1M * 2200UL) 39ec6683adSJanosch Frank 4073950a25SJanosch Frank #define SNIPPET_PV_TWEAK0 0x42UL 4173950a25SJanosch Frank #define SNIPPET_PV_TWEAK1 0UL 42b36f35a8SJanosch Frank #define SNIPPET_UNPACK_OFF 0 4373950a25SJanosch Frank 4473950a25SJanosch Frank 45da96771eSJanosch Frank /* 46da96771eSJanosch Frank * C snippet instructions start at 0x4000 due to the prefix and the 47da96771eSJanosch Frank * stack being before that. ASM snippets don't strictly need a stack 48da96771eSJanosch Frank * but keeping the starting address the same means less code. 49da96771eSJanosch Frank */ 50da96771eSJanosch Frank #define SNIPPET_ENTRY_ADDR 0x4000 51da96771eSJanosch Frank 52da96771eSJanosch Frank /* Standard entry PSWs for snippets which can simply be copied into the guest PSW */ 53da96771eSJanosch Frank static const struct psw snippet_psw = { 54da96771eSJanosch Frank .mask = PSW_MASK_64, 55da96771eSJanosch Frank .addr = SNIPPET_ENTRY_ADDR, 56da96771eSJanosch Frank }; 5773950a25SJanosch Frank 5873950a25SJanosch Frank /* 5973950a25SJanosch Frank * Sets up a snippet guest on top of an existing and initialized SIE 6073950a25SJanosch Frank * vm struct. 6173950a25SJanosch Frank * Once this function has finished without errors the guest can be started. 6273950a25SJanosch Frank * 6373950a25SJanosch Frank * @vm: VM that this function will populated, has to be initialized already 6473950a25SJanosch Frank * @gbin: Snippet gbin data pointer 6573950a25SJanosch Frank * @gbin_len: Length of the gbin data 6673950a25SJanosch Frank * @off: Offset from guest absolute 0x0 where snippet is copied to 6773950a25SJanosch Frank */ 6873950a25SJanosch Frank static inline void snippet_init(struct vm *vm, const char *gbin, 6973950a25SJanosch Frank uint64_t gbin_len, uint64_t off) 7073950a25SJanosch Frank { 7173950a25SJanosch Frank uint64_t mso = vm->sblk->mso; 7273950a25SJanosch Frank 7373950a25SJanosch Frank /* Copy test image to guest memory */ 7473950a25SJanosch Frank memcpy((void *)mso + off, gbin, gbin_len); 7573950a25SJanosch Frank 7673950a25SJanosch Frank /* Setup guest PSW */ 7773950a25SJanosch Frank vm->sblk->gpsw = snippet_psw; 7873950a25SJanosch Frank 7973950a25SJanosch Frank /* 8073950a25SJanosch Frank * We want to exit on PGM exceptions so we don't need 8173950a25SJanosch Frank * exception handlers in the guest. 8273950a25SJanosch Frank */ 8373950a25SJanosch Frank vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT; 8473950a25SJanosch Frank } 8573950a25SJanosch Frank 8673950a25SJanosch Frank /* 8773950a25SJanosch Frank * Sets up a snippet UV/PV guest on top of an existing and initialized 8873950a25SJanosch Frank * SIE vm struct. 8973950a25SJanosch Frank * Once this function has finished without errors the guest can be started. 9073950a25SJanosch Frank * 9173950a25SJanosch Frank * @vm: VM that this function will populated, has to be initialized already 9273950a25SJanosch Frank * @gbin: Snippet gbin data pointer 9373950a25SJanosch Frank * @hdr: Snippet SE header data pointer 9473950a25SJanosch Frank * @gbin_len: Length of the gbin data 9573950a25SJanosch Frank * @hdr_len: Length of the hdr data 9673950a25SJanosch Frank * @off: Offset from guest absolute 0x0 where snippet is copied to 9773950a25SJanosch Frank */ 9873950a25SJanosch Frank static inline void snippet_pv_init(struct vm *vm, const char *gbin, 9973950a25SJanosch Frank const char *hdr, uint64_t gbin_len, 10073950a25SJanosch Frank uint64_t hdr_len, uint64_t off) 10173950a25SJanosch Frank { 10273950a25SJanosch Frank uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1}; 10373950a25SJanosch Frank uint64_t mso = vm->sblk->mso; 10473950a25SJanosch Frank int i; 10573950a25SJanosch Frank 10673950a25SJanosch Frank snippet_init(vm, gbin, gbin_len, off); 10773950a25SJanosch Frank 10873950a25SJanosch Frank uv_create_guest(vm); 10973950a25SJanosch Frank uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len); 11073950a25SJanosch Frank 11173950a25SJanosch Frank /* Unpack works on guest addresses so we only need off */ 11273950a25SJanosch Frank uv_unpack(vm, off, gbin_len, tweak[0]); 11373950a25SJanosch Frank uv_verify_load(vm); 11473950a25SJanosch Frank 11573950a25SJanosch Frank /* 11673950a25SJanosch Frank * Manually import: 11773950a25SJanosch Frank * - lowcore 0x0 - 0x1000 (asm) 11873950a25SJanosch Frank * - stack 0x3000 (C) 11973950a25SJanosch Frank */ 12073950a25SJanosch Frank for (i = 0; i < 4; i++) { 12173950a25SJanosch Frank uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i); 12273950a25SJanosch Frank } 12373950a25SJanosch Frank } 12473950a25SJanosch Frank 12573950a25SJanosch Frank /* Allocates and sets up a snippet based guest */ 12673950a25SJanosch Frank static inline void snippet_setup_guest(struct vm *vm, bool is_pv) 12773950a25SJanosch Frank { 128*ae337a39SNico Boehr const unsigned long guest_size = SZ_1M; 129*ae337a39SNico Boehr uint8_t *guest_start = sie_guest_alloc(guest_size); 13073950a25SJanosch Frank 13173950a25SJanosch Frank /* Initialize the vm struct and allocate control blocks */ 132*ae337a39SNico Boehr sie_guest_create(vm, (uint64_t)guest_start, guest_size); 13373950a25SJanosch Frank 13473950a25SJanosch Frank if (is_pv) { 13573950a25SJanosch Frank /* FMT4 needs a ESCA */ 13673950a25SJanosch Frank sie_guest_sca_create(vm); 13773950a25SJanosch Frank 13873950a25SJanosch Frank /* 13973950a25SJanosch Frank * Initialize UV and setup the address spaces needed 14073950a25SJanosch Frank * to run a PV guest. 14173950a25SJanosch Frank */ 14273950a25SJanosch Frank uv_init(); 14373950a25SJanosch Frank uv_setup_asces(); 14473950a25SJanosch Frank } 14573950a25SJanosch Frank } 14673950a25SJanosch Frank 147da96771eSJanosch Frank #endif 148