1 /* 2 * Copyright (C) 2016, VMware, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 12 * NON INFRINGEMENT. See the GNU General Public License for more 13 * details. 14 * 15 * Based on code from vmware.c and vmmouse.c. 16 * Author: 17 * Sinclair Yeh <syeh@vmware.com> 18 */ 19 #ifndef _VMWGFX_MSG_H 20 #define _VMWGFX_MSG_H 21 22 23 /** 24 * Hypervisor-specific bi-directional communication channel. Should never 25 * execute on bare metal hardware. The caller must make sure to check for 26 * supported hypervisor before using these macros. 27 * 28 * The last two parameters are both input and output and must be initialized. 29 * 30 * @cmd: [IN] Message Cmd 31 * @in_ebx: [IN] Message Len, through EBX 32 * @in_si: [IN] Input argument through SI, set to 0 if not used 33 * @in_di: [IN] Input argument through DI, set ot 0 if not used 34 * @port_num: [IN] port number + [channel id] 35 * @magic: [IN] hypervisor magic value 36 * @eax: [OUT] value of EAX register 37 * @ebx: [OUT] e.g. status from an HB message status command 38 * @ecx: [OUT] e.g. status from a non-HB message status command 39 * @edx: [OUT] e.g. channel id 40 * @si: [OUT] 41 * @di: [OUT] 42 */ 43 #define VMW_PORT(cmd, in_ebx, in_si, in_di, \ 44 port_num, magic, \ 45 eax, ebx, ecx, edx, si, di) \ 46 ({ \ 47 asm volatile ("inl %%dx, %%eax;" : \ 48 "=a"(eax), \ 49 "=b"(ebx), \ 50 "=c"(ecx), \ 51 "=d"(edx), \ 52 "=S"(si), \ 53 "=D"(di) : \ 54 "a"(magic), \ 55 "b"(in_ebx), \ 56 "c"(cmd), \ 57 "d"(port_num), \ 58 "S"(in_si), \ 59 "D"(in_di) : \ 60 "memory"); \ 61 }) 62 63 64 /** 65 * Hypervisor-specific bi-directional communication channel. Should never 66 * execute on bare metal hardware. The caller must make sure to check for 67 * supported hypervisor before using these macros. 68 * 69 * The last 3 parameters are both input and output and must be initialized. 70 * 71 * @cmd: [IN] Message Cmd 72 * @in_ecx: [IN] Message Len, through ECX 73 * @in_si: [IN] Input argument through SI, set to 0 if not used 74 * @in_di: [IN] Input argument through DI, set to 0 if not used 75 * @port_num: [IN] port number + [channel id] 76 * @magic: [IN] hypervisor magic value 77 * @bp: [IN] 78 * @eax: [OUT] value of EAX register 79 * @ebx: [OUT] e.g. status from an HB message status command 80 * @ecx: [OUT] e.g. status from a non-HB message status command 81 * @edx: [OUT] e.g. channel id 82 * @si: [OUT] 83 * @di: [OUT] 84 */ 85 #ifdef __x86_64__ 86 87 #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ 88 port_num, magic, bp, \ 89 eax, ebx, ecx, edx, si, di) \ 90 ({ \ 91 asm volatile ("push %%rbp;" \ 92 "mov %12, %%rbp;" \ 93 "rep outsb;" \ 94 "pop %%rbp;" : \ 95 "=a"(eax), \ 96 "=b"(ebx), \ 97 "=c"(ecx), \ 98 "=d"(edx), \ 99 "=S"(si), \ 100 "=D"(di) : \ 101 "a"(magic), \ 102 "b"(cmd), \ 103 "c"(in_ecx), \ 104 "d"(port_num), \ 105 "S"(in_si), \ 106 "D"(in_di), \ 107 "r"(bp) : \ 108 "memory", "cc"); \ 109 }) 110 111 112 #define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ 113 port_num, magic, bp, \ 114 eax, ebx, ecx, edx, si, di) \ 115 ({ \ 116 asm volatile ("push %%rbp;" \ 117 "mov %12, %%rbp;" \ 118 "rep insb;" \ 119 "pop %%rbp" : \ 120 "=a"(eax), \ 121 "=b"(ebx), \ 122 "=c"(ecx), \ 123 "=d"(edx), \ 124 "=S"(si), \ 125 "=D"(di) : \ 126 "a"(magic), \ 127 "b"(cmd), \ 128 "c"(in_ecx), \ 129 "d"(port_num), \ 130 "S"(in_si), \ 131 "D"(in_di), \ 132 "r"(bp) : \ 133 "memory", "cc"); \ 134 }) 135 136 #else 137 138 /* 139 * In the 32-bit version of this macro, we store bp in a memory location 140 * because we've ran out of registers. 141 * Now we can't reference that memory location while we've modified 142 * %esp or %ebp, so we first push it on the stack, just before we push 143 * %ebp, and then when we need it we read it from the stack where we 144 * just pushed it. 145 */ 146 #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ 147 port_num, magic, bp, \ 148 eax, ebx, ecx, edx, si, di) \ 149 ({ \ 150 asm volatile ("push %12;" \ 151 "push %%ebp;" \ 152 "mov 0x04(%%esp), %%ebp;" \ 153 "rep outsb;" \ 154 "pop %%ebp;" \ 155 "add $0x04, %%esp;" : \ 156 "=a"(eax), \ 157 "=b"(ebx), \ 158 "=c"(ecx), \ 159 "=d"(edx), \ 160 "=S"(si), \ 161 "=D"(di) : \ 162 "a"(magic), \ 163 "b"(cmd), \ 164 "c"(in_ecx), \ 165 "d"(port_num), \ 166 "S"(in_si), \ 167 "D"(in_di), \ 168 "m"(bp) : \ 169 "memory", "cc"); \ 170 }) 171 172 173 #define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ 174 port_num, magic, bp, \ 175 eax, ebx, ecx, edx, si, di) \ 176 ({ \ 177 asm volatile ("push %12;" \ 178 "push %%ebp;" \ 179 "mov 0x04(%%esp), %%ebp;" \ 180 "rep insb;" \ 181 "pop %%ebp;" \ 182 "add $0x04, %%esp;" : \ 183 "=a"(eax), \ 184 "=b"(ebx), \ 185 "=c"(ecx), \ 186 "=d"(edx), \ 187 "=S"(si), \ 188 "=D"(di) : \ 189 "a"(magic), \ 190 "b"(cmd), \ 191 "c"(in_ecx), \ 192 "d"(port_num), \ 193 "S"(in_si), \ 194 "D"(in_di), \ 195 "m"(bp) : \ 196 "memory", "cc"); \ 197 }) 198 #endif /* #if __x86_64__ */ 199 200 #endif 201