xref: /linux/arch/s390/include/asm/uv.h (revision 6fdcba32711044c35c0e1b094cbd8f3f0b4472c9)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Ultravisor Interfaces
4  *
5  * Copyright IBM Corp. 2019
6  *
7  * Author(s):
8  *	Vasily Gorbik <gor@linux.ibm.com>
9  *	Janosch Frank <frankja@linux.ibm.com>
10  */
11 #ifndef _ASM_S390_UV_H
12 #define _ASM_S390_UV_H
13 
14 #include <linux/types.h>
15 #include <linux/errno.h>
16 #include <linux/bug.h>
17 #include <asm/page.h>
18 
19 #define UVC_RC_EXECUTED		0x0001
20 #define UVC_RC_INV_CMD		0x0002
21 #define UVC_RC_INV_STATE	0x0003
22 #define UVC_RC_INV_LEN		0x0005
23 #define UVC_RC_NO_RESUME	0x0007
24 
25 #define UVC_CMD_QUI			0x0001
26 #define UVC_CMD_SET_SHARED_ACCESS	0x1000
27 #define UVC_CMD_REMOVE_SHARED_ACCESS	0x1001
28 
29 /* Bits in installed uv calls */
30 enum uv_cmds_inst {
31 	BIT_UVC_CMD_QUI = 0,
32 	BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
33 	BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
34 };
35 
36 struct uv_cb_header {
37 	u16 len;
38 	u16 cmd;	/* Command Code */
39 	u16 rc;		/* Response Code */
40 	u16 rrc;	/* Return Reason Code */
41 } __packed __aligned(8);
42 
43 struct uv_cb_qui {
44 	struct uv_cb_header header;
45 	u64 reserved08;
46 	u64 inst_calls_list[4];
47 	u64 reserved30[15];
48 } __packed __aligned(8);
49 
50 struct uv_cb_share {
51 	struct uv_cb_header header;
52 	u64 reserved08[3];
53 	u64 paddr;
54 	u64 reserved28;
55 } __packed __aligned(8);
56 
57 static inline int uv_call(unsigned long r1, unsigned long r2)
58 {
59 	int cc;
60 
61 	asm volatile(
62 		"0:	.insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
63 		"		brc	3,0b\n"
64 		"		ipm	%[cc]\n"
65 		"		srl	%[cc],28\n"
66 		: [cc] "=d" (cc)
67 		: [r1] "a" (r1), [r2] "a" (r2)
68 		: "memory", "cc");
69 	return cc;
70 }
71 
72 #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
73 extern int prot_virt_guest;
74 
75 static inline int is_prot_virt_guest(void)
76 {
77 	return prot_virt_guest;
78 }
79 
80 static inline int share(unsigned long addr, u16 cmd)
81 {
82 	struct uv_cb_share uvcb = {
83 		.header.cmd = cmd,
84 		.header.len = sizeof(uvcb),
85 		.paddr = addr
86 	};
87 
88 	if (!is_prot_virt_guest())
89 		return -EOPNOTSUPP;
90 	/*
91 	 * Sharing is page wise, if we encounter addresses that are
92 	 * not page aligned, we assume something went wrong. If
93 	 * malloced structs are passed to this function, we could leak
94 	 * data to the hypervisor.
95 	 */
96 	BUG_ON(addr & ~PAGE_MASK);
97 
98 	if (!uv_call(0, (u64)&uvcb))
99 		return 0;
100 	return -EINVAL;
101 }
102 
103 /*
104  * Guest 2 request to the Ultravisor to make a page shared with the
105  * hypervisor for IO.
106  *
107  * @addr: Real or absolute address of the page to be shared
108  */
109 static inline int uv_set_shared(unsigned long addr)
110 {
111 	return share(addr, UVC_CMD_SET_SHARED_ACCESS);
112 }
113 
114 /*
115  * Guest 2 request to the Ultravisor to make a page unshared.
116  *
117  * @addr: Real or absolute address of the page to be unshared
118  */
119 static inline int uv_remove_shared(unsigned long addr)
120 {
121 	return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
122 }
123 
124 void uv_query_info(void);
125 #else
126 #define is_prot_virt_guest() 0
127 static inline int uv_set_shared(unsigned long addr) { return 0; }
128 static inline int uv_remove_shared(unsigned long addr) { return 0; }
129 static inline void uv_query_info(void) {}
130 #endif
131 
132 #endif /* _ASM_S390_UV_H */
133