[porthole] initial implementation of the porthole device interface

This is known as 'introspection' in the gnif/qemu repo, it's name is not
final, however porthole is more appropriate but also may not be the
final name.

Note: This branch is experiemental and may never be released if QEMU do
not accept the patch for the new device upstream.
This commit is contained in:
Geoffrey McRae
2019-10-30 17:28:13 +11:00
parent 0e7e918e2c
commit 438548c427
9 changed files with 394 additions and 1 deletions

View File

@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.0)
project(porthole-windows LANGUAGES C)
add_library(porthole-windows STATIC
device.c
)
target_link_libraries(porthole-windows
setupapi
lg_common
)
target_include_directories(porthole-windows
PRIVATE
src
)

View File

@@ -0,0 +1,158 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
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 "porthole/device.h"
#include "driver.h"
#include "common/debug.h"
#include <windows.h>
#include <setupapi.h>
struct PortholeDev
{
HANDLE dev;
};
bool porthole_dev_open(PortholeDev *handle, const uint32_t vendor_id)
{
HDEVINFO devInfo = {0};
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
SP_DEVICE_INTERFACE_DATA devInfData = {0};
HANDLE dev;
if (!handle)
{
DEBUG_ERROR("Invalid buffer provided");
return false;
}
devInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
devInfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for(int devIndex = 0; ; ++devIndex)
{
if (SetupDiEnumDeviceInterfaces(devInfo, NULL, &GUID_DEVINTERFACE_PORTHOLE, devIndex, &devInfData) == FALSE)
{
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS)
{
DEBUG_ERROR("Unable to enumerate the device, is it attached?");
SetupDiDestroyDeviceInfoList(devInfo);
return false;
}
}
DWORD reqSize = 0;
SetupDiGetDeviceInterfaceDetail(devInfo, &devInfData, NULL, 0, &reqSize, NULL);
if (!reqSize)
{
DEBUG_WARN("SetupDiGetDeviceInterfaceDetail for %lu failed\n", reqSize);
continue;
}
infData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)calloc(reqSize, 1);
infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfData, infData, reqSize, NULL, NULL))
{
free(infData);
DEBUG_WARN("SetupDiGetDeviceInterfaceDetail for %lu failed\n", reqSize);
continue;
}
/* get the subsys id from the device */
unsigned int vendorID, deviceID, subsysID;
if (sscanf(infData->DevicePath, "\\\\?\\pci#ven_%4x&dev_%4x&subsys_%8x", &vendorID, &deviceID, &subsysID) != 3)
{
free(infData);
DEBUG_ERROR("Failed to parse: %s", infData->DevicePath);
continue;
}
if (subsysID != vendor_id)
{
DEBUG_INFO("Skipping device %d, vendor_id 0x%x != 0x%x", devIndex, subsysID, vendor_id);
free(infData);
continue;
}
dev = CreateFile(infData->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0);
if (dev == INVALID_HANDLE_VALUE)
{
DEBUG_ERROR("Failed to open device %d", devIndex);
free(infData);
continue;
}
DEBUG_INFO("Device found");
free(infData);
break;
}
*handle = (PortholeDev)calloc(sizeof(struct PortholeDev), 1);
if (!*handle)
{
DEBUG_ERROR("Failed to allocate PortholeDev struct, out of memory!");
CloseHandle(dev);
return false;
}
(*handle)->dev = dev;
return true;
}
void porthole_dev_close(PortholeDev *handle)
{
CloseHandle((*handle)->dev);
free(*handle);
*handle = NULL;
}
bool porthole_dev_share(PortholeDev handle, const uint32_t type, void *buffer, size_t size)
{
DWORD returned;
PortholeMsg msg = {
.type = type,
.addr = buffer,
.size = size
};
if (!DeviceIoControl(handle->dev, IOCTL_PORTHOLE_SEND_MSG, &msg, sizeof(PortholeMsg), NULL, 0, &returned, NULL))
return false;
return true;
}
bool porthole_dev_unlock(PortholeDev handle, void *buffer, size_t size)
{
DWORD returned;
PortholeLockMsg msg = {
.addr = buffer,
.size = size
};
if (!DeviceIoControl(handle->dev, IOCTL_PORTHOLE_UNLOCK_BUFFER, &msg , sizeof(PortholeLockMsg), NULL, 0, &returned, NULL))
return false;
return true;
}

View File

@@ -0,0 +1,24 @@
#include <windows.h>
#include <initguid.h>
DEFINE_GUID (GUID_DEVINTERFACE_PORTHOLE,
0x10ccc0ac,0xf4b0,0x4d78,0xba,0x41,0x1e,0xbb,0x38,0x5a,0x52,0x85);
// {10ccc0ac-f4b0-4d78-ba41-1ebb385a5285}
typedef struct _PortholeMsg
{
UINT32 type;
PVOID addr;
UINT32 size;
}
PortholeMsg, *PPortholeMsg;
typedef struct _PortholeLockMsg
{
PVOID addr;
UINT32 size;
}
PortholeLockMsg, *PPortholeLockMsg;
#define IOCTL_PORTHOLE_SEND_MSG CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PORTHOLE_UNLOCK_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)