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