Serenity Operating System
at portability 208 lines 6.4 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Assertions.h> 28#include <AK/String.h> 29#include <Kernel/Arch/i386/CPU.h> 30#include <Kernel/Devices/VMWareBackdoor.h> 31#include <LibBareMetal/IO.h> 32 33namespace Kernel { 34 35#define VMWARE_CMD_GETVERSION 0x0a 36 37#define VMMOUSE_READ_ID 0x45414552 38#define VMMOUSE_DISABLE 0x000000f5 39#define VMMOUSE_REQUEST_RELATIVE 0x4c455252 40#define VMMOUSE_REQUEST_ABSOLUTE 0x53424152 41 42#define VMMOUSE_QEMU_VERSION 0x3442554a 43 44#define VMWARE_MAGIC 0x564D5868 45#define VMWARE_PORT 0x5658 46#define VMWARE_PORT_HIGHBANDWIDTH 0x5659 47 48//#define VMWAREBACKDOOR_DEBUG 49 50inline void vmware_out(VMWareCommand& command) 51{ 52 command.magic = VMWARE_MAGIC; 53 command.port = VMWARE_PORT; 54 command.si = 0; 55 command.di = 0; 56 asm volatile("in %%dx, %0" 57 : "+a"(command.ax), "+b"(command.bx), "+c"(command.cx), "+d"(command.dx), "+S"(command.si), "+D"(command.di)); 58} 59 60inline void vmware_high_bandwidth_send(VMWareCommand& command) 61{ 62 63 command.magic = VMWARE_MAGIC; 64 command.port = VMWARE_PORT_HIGHBANDWIDTH; 65 66 asm volatile("cld; rep; outsb" 67 : "+a"(command.ax), "+b"(command.bx), "+c"(command.cx), "+d"(command.dx), "+S"(command.si), "+D"(command.di)); 68} 69 70inline void vmware_high_bandwidth_get(VMWareCommand& command) 71{ 72 command.magic = VMWARE_MAGIC; 73 command.port = VMWARE_PORT_HIGHBANDWIDTH; 74 asm volatile("cld; rep; insb" 75 : "+a"(command.ax), "+b"(command.bx), "+c"(command.cx), "+d"(command.dx), "+S"(command.si), "+D"(command.di)); 76} 77 78static VMWareBackdoor* s_vmware_backdoor; 79 80static bool is_initialized() 81{ 82 return s_vmware_backdoor != nullptr; 83} 84 85void VMWareBackdoor::initialize() 86{ 87 if (!is_initialized()) 88 s_vmware_backdoor = new VMWareBackdoor; 89} 90 91VMWareBackdoor& VMWareBackdoor::the() 92{ 93 ASSERT(s_vmware_backdoor != nullptr); 94 return *s_vmware_backdoor; 95} 96 97VMWareBackdoor::VMWareBackdoor() 98{ 99 if (!detect_presence()) { 100 kprintf("VMWare Backdoor: Not supported!\n"); 101 m_supported = false; 102 return; 103 } 104 kprintf("VMWare Backdoor: Supported.\n"); 105 m_supported = true; 106} 107bool VMWareBackdoor::detect_presence() 108{ 109 VMWareCommand command; 110 command.bx = ~VMWARE_MAGIC; 111 command.command = VMWARE_CMD_GETVERSION; 112 vmware_out(command); 113 if (command.bx != VMWARE_MAGIC || command.ax == 0xFFFFFFFF) 114 return false; 115 return true; 116} 117 118bool VMWareBackdoor::supported() 119{ 120 return m_supported; 121} 122 123bool VMWareBackdoor::detect_vmmouse() 124{ 125 if (!supported()) 126 return false; 127 VMWareCommand command; 128 command.bx = VMMOUSE_READ_ID; 129 command.command = VMMOUSE_COMMAND; 130 send(command); 131 command.bx = 1; 132 command.command = VMMOUSE_DATA; 133 send(command); 134 if (command.ax != VMMOUSE_QEMU_VERSION) 135 return false; 136 return true; 137} 138bool VMWareBackdoor::vmmouse_is_absolute() 139{ 140 return m_vmmouse_absolute; 141} 142 143void VMWareBackdoor::enable_absolute_vmmouse() 144{ 145 InterruptDisabler disabler; 146 if (!supported() || !detect_vmmouse()) 147 return; 148 dbgprintf("Enabling vmmouse, absolute mode\n"); 149 150 VMWareCommand command; 151 152 command.bx = 0; 153 command.command = VMMOUSE_STATUS; 154 send(command); 155 if (command.ax == 0xFFFF0000) { 156 kprintf("VMMouse retuned bad status.\n"); 157 return; 158 } 159 160 // Enable absolute vmmouse 161 command.bx = VMMOUSE_REQUEST_ABSOLUTE; 162 command.command = VMMOUSE_COMMAND; 163 send(command); 164 m_vmmouse_absolute = true; 165} 166void VMWareBackdoor::disable_absolute_vmmouse() 167{ 168 InterruptDisabler disabler; 169 if (!supported()) 170 return; 171 VMWareCommand command; 172 command.bx = VMMOUSE_REQUEST_RELATIVE; 173 command.command = VMMOUSE_COMMAND; 174 send(command); 175 m_vmmouse_absolute = false; 176} 177 178void VMWareBackdoor::send_high_bandwidth(VMWareCommand& command) 179{ 180 if (supported()) { 181 vmware_high_bandwidth_send(command); 182#ifdef VMWAREBACKDOOR_DEBUG 183 dbg() << "VMWareBackdoor Command High bandwidth Send Results: EAX " << String::format("%x", command.ax) << " EBX " << String::format("%x", command.bx) << " ECX " << String::format("%x", command.cx) << " EDX " << String::format("%x", command.dx); 184#endif 185 } 186} 187 188void VMWareBackdoor::get_high_bandwidth(VMWareCommand& command) 189{ 190 if (supported()) { 191 vmware_high_bandwidth_get(command); 192#ifdef VMWAREBACKDOOR_DEBUG 193 dbg() << "VMWareBackdoor Command High bandwidth Get Results: EAX " << String::format("%x", command.ax) << " EBX " << String::format("%x", command.bx) << " ECX " << String::format("%x", command.cx) << " EDX " << String::format("%x", command.dx); 194#endif 195 } 196} 197 198void VMWareBackdoor::send(VMWareCommand& command) 199{ 200 if (supported()) { 201 vmware_out(command); 202#ifdef VMWAREBACKDOOR_DEBUG 203 dbg() << "VMWareBackdoor Command Send Results: EAX " << String::format("%x", command.ax) << " EBX " << String::format("%x", command.bx) << " ECX " << String::format("%x", command.cx) << " EDX " << String::format("%x", command.dx); 204#endif 205 } 206} 207 208}