mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 14:57:20 +00:00
189 lines
5.1 KiB
C++
189 lines
5.1 KiB
C++
/**
|
|
* Looking Glass
|
|
* Copyright © 2017-2024 The Looking Glass Authors
|
|
* https://looking-glass.io
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "CIVSHMEM.h"
|
|
|
|
#include <Windows.h>
|
|
#include <SetupAPI.h>
|
|
#include <algorithm>
|
|
#include <winioctl.h>
|
|
|
|
#include "Debug.h"
|
|
#include "ivshmem/ivshmem.h"
|
|
|
|
CIVSHMEM::CIVSHMEM()
|
|
{
|
|
}
|
|
|
|
CIVSHMEM::~CIVSHMEM()
|
|
{
|
|
if (m_handle == INVALID_HANDLE_VALUE)
|
|
return;
|
|
|
|
Close();
|
|
CloseHandle(m_handle);
|
|
}
|
|
|
|
bool CIVSHMEM::Init()
|
|
{
|
|
HDEVINFO devInfoSet;
|
|
SP_DEVINFO_DATA devInfoData;
|
|
SP_DEVICE_INTERFACE_DATA devInterfaceData;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = nullptr;
|
|
|
|
devInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IVSHMEM, nullptr, nullptr,
|
|
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
|
|
devInfoData.cbSize = sizeof(devInfoData);
|
|
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
|
|
m_devices.clear();
|
|
for (int i = 0; SetupDiEnumDeviceInfo(devInfoSet, i, &devInfoData); ++i)
|
|
{
|
|
DWORD bus, addr;
|
|
if (!SetupDiGetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_BUSNUMBER,
|
|
nullptr, (BYTE*)&bus, sizeof(bus), nullptr))
|
|
bus = 0xffff;
|
|
|
|
if (!SetupDiGetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_ADDRESS,
|
|
nullptr, (BYTE*)&addr, sizeof(addr), nullptr))
|
|
addr = 0xffff;
|
|
|
|
IVSHMEMData data;
|
|
data.busAddr = ((DWORD64)bus) << 32 | addr;
|
|
memcpy(&data.devInfoData, &devInfoData, sizeof(devInfoData));
|
|
m_devices.push_back(data);
|
|
}
|
|
|
|
if (GetLastError() != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
m_devices.clear();
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return false;
|
|
}
|
|
|
|
std::sort(m_devices.begin(), m_devices.end(),
|
|
[](const IVSHMEMData & a, const IVSHMEMData & b) -> bool
|
|
{ return a.busAddr < b.busAddr; });
|
|
|
|
|
|
HKEY hkeyLG;
|
|
IVSHMEMData * device = nullptr;
|
|
DWORD shmDevice = 0;
|
|
|
|
if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Looking Glass", &hkeyLG) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dataType;
|
|
DWORD dataSize = sizeof(shmDevice);
|
|
if (RegQueryValueExA(hkeyLG, "shmDevice", nullptr, &dataType, (BYTE*)&shmDevice, &dataSize) != ERROR_SUCCESS ||
|
|
dataType != REG_DWORD)
|
|
shmDevice = 0;
|
|
}
|
|
|
|
DWORD i = 0;
|
|
for (auto it = m_devices.begin(); it != m_devices.end(); ++it, ++i)
|
|
{
|
|
DWORD bus = it->busAddr >> 32;
|
|
DWORD addr = it->busAddr & 0xFFFFFFFF;
|
|
DBGPRINT("IVSHMEM %u%c on bus 0x%lx, device 0x%lx, function 0x%lx\n",
|
|
i, i == shmDevice ? '*' : ' ', bus, addr >> 16, addr & 0xFFFF);
|
|
|
|
if (i == shmDevice)
|
|
device = &(*it);
|
|
}
|
|
|
|
if (!device)
|
|
{
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return false;
|
|
}
|
|
|
|
if (SetupDiEnumDeviceInterfaces(devInfoSet, &devInfoData, &GUID_DEVINTERFACE_IVSHMEM, 0, &devInterfaceData) == FALSE)
|
|
{
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return false;
|
|
}
|
|
|
|
DWORD reqSize = 0;
|
|
SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterfaceData, nullptr, 0, &reqSize, nullptr);
|
|
if (!reqSize)
|
|
{
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return false;
|
|
}
|
|
|
|
infData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)calloc(1, reqSize);
|
|
infData->cbSize = sizeof(PSP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
if (!SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterfaceData, infData, reqSize, nullptr, nullptr))
|
|
{
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return false;
|
|
}
|
|
|
|
m_handle = CreateFile(infData->DevicePath, 0, 0, nullptr, OPEN_EXISTING, 0, 0);
|
|
if (m_handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return false;
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList(devInfoSet);
|
|
return true;
|
|
}
|
|
|
|
bool CIVSHMEM::Open()
|
|
{
|
|
IVSHMEM_SIZE size;
|
|
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, nullptr, 0, &size, sizeof(size), nullptr, nullptr))
|
|
{
|
|
DBGPRINT("Failed to request ivshmem size");
|
|
return false;
|
|
}
|
|
|
|
IVSHMEM_MMAP_CONFIG config = {};
|
|
IVSHMEM_MMAP map = {};
|
|
|
|
config.cacheMode = IVSHMEM_CACHE_WRITECOMBINED;
|
|
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_MMAP, &config, sizeof(config), &map, sizeof(map), nullptr, nullptr))
|
|
{
|
|
DBGPRINT("Failed to request ivshmem mmap");
|
|
return false;
|
|
}
|
|
|
|
m_size = (size_t)size;
|
|
m_mem = map.ptr;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CIVSHMEM::Close()
|
|
{
|
|
if (m_mem == nullptr)
|
|
return;
|
|
|
|
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_RELEASE_MMAP, nullptr, 0, nullptr, 0, nullptr, nullptr))
|
|
{
|
|
DBGPRINT("Failed to release ivshmem mmap");
|
|
return;
|
|
}
|
|
|
|
m_size = 0;
|
|
m_mem = nullptr;
|
|
} |