Commit | Line | Data |
---|---|---|
5abb9351 VG |
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()) | |
157309a9 | 89 | return -EOPNOTSUPP; |
5abb9351 VG |
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 */ |