xref: /kvm-unit-tests/lib/s390x/uv.c (revision f1dcfd54130ca2b1851d46dffd7ffadbe5eb4a3b)
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 int uv_setup(void)
51 {
52 	if (!test_facility(158))
53 		return 0;
54 
55 	uv_call(0, (u64)&uvcb_qui);
56 
57 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
58 	return 1;
59 }
60 
61 void uv_init(void)
62 {
63 	struct uv_cb_init uvcb_init = {
64 		.header.len = sizeof(uvcb_init),
65 		.header.cmd = UVC_CMD_INIT_UV,
66 	};
67 	static bool initialized;
68 	int cc;
69 
70 	/* Let's not do this twice */
71 	assert(!initialized);
72 	/* Query is done on initialization but let's check anyway */
73 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
74 
75 	/* Donated storage needs to be over 2GB aligned to 1MB */
76 	uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
77 	uvcb_init.stor_origin = uv_init_mem;
78 	uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
79 
80 	cc = uv_call(0, (uint64_t)&uvcb_init);
81 	assert(cc == 0);
82 	initialized = true;
83 }
84 
85 void uv_create_guest(struct vm *vm)
86 {
87 	struct uv_cb_cgc uvcb_cgc = {
88 		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
89 		.header.len = sizeof(uvcb_cgc),
90 	};
91 	struct uv_cb_csc uvcb_csc = {
92 		.header.len = sizeof(uvcb_csc),
93 		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
94 		.state_origin = (uint64_t)vm->sblk,
95 		.num = 0,
96 	};
97 	unsigned long vsize;
98 	int cc;
99 
100 	uvcb_cgc.guest_stor_origin = vm->sblk->mso;
101 	uvcb_cgc.guest_stor_len = vm->sblk->msl;
102 
103 	/* Config allocation */
104 	vsize = uvcb_qui.conf_base_virt_stor_len +
105 		((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len);
106 
107 	vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0);
108 	/*
109 	 * This allocation needs to be below the max guest storage
110 	 * address so let's simply put it into the physical memory
111 	 */
112 	vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0);
113 	uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor;
114 	uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor;
115 
116 	/* CPU allocation */
117 	vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0);
118 	uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor;
119 
120 	uvcb_cgc.guest_asce = (uint64_t)stctg(1);
121 	uvcb_cgc.guest_sca = (uint64_t)vm->sca;
122 
123 	cc = uv_call(0, (uint64_t)&uvcb_cgc);
124 	assert(!cc);
125 
126 	vm->uv.vm_handle = uvcb_cgc.guest_handle;
127 	uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
128 	cc = uv_call(0, (uint64_t)&uvcb_csc);
129 	vm->uv.vcpu_handle = uvcb_csc.cpu_handle;
130 	assert(!cc);
131 
132 	/*
133 	 * Convert guest to format 4:
134 	 *
135 	 *  - Set format 4
136 	 *  - Write UV handles into sblk
137 	 *  - Allocate and set SIDA
138 	 */
139 	vm->sblk->sdf = 2;
140 	vm->sblk->sidad = (uint64_t)alloc_page();
141 	vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle;
142 	vm->sblk->pv_handle_config = uvcb_cgc.guest_handle;
143 }
144 
145 void uv_destroy_guest(struct vm *vm)
146 {
147 	int cc;
148 	u16 rc, rrc;
149 
150 	cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu,
151 			   UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc);
152 	assert(cc == 0);
153 	free_page((void *)vm->sblk->sidad);
154 	free_pages(vm->uv.cpu_stor);
155 
156 	cc = uv_cmd_nodata(vm->sblk->pv_handle_config,
157 			   UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc);
158 	assert(cc == 0);
159 	free_pages(vm->uv.conf_base_stor);
160 	free_pages(vm->uv.conf_var_stor);
161 }
162 
163 int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak)
164 {
165 	int i, cc;
166 
167 	for (i = 0; i < len / PAGE_SIZE; i++) {
168 		cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE);
169 		assert(!cc);
170 		addr += PAGE_SIZE;
171 	}
172 	return cc;
173 }
174 
175 void uv_verify_load(struct vm *vm)
176 {
177 	uint16_t rc, rrc;
178 	int cc;
179 
180 	cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc);
181 	assert(!cc);
182 	cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD);
183 	assert(!cc);
184 }
185