1 /* SPDX-License-Identifier: GPL-2.0+ OR MIT */
2 /**************************************************************************
3  *
4  * Copyright 2016 VMware, Inc., Palo Alto, CA., USA
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************
27  *
28  * Based on code from vmware.c and vmmouse.c.
29  * Author:
30  *   Sinclair Yeh <syeh@vmware.com>
31  */
32 #ifndef _VMWGFX_MSG_H
33 #define _VMWGFX_MSG_H
34 
35 
36 /**
37  * Hypervisor-specific bi-directional communication channel.  Should never
38  * execute on bare metal hardware.  The caller must make sure to check for
39  * supported hypervisor before using these macros.
40  *
41  * The last two parameters are both input and output and must be initialized.
42  *
43  * @cmd: [IN] Message Cmd
44  * @in_ebx: [IN] Message Len, through EBX
45  * @in_si: [IN] Input argument through SI, set to 0 if not used
46  * @in_di: [IN] Input argument through DI, set ot 0 if not used
47  * @port_num: [IN] port number + [channel id]
48  * @magic: [IN] hypervisor magic value
49  * @eax: [OUT] value of EAX register
50  * @ebx: [OUT] e.g. status from an HB message status command
51  * @ecx: [OUT] e.g. status from a non-HB message status command
52  * @edx: [OUT] e.g. channel id
53  * @si:  [OUT]
54  * @di:  [OUT]
55  */
56 #define VMW_PORT(cmd, in_ebx, in_si, in_di,	\
57 		 port_num, magic,		\
58 		 eax, ebx, ecx, edx, si, di)	\
59 ({						\
60 	asm volatile ("inl %%dx, %%eax;" :	\
61 		"=a"(eax),			\
62 		"=b"(ebx),			\
63 		"=c"(ecx),			\
64 		"=d"(edx),			\
65 		"=S"(si),			\
66 		"=D"(di) :			\
67 		"a"(magic),			\
68 		"b"(in_ebx),			\
69 		"c"(cmd),			\
70 		"d"(port_num),			\
71 		"S"(in_si),			\
72 		"D"(in_di) :			\
73 		"memory");			\
74 })
75 
76 
77 /**
78  * Hypervisor-specific bi-directional communication channel.  Should never
79  * execute on bare metal hardware.  The caller must make sure to check for
80  * supported hypervisor before using these macros.
81  *
82  * The last 3 parameters are both input and output and must be initialized.
83  *
84  * @cmd: [IN] Message Cmd
85  * @in_ecx: [IN] Message Len, through ECX
86  * @in_si: [IN] Input argument through SI, set to 0 if not used
87  * @in_di: [IN] Input argument through DI, set to 0 if not used
88  * @port_num: [IN] port number + [channel id]
89  * @magic: [IN] hypervisor magic value
90  * @bp:  [IN]
91  * @eax: [OUT] value of EAX register
92  * @ebx: [OUT] e.g. status from an HB message status command
93  * @ecx: [OUT] e.g. status from a non-HB message status command
94  * @edx: [OUT] e.g. channel id
95  * @si:  [OUT]
96  * @di:  [OUT]
97  */
98 #ifdef __x86_64__
99 
100 #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di,	\
101 			port_num, magic, bp,		\
102 			eax, ebx, ecx, edx, si, di)	\
103 ({							\
104 	asm volatile ("push %%rbp;"			\
105 		"mov %12, %%rbp;"			\
106 		"rep outsb;"				\
107 		"pop %%rbp;" :				\
108 		"=a"(eax),				\
109 		"=b"(ebx),				\
110 		"=c"(ecx),				\
111 		"=d"(edx),				\
112 		"=S"(si),				\
113 		"=D"(di) :				\
114 		"a"(magic),				\
115 		"b"(cmd),				\
116 		"c"(in_ecx),				\
117 		"d"(port_num),				\
118 		"S"(in_si),				\
119 		"D"(in_di),				\
120 		"r"(bp) :				\
121 		"memory", "cc");			\
122 })
123 
124 
125 #define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di,	\
126 		       port_num, magic, bp,		\
127 		       eax, ebx, ecx, edx, si, di)	\
128 ({							\
129 	asm volatile ("push %%rbp;"			\
130 		"mov %12, %%rbp;"			\
131 		"rep insb;"				\
132 		"pop %%rbp" :				\
133 		"=a"(eax),				\
134 		"=b"(ebx),				\
135 		"=c"(ecx),				\
136 		"=d"(edx),				\
137 		"=S"(si),				\
138 		"=D"(di) :				\
139 		"a"(magic),				\
140 		"b"(cmd),				\
141 		"c"(in_ecx),				\
142 		"d"(port_num),				\
143 		"S"(in_si),				\
144 		"D"(in_di),				\
145 		"r"(bp) :				\
146 		"memory", "cc");			\
147 })
148 
149 #else
150 
151 /*
152  * In the 32-bit version of this macro, we store bp in a memory location
153  * because we've ran out of registers.
154  * Now we can't reference that memory location while we've modified
155  * %esp or %ebp, so we first push it on the stack, just before we push
156  * %ebp, and then when we need it we read it from the stack where we
157  * just pushed it.
158  */
159 #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di,	\
160 			port_num, magic, bp,		\
161 			eax, ebx, ecx, edx, si, di)	\
162 ({							\
163 	asm volatile ("push %12;"			\
164 		"push %%ebp;"				\
165 		"mov 0x04(%%esp), %%ebp;"		\
166 		"rep outsb;"				\
167 		"pop %%ebp;"				\
168 		"add $0x04, %%esp;" :			\
169 		"=a"(eax),				\
170 		"=b"(ebx),				\
171 		"=c"(ecx),				\
172 		"=d"(edx),				\
173 		"=S"(si),				\
174 		"=D"(di) :				\
175 		"a"(magic),				\
176 		"b"(cmd),				\
177 		"c"(in_ecx),				\
178 		"d"(port_num),				\
179 		"S"(in_si),				\
180 		"D"(in_di),				\
181 		"m"(bp) :				\
182 		"memory", "cc");			\
183 })
184 
185 
186 #define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di,	\
187 		       port_num, magic, bp,		\
188 		       eax, ebx, ecx, edx, si, di)	\
189 ({							\
190 	asm volatile ("push %12;"			\
191 		"push %%ebp;"				\
192 		"mov 0x04(%%esp), %%ebp;"		\
193 		"rep insb;"				\
194 		"pop %%ebp;"				\
195 		"add $0x04, %%esp;" :			\
196 		"=a"(eax),				\
197 		"=b"(ebx),				\
198 		"=c"(ecx),				\
199 		"=d"(edx),				\
200 		"=S"(si),				\
201 		"=D"(di) :				\
202 		"a"(magic),				\
203 		"b"(cmd),				\
204 		"c"(in_ecx),				\
205 		"d"(port_num),				\
206 		"S"(in_si),				\
207 		"D"(in_di),				\
208 		"m"(bp) :				\
209 		"memory", "cc");			\
210 })
211 #endif /* #if __x86_64__ */
212 
213 #endif
214