1 /* $NetBSD: vmtvar.h,v 1.2 2021/03/27 21:23:14 ryo Exp $ */ 2 /* NetBSD: vmt.c,v 1.15 2016/11/10 03:32:04 ozaki-r Exp */ 3 /* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */ 4 5 /* 6 * Copyright (c) 2007 David Crawshaw <david (at) zentus.com> 7 * Copyright (c) 2008 David Gwynne <dlg (at) openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #ifndef _DEV_VMT_VMTVAR_H_ 23 #define _DEV_VMT_VMTVAR_H_ 24 25 #include <sys/uuid.h> 26 #include <dev/sysmon/sysmonvar.h> 27 28 /* A register frame. */ 29 /* XXX 'volatile' as a workaround because BACKDOOR_OP is likely broken */ 30 struct vm_backdoor { 31 volatile register_t eax; 32 volatile register_t ebx; 33 volatile register_t ecx; 34 volatile register_t edx; 35 volatile register_t esi; 36 volatile register_t edi; 37 volatile register_t ebp; 38 }; 39 40 #define VM_REG_LOW_MASK __BITS(15,0) 41 #define VM_REG_HIGH_MASK __BITS(31,16) 42 #define VM_REG_WORD_MASK __BITS(31,0) 43 #define VM_REG_CMD(hi, low) \ 44 (__SHIFTIN((hi), VM_REG_HIGH_MASK) | __SHIFTIN((low), VM_REG_LOW_MASK)) 45 #define VM_REG_CMD_RPC(cmd) VM_REG_CMD((cmd), VM_CMD_RPC) 46 #define VM_REG_PORT_CMD(cmd) VM_REG_CMD((cmd), VM_PORT_CMD) 47 #define VM_REG_PORT_RPC(cmd) VM_REG_CMD((cmd), VM_PORT_RPC) 48 49 /* RPC context. */ 50 struct vm_rpc { 51 uint16_t channel; 52 uint32_t cookie1; 53 uint32_t cookie2; 54 }; 55 56 struct vmt_event { 57 struct sysmon_pswitch ev_smpsw; 58 int ev_code; 59 }; 60 61 struct vmt_softc { 62 device_t sc_dev; 63 64 struct sysctllog *sc_log; 65 struct vm_rpc sc_tclo_rpc; 66 bool sc_tclo_rpc_open; 67 char *sc_rpc_buf; 68 int sc_rpc_error; 69 int sc_tclo_ping; 70 int sc_set_guest_os; 71 #define VMT_RPC_BUFLEN 256 72 73 struct callout sc_tick; 74 struct callout sc_tclo_tick; 75 76 #define VMT_CLOCK_SYNC_PERIOD_SECONDS 60 77 int sc_clock_sync_period_seconds; 78 struct callout sc_clock_sync_tick; 79 80 struct vmt_event sc_ev_power; 81 struct vmt_event sc_ev_reset; 82 struct vmt_event sc_ev_sleep; 83 bool sc_smpsw_valid; 84 85 char sc_hostname[MAXHOSTNAMELEN]; 86 char sc_uuid[_UUID_STR_LEN]; 87 }; 88 89 bool vmt_probe(void); 90 void vmt_common_attach(struct vmt_softc *); 91 int vmt_common_detach(struct vmt_softc *); 92 93 #define BACKDOOR_OP_I386(op, frame) \ 94 __asm__ __volatile__ ( \ 95 "pushal;" \ 96 "pushl %%eax;" \ 97 "movl 0x18(%%eax), %%ebp;" \ 98 "movl 0x14(%%eax), %%edi;" \ 99 "movl 0x10(%%eax), %%esi;" \ 100 "movl 0x0c(%%eax), %%edx;" \ 101 "movl 0x08(%%eax), %%ecx;" \ 102 "movl 0x04(%%eax), %%ebx;" \ 103 "movl 0x00(%%eax), %%eax;" \ 104 op \ 105 "xchgl %%eax, 0x00(%%esp);" \ 106 "movl %%ebp, 0x18(%%eax);" \ 107 "movl %%edi, 0x14(%%eax);" \ 108 "movl %%esi, 0x10(%%eax);" \ 109 "movl %%edx, 0x0c(%%eax);" \ 110 "movl %%ecx, 0x08(%%eax);" \ 111 "movl %%ebx, 0x04(%%eax);" \ 112 "popl 0x00(%%eax);" \ 113 "popal;" \ 114 : \ 115 :"a"(frame) \ 116 ) 117 118 #define BACKDOOR_OP_AMD64(op, frame) \ 119 __asm__ __volatile__ ( \ 120 "pushq %%rbp; \n\t" \ 121 "pushq %%rax; \n\t" \ 122 "movq 0x30(%%rax), %%rbp; \n\t" \ 123 "movq 0x28(%%rax), %%rdi; \n\t" \ 124 "movq 0x20(%%rax), %%rsi; \n\t" \ 125 "movq 0x18(%%rax), %%rdx; \n\t" \ 126 "movq 0x10(%%rax), %%rcx; \n\t" \ 127 "movq 0x08(%%rax), %%rbx; \n\t" \ 128 "movq 0x00(%%rax), %%rax; \n\t" \ 129 op "\n\t" \ 130 "xchgq %%rax, 0x00(%%rsp); \n\t" \ 131 "movq %%rbp, 0x30(%%rax); \n\t" \ 132 "movq %%rdi, 0x28(%%rax); \n\t" \ 133 "movq %%rsi, 0x20(%%rax); \n\t" \ 134 "movq %%rdx, 0x18(%%rax); \n\t" \ 135 "movq %%rcx, 0x10(%%rax); \n\t" \ 136 "movq %%rbx, 0x08(%%rax); \n\t" \ 137 "popq 0x00(%%rax); \n\t" \ 138 "popq %%rbp; \n\t" \ 139 : /* No outputs. */ \ 140 : "a" (frame) \ 141 /* No pushal on amd64 so warn gcc about the clobbered registers. */\ 142 : "rbx", "rcx", "rdx", "rdi", "rsi", "cc", "memory" \ 143 ) 144 145 #define X86_IO_MAGIC 0x86 /* magic for upper 32bit of x7 */ 146 #define X86_IO_W7_SIZE_MASK __BITS(1, 0) 147 #define X86_IO_W7_SIZE(n) __SHIFTIN((n), X86_IO_W7_SIZE_MASK) 148 #define X86_IO_W7_DIR __BIT(2) 149 #define X86_IO_W7_WITH __BIT(3) 150 #define X86_IO_W7_STR __BIT(4) 151 #define X86_IO_W7_DF __BIT(5) 152 #define X86_IO_W7_IMM_MASK __BITS(12, 5) 153 #define X86_IO_W7_IMM(imm) __SHIFTIN((imm), X86_IO_W7_IMM_MASK) 154 #define BACKDOOR_OP_AARCH64(op, frame) \ 155 __asm__ __volatile__ ( \ 156 "ldp x0, x1, [%0, 8 * 0]; \n\t" \ 157 "ldp x2, x3, [%0, 8 * 2]; \n\t" \ 158 "ldp x4, x5, [%0, 8 * 4]; \n\t" \ 159 "ldr x6, [%0, 8 * 6]; \n\t" \ 160 "mov x7, %1 \n\t" \ 161 "movk x7, %2, lsl #32; \n\t" \ 162 "mrs xzr, mdccsr_el0; \n\t" \ 163 "stp x0, x1, [%0, 8 * 0]; \n\t" \ 164 "stp x2, x3, [%0, 8 * 2]; \n\t" \ 165 "stp x4, x5, [%0, 8 * 4]; \n\t" \ 166 "str x6, [%0, 8 * 6]; \n\t" \ 167 : /* No outputs. */ \ 168 : "r" (frame), \ 169 "r" (op), \ 170 "i" (X86_IO_MAGIC) \ 171 : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "memory" \ 172 ) 173 174 #if defined(__i386__) 175 #define BACKDOOR_OP(op, frame) BACKDOOR_OP_I386(op, frame) 176 #elif defined(__amd64__) 177 #define BACKDOOR_OP(op, frame) BACKDOOR_OP_AMD64(op, frame) 178 #elif defined(__aarch64__) 179 #define BACKDOOR_OP(op, frame) BACKDOOR_OP_AARCH64(op, frame) 180 #endif 181 182 #if defined(__i386__) || defined(__amd64__) 183 #define BACKDOOR_OP_CMD "inl %%dx, %%eax;" 184 #define BACKDOOR_OP_IN "cld;\n\trep insb;" 185 #define BACKDOOR_OP_OUT "cld;\n\trep outsb;" 186 #elif defined(__aarch64__) 187 #define BACKDOOR_OP_CMD (X86_IO_W7_WITH | X86_IO_W7_DIR | X86_IO_W7_SIZE(2)) 188 #define BACKDOOR_OP_IN (X86_IO_W7_WITH | X86_IO_W7_STR | X86_IO_W7_DIR) 189 #define BACKDOOR_OP_OUT (X86_IO_W7_WITH | X86_IO_W7_STR) 190 #endif 191 192 static __inline void 193 vmt_hvcall(uint8_t cmd, u_int regs[6]) 194 { 195 struct vm_backdoor frame; 196 197 memset(&frame, 0, sizeof(frame)); 198 frame.eax = VM_MAGIC; 199 frame.ebx = UINT_MAX; 200 frame.ecx = VM_REG_CMD(0, cmd); 201 frame.edx = VM_REG_PORT_CMD(0); 202 203 BACKDOOR_OP(BACKDOOR_OP_CMD, &frame); 204 205 regs[0] = __SHIFTOUT(frame.eax, VM_REG_WORD_MASK); 206 regs[1] = __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK); 207 regs[2] = __SHIFTOUT(frame.ecx, VM_REG_WORD_MASK); 208 regs[3] = __SHIFTOUT(frame.edx, VM_REG_WORD_MASK); 209 regs[4] = __SHIFTOUT(frame.esi, VM_REG_WORD_MASK); 210 regs[5] = __SHIFTOUT(frame.edi, VM_REG_WORD_MASK); 211 } 212 213 #endif /* _DEV_VMT_VMTVAR_H_ */ 214