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 */
snippet_init(struct vm * vm,const char * gbin,uint64_t gbin_len,uint64_t off)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 */
snippet_pv_init(struct vm * vm,const char * gbin,const char * hdr,uint64_t gbin_len,uint64_t hdr_len,uint64_t off)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 */
snippet_setup_guest(struct vm * vm,bool is_pv)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