xref: /kvm-unit-tests/lib/s390x/uv.c (revision f4f97af0c5b6aa68f1432ff6ac316bad876a27be)
1aa8794b1SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
2aa8794b1SJanosch Frank /*
3aa8794b1SJanosch Frank  * Ultravisor related functionality
4aa8794b1SJanosch Frank  *
5aa8794b1SJanosch Frank  * Copyright 2020 IBM Corp.
6aa8794b1SJanosch Frank  *
7aa8794b1SJanosch Frank  * Authors:
8aa8794b1SJanosch Frank  *    Janosch Frank <frankja@linux.ibm.com>
9aa8794b1SJanosch Frank  */
1007ac63dcSJanosch Frank #include <libcflat.h>
1107ac63dcSJanosch Frank #include <bitops.h>
1207ac63dcSJanosch Frank #include <alloc.h>
1307ac63dcSJanosch Frank #include <alloc_page.h>
1407ac63dcSJanosch Frank #include <asm/page.h>
1507ac63dcSJanosch Frank #include <asm/arch_def.h>
1607ac63dcSJanosch Frank 
1707ac63dcSJanosch Frank #include <asm/facility.h>
1807ac63dcSJanosch Frank #include <asm/uv.h>
1907ac63dcSJanosch Frank #include <uv.h>
20*f4f97af0SJanosch Frank #include <sie.h>
2107ac63dcSJanosch Frank 
2207ac63dcSJanosch Frank static struct uv_cb_qui uvcb_qui = {
2307ac63dcSJanosch Frank 	.header.cmd = UVC_CMD_QUI,
2407ac63dcSJanosch Frank 	.header.len = sizeof(uvcb_qui),
2507ac63dcSJanosch Frank };
26*f4f97af0SJanosch Frank static uint64_t uv_init_mem;
27*f4f97af0SJanosch Frank 
2807ac63dcSJanosch Frank 
2907ac63dcSJanosch Frank bool uv_os_is_guest(void)
3007ac63dcSJanosch Frank {
3107ac63dcSJanosch Frank 	return test_facility(158) &&
3207ac63dcSJanosch Frank 		uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS) &&
3307ac63dcSJanosch Frank 		uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS);
3407ac63dcSJanosch Frank }
3507ac63dcSJanosch Frank 
3607ac63dcSJanosch Frank bool uv_os_is_host(void)
3707ac63dcSJanosch Frank {
3807ac63dcSJanosch Frank 	return test_facility(158) && uv_query_test_call(BIT_UVC_CMD_INIT_UV);
3907ac63dcSJanosch Frank }
4007ac63dcSJanosch Frank 
4107ac63dcSJanosch Frank bool uv_query_test_call(unsigned int nr)
4207ac63dcSJanosch Frank {
4307ac63dcSJanosch Frank 	/* Query needs to be called first */
4407ac63dcSJanosch Frank 	assert(uvcb_qui.header.rc);
4507ac63dcSJanosch Frank 	assert(nr < BITS_PER_LONG * ARRAY_SIZE(uvcb_qui.inst_calls_list));
4607ac63dcSJanosch Frank 
4707ac63dcSJanosch Frank 	return test_bit_inv(nr, uvcb_qui.inst_calls_list);
4807ac63dcSJanosch Frank }
4907ac63dcSJanosch Frank 
5007ac63dcSJanosch Frank int uv_setup(void)
5107ac63dcSJanosch Frank {
5207ac63dcSJanosch Frank 	if (!test_facility(158))
5307ac63dcSJanosch Frank 		return 0;
5407ac63dcSJanosch Frank 
5578168306SJanosch Frank 	uv_call(0, (u64)&uvcb_qui);
5678168306SJanosch Frank 
5778168306SJanosch Frank 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
5807ac63dcSJanosch Frank 	return 1;
5907ac63dcSJanosch Frank }
60*f4f97af0SJanosch Frank 
61*f4f97af0SJanosch Frank void uv_init(void)
62*f4f97af0SJanosch Frank {
63*f4f97af0SJanosch Frank 	struct uv_cb_init uvcb_init = {
64*f4f97af0SJanosch Frank 		.header.len = sizeof(uvcb_init),
65*f4f97af0SJanosch Frank 		.header.cmd = UVC_CMD_INIT_UV,
66*f4f97af0SJanosch Frank 	};
67*f4f97af0SJanosch Frank 	static bool initialized;
68*f4f97af0SJanosch Frank 	int cc;
69*f4f97af0SJanosch Frank 
70*f4f97af0SJanosch Frank 	/* Let's not do this twice */
71*f4f97af0SJanosch Frank 	assert(!initialized);
72*f4f97af0SJanosch Frank 	/* Query is done on initialization but let's check anyway */
73*f4f97af0SJanosch Frank 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
74*f4f97af0SJanosch Frank 
75*f4f97af0SJanosch Frank 	/* Donated storage needs to be over 2GB aligned to 1MB */
76*f4f97af0SJanosch Frank 	uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
77*f4f97af0SJanosch Frank 	uvcb_init.stor_origin = uv_init_mem;
78*f4f97af0SJanosch Frank 	uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
79*f4f97af0SJanosch Frank 
80*f4f97af0SJanosch Frank 	cc = uv_call(0, (uint64_t)&uvcb_init);
81*f4f97af0SJanosch Frank 	assert(cc == 0);
82*f4f97af0SJanosch Frank 	initialized = true;
83*f4f97af0SJanosch Frank }
84*f4f97af0SJanosch Frank 
85*f4f97af0SJanosch Frank void uv_create_guest(struct vm *vm)
86*f4f97af0SJanosch Frank {
87*f4f97af0SJanosch Frank 	struct uv_cb_cgc uvcb_cgc = {
88*f4f97af0SJanosch Frank 		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
89*f4f97af0SJanosch Frank 		.header.len = sizeof(uvcb_cgc),
90*f4f97af0SJanosch Frank 	};
91*f4f97af0SJanosch Frank 	struct uv_cb_csc uvcb_csc = {
92*f4f97af0SJanosch Frank 		.header.len = sizeof(uvcb_csc),
93*f4f97af0SJanosch Frank 		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
94*f4f97af0SJanosch Frank 		.state_origin = (uint64_t)vm->sblk,
95*f4f97af0SJanosch Frank 		.num = 0,
96*f4f97af0SJanosch Frank 	};
97*f4f97af0SJanosch Frank 	unsigned long vsize;
98*f4f97af0SJanosch Frank 	int cc;
99*f4f97af0SJanosch Frank 
100*f4f97af0SJanosch Frank 	uvcb_cgc.guest_stor_origin = vm->sblk->mso;
101*f4f97af0SJanosch Frank 	uvcb_cgc.guest_stor_len = vm->sblk->msl;
102*f4f97af0SJanosch Frank 
103*f4f97af0SJanosch Frank 	/* Config allocation */
104*f4f97af0SJanosch Frank 	vsize = uvcb_qui.conf_base_virt_stor_len +
105*f4f97af0SJanosch Frank 		((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len);
106*f4f97af0SJanosch Frank 
107*f4f97af0SJanosch Frank 	vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0);
108*f4f97af0SJanosch Frank 	/*
109*f4f97af0SJanosch Frank 	 * This allocation needs to be below the max guest storage
110*f4f97af0SJanosch Frank 	 * address so let's simply put it into the physical memory
111*f4f97af0SJanosch Frank 	 */
112*f4f97af0SJanosch Frank 	vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0);
113*f4f97af0SJanosch Frank 	uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor;
114*f4f97af0SJanosch Frank 	uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor;
115*f4f97af0SJanosch Frank 
116*f4f97af0SJanosch Frank 	/* CPU allocation */
117*f4f97af0SJanosch Frank 	vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0);
118*f4f97af0SJanosch Frank 	uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor;
119*f4f97af0SJanosch Frank 
120*f4f97af0SJanosch Frank 	uvcb_cgc.guest_asce = (uint64_t)stctg(1);
121*f4f97af0SJanosch Frank 	uvcb_cgc.guest_sca = (uint64_t)vm->sca;
122*f4f97af0SJanosch Frank 
123*f4f97af0SJanosch Frank 	cc = uv_call(0, (uint64_t)&uvcb_cgc);
124*f4f97af0SJanosch Frank 	assert(!cc);
125*f4f97af0SJanosch Frank 
126*f4f97af0SJanosch Frank 	vm->uv.vm_handle = uvcb_cgc.guest_handle;
127*f4f97af0SJanosch Frank 	uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
128*f4f97af0SJanosch Frank 	cc = uv_call(0, (uint64_t)&uvcb_csc);
129*f4f97af0SJanosch Frank 	vm->uv.vcpu_handle = uvcb_csc.cpu_handle;
130*f4f97af0SJanosch Frank 	assert(!cc);
131*f4f97af0SJanosch Frank 
132*f4f97af0SJanosch Frank 	/*
133*f4f97af0SJanosch Frank 	 * Convert guest to format 4:
134*f4f97af0SJanosch Frank 	 *
135*f4f97af0SJanosch Frank 	 *  - Set format 4
136*f4f97af0SJanosch Frank 	 *  - Write UV handles into sblk
137*f4f97af0SJanosch Frank 	 *  - Allocate and set SIDA
138*f4f97af0SJanosch Frank 	 */
139*f4f97af0SJanosch Frank 	vm->sblk->sdf = 2;
140*f4f97af0SJanosch Frank 	vm->sblk->sidad = (uint64_t)alloc_page();
141*f4f97af0SJanosch Frank 	vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle;
142*f4f97af0SJanosch Frank 	vm->sblk->pv_handle_config = uvcb_cgc.guest_handle;
143*f4f97af0SJanosch Frank }
144*f4f97af0SJanosch Frank 
145*f4f97af0SJanosch Frank void uv_destroy_guest(struct vm *vm)
146*f4f97af0SJanosch Frank {
147*f4f97af0SJanosch Frank 	int cc;
148*f4f97af0SJanosch Frank 	u16 rc, rrc;
149*f4f97af0SJanosch Frank 
150*f4f97af0SJanosch Frank 	cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu,
151*f4f97af0SJanosch Frank 			   UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc);
152*f4f97af0SJanosch Frank 	assert(cc == 0);
153*f4f97af0SJanosch Frank 	free_page((void *)vm->sblk->sidad);
154*f4f97af0SJanosch Frank 	free_pages(vm->uv.cpu_stor);
155*f4f97af0SJanosch Frank 
156*f4f97af0SJanosch Frank 	cc = uv_cmd_nodata(vm->sblk->pv_handle_config,
157*f4f97af0SJanosch Frank 			   UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc);
158*f4f97af0SJanosch Frank 	assert(cc == 0);
159*f4f97af0SJanosch Frank 	free_pages(vm->uv.conf_base_stor);
160*f4f97af0SJanosch Frank 	free_pages(vm->uv.conf_var_stor);
161*f4f97af0SJanosch Frank }
162*f4f97af0SJanosch Frank 
163*f4f97af0SJanosch Frank int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak)
164*f4f97af0SJanosch Frank {
165*f4f97af0SJanosch Frank 	int i, cc;
166*f4f97af0SJanosch Frank 
167*f4f97af0SJanosch Frank 	for (i = 0; i < len / PAGE_SIZE; i++) {
168*f4f97af0SJanosch Frank 		cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE);
169*f4f97af0SJanosch Frank 		assert(!cc);
170*f4f97af0SJanosch Frank 		addr += PAGE_SIZE;
171*f4f97af0SJanosch Frank 	}
172*f4f97af0SJanosch Frank 	return cc;
173*f4f97af0SJanosch Frank }
174*f4f97af0SJanosch Frank 
175*f4f97af0SJanosch Frank void uv_verify_load(struct vm *vm)
176*f4f97af0SJanosch Frank {
177*f4f97af0SJanosch Frank 	uint16_t rc, rrc;
178*f4f97af0SJanosch Frank 	int cc;
179*f4f97af0SJanosch Frank 
180*f4f97af0SJanosch Frank 	cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc);
181*f4f97af0SJanosch Frank 	assert(!cc);
182*f4f97af0SJanosch Frank 	cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD);
183*f4f97af0SJanosch Frank 	assert(!cc);
184*f4f97af0SJanosch Frank }
185