xref: /kvm-unit-tests/lib/s390x/uv.c (revision 4c8a99ca02252d4a2bee43f4558fe47ce5ab7ec0)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Ultravisor related functionality
4  *
5  * Copyright 2020 IBM Corp.
6  *
7  * Authors:
8  *    Janosch Frank <frankja@linux.ibm.com>
9  */
10 #include <libcflat.h>
11 #include <bitops.h>
12 #include <alloc.h>
13 #include <alloc_page.h>
14 #include <asm/page.h>
15 #include <asm/arch_def.h>
16 
17 #include <asm/facility.h>
18 #include <asm/uv.h>
19 #include <uv.h>
20 #include <sie.h>
21 
22 static struct uv_cb_qui uvcb_qui = {
23 	.header.cmd = UVC_CMD_QUI,
24 	.header.len = sizeof(uvcb_qui),
25 };
26 static uint64_t uv_init_mem;
27 
28 
29 bool uv_os_is_guest(void)
30 {
31 	return test_facility(158) &&
32 		uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS) &&
33 		uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS);
34 }
35 
36 bool uv_os_is_host(void)
37 {
38 	return test_facility(158) && uv_query_test_call(BIT_UVC_CMD_INIT_UV);
39 }
40 
41 bool uv_query_test_call(unsigned int nr)
42 {
43 	/* Query needs to be called first */
44 	assert(uvcb_qui.header.rc);
45 	assert(nr < BITS_PER_LONG * ARRAY_SIZE(uvcb_qui.inst_calls_list));
46 
47 	return test_bit_inv(nr, uvcb_qui.inst_calls_list);
48 }
49 
50 const struct uv_cb_qui *uv_get_query_data(void)
51 {
52 	/* Query needs to be called first */
53 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
54 
55 	return &uvcb_qui;
56 }
57 
58 int uv_setup(void)
59 {
60 	if (!test_facility(158))
61 		return 0;
62 
63 	uv_call(0, (u64)&uvcb_qui);
64 
65 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
66 	return 1;
67 }
68 
69 void uv_init(void)
70 {
71 	struct uv_cb_init uvcb_init = {
72 		.header.len = sizeof(uvcb_init),
73 		.header.cmd = UVC_CMD_INIT_UV,
74 	};
75 	static bool initialized;
76 	int cc;
77 
78 	/* Let's not do this twice */
79 	assert(!initialized);
80 	/* Query is done on initialization but let's check anyway */
81 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
82 
83 	/* Donated storage needs to be over 2GB aligned to 1MB */
84 	uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
85 	uvcb_init.stor_origin = uv_init_mem;
86 	uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
87 
88 	cc = uv_call(0, (uint64_t)&uvcb_init);
89 	assert(cc == 0);
90 	initialized = true;
91 }
92 
93 void uv_create_guest(struct vm *vm)
94 {
95 	struct uv_cb_cgc uvcb_cgc = {
96 		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
97 		.header.len = sizeof(uvcb_cgc),
98 	};
99 	struct uv_cb_csc uvcb_csc = {
100 		.header.len = sizeof(uvcb_csc),
101 		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
102 		.state_origin = (uint64_t)vm->sblk,
103 		.num = 0,
104 	};
105 	unsigned long vsize;
106 	int cc;
107 
108 	uvcb_cgc.guest_stor_origin = vm->sblk->mso;
109 	uvcb_cgc.guest_stor_len = vm->sblk->msl;
110 
111 	/* Config allocation */
112 	vsize = uvcb_qui.conf_base_virt_stor_len +
113 		((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len);
114 
115 	vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0);
116 	/*
117 	 * This allocation needs to be below the max guest storage
118 	 * address so let's simply put it into the physical memory
119 	 */
120 	vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0);
121 	uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor;
122 	uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor;
123 
124 	/* CPU allocation */
125 	vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0);
126 	uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor;
127 
128 	uvcb_cgc.guest_asce = (uint64_t)stctg(1);
129 	uvcb_cgc.guest_sca = (uint64_t)vm->sca;
130 
131 	cc = uv_call(0, (uint64_t)&uvcb_cgc);
132 	assert(!cc);
133 
134 	vm->uv.vm_handle = uvcb_cgc.guest_handle;
135 	uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
136 	cc = uv_call(0, (uint64_t)&uvcb_csc);
137 	vm->uv.vcpu_handle = uvcb_csc.cpu_handle;
138 	assert(!cc);
139 
140 	/*
141 	 * Convert guest to format 4:
142 	 *
143 	 *  - Set format 4
144 	 *  - Write UV handles into sblk
145 	 *  - Allocate and set SIDA
146 	 */
147 	vm->sblk->sdf = 2;
148 	vm->sblk->sidad = (uint64_t)alloc_page();
149 	vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle;
150 	vm->sblk->pv_handle_config = uvcb_cgc.guest_handle;
151 }
152 
153 void uv_destroy_guest(struct vm *vm)
154 {
155 	int cc;
156 	u16 rc, rrc;
157 
158 	cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu,
159 			   UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc);
160 	assert(cc == 0);
161 	free_page((void *)vm->sblk->sidad);
162 	free_pages(vm->uv.cpu_stor);
163 
164 	cc = uv_cmd_nodata(vm->sblk->pv_handle_config,
165 			   UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc);
166 	assert(cc == 0);
167 	free_pages(vm->uv.conf_base_stor);
168 	free_pages(vm->uv.conf_var_stor);
169 }
170 
171 int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak)
172 {
173 	int i, cc;
174 
175 	for (i = 0; i < len / PAGE_SIZE; i++) {
176 		cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE);
177 		assert(!cc);
178 		addr += PAGE_SIZE;
179 	}
180 	return cc;
181 }
182 
183 void uv_verify_load(struct vm *vm)
184 {
185 	uint16_t rc, rrc;
186 	int cc;
187 
188 	cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc);
189 	assert(!cc);
190 	cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD);
191 	assert(!cc);
192 }
193