xref: /kvm-unit-tests/lib/s390x/uv.c (revision b36f35a82ff4cec5f71a68aa782332e2bc3488f7)
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 	if (initialized)
80 		return;
81 	/* Query is done on initialization but let's check anyway */
82 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
83 
84 	/* Donated storage needs to be over 2GB aligned to 1MB */
85 	uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
86 	uvcb_init.stor_origin = uv_init_mem;
87 	uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
88 
89 	cc = uv_call(0, (uint64_t)&uvcb_init);
90 	assert(cc == 0);
91 	initialized = true;
92 }
93 
94 /*
95  * Create a new ASCE for the UV config because they can't be shared
96  * for security reasons. We just simply copy the top most table into a
97  * fresh set of allocated pages and use those pages as the asce.
98  */
99 static uint64_t create_asce(void)
100 {
101 	void *pgd_new, *pgd_old;
102 	uint64_t asce = stctg(1);
103 
104 	pgd_new = memalign_pages(PAGE_SIZE, PAGE_SIZE * 4);
105 	pgd_old = (void *)(asce & PAGE_MASK);
106 
107 	memcpy(pgd_new, pgd_old, PAGE_SIZE * 4);
108 
109 	asce = __pa(pgd_new) | ASCE_P | (asce & (ASCE_DT | ASCE_TL));
110 	return asce;
111 }
112 
113 void uv_create_guest(struct vm *vm)
114 {
115 	struct uv_cb_cgc uvcb_cgc = {
116 		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
117 		.header.len = sizeof(uvcb_cgc),
118 	};
119 	struct uv_cb_csc uvcb_csc = {
120 		.header.len = sizeof(uvcb_csc),
121 		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
122 		.state_origin = (uint64_t)vm->sblk,
123 		.num = 0,
124 	};
125 	unsigned long vsize;
126 	int cc;
127 
128 	uvcb_cgc.guest_stor_origin = vm->sblk->mso;
129 	uvcb_cgc.guest_stor_len = vm->sblk->msl;
130 
131 	/* Config allocation */
132 	vsize = uvcb_qui.conf_base_virt_stor_len +
133 		((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len);
134 
135 	vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0);
136 	/*
137 	 * This allocation needs to be below the max guest storage
138 	 * address so let's simply put it into the physical memory
139 	 */
140 	vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0);
141 	uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor;
142 	uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor;
143 
144 	/* CPU allocation */
145 	vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0);
146 	uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor;
147 
148 	uvcb_cgc.guest_asce = create_asce();
149 	vm->save_area.guest.asce = uvcb_cgc.guest_asce;
150 	uvcb_cgc.guest_sca = (uint64_t)vm->sca;
151 
152 	cc = uv_call(0, (uint64_t)&uvcb_cgc);
153 	assert(!cc);
154 
155 	vm->uv.vm_handle = uvcb_cgc.guest_handle;
156 	uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
157 	cc = uv_call(0, (uint64_t)&uvcb_csc);
158 	vm->uv.vcpu_handle = uvcb_csc.cpu_handle;
159 	assert(!cc);
160 
161 	/*
162 	 * Convert guest to format 4:
163 	 *
164 	 *  - Set format 4
165 	 *  - Write UV handles into sblk
166 	 *  - Allocate and set SIDA
167 	 */
168 	vm->sblk->sdf = 2;
169 	vm->sblk->sidad = (uint64_t)alloc_page();
170 	vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle;
171 	vm->sblk->pv_handle_config = uvcb_cgc.guest_handle;
172 }
173 
174 void uv_destroy_guest(struct vm *vm)
175 {
176 	int cc;
177 	u16 rc, rrc;
178 
179 	cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu,
180 			   UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc);
181 	assert(cc == 0);
182 	free_page((void *)vm->sblk->sidad);
183 	free_pages(vm->uv.cpu_stor);
184 
185 	cc = uv_cmd_nodata(vm->sblk->pv_handle_config,
186 			   UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc);
187 	assert(cc == 0);
188 	free_pages(vm->uv.conf_base_stor);
189 	free_pages(vm->uv.conf_var_stor);
190 
191 	free_pages((void *)(vm->uv.asce & PAGE_MASK));
192 	memset(&vm->uv, 0, sizeof(vm->uv));
193 
194 	/* Convert the sblk back to non-PV */
195 	vm->save_area.guest.asce = stctg(1);
196 	vm->sblk->sdf = 0;
197 	vm->sblk->sidad = 0;
198 	vm->sblk->pv_handle_cpu = 0;
199 	vm->sblk->pv_handle_config = 0;
200 }
201 
202 int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak)
203 {
204 	int i, cc;
205 
206 	for (i = 0; i < len / PAGE_SIZE; i++) {
207 		cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE);
208 		assert(!cc);
209 		addr += PAGE_SIZE;
210 	}
211 	return cc;
212 }
213 
214 void uv_verify_load(struct vm *vm)
215 {
216 	uint16_t rc, rrc;
217 	int cc;
218 
219 	cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc);
220 	assert(!cc);
221 	cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD);
222 	assert(!cc);
223 }
224