mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-12 23:07:21 +00:00
[common/client] ivshmem: add portable external frames
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "common/ivshmem.h"
|
||||
#include "common/ivshmem_dmabuf.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
@@ -39,9 +39,9 @@
|
||||
|
||||
struct IVSHMEMInfo
|
||||
{
|
||||
int devFd;
|
||||
int size;
|
||||
bool hasDMA;
|
||||
int devFd;
|
||||
size_t size;
|
||||
bool hasDMA;
|
||||
};
|
||||
|
||||
static bool ivshmemDeviceValidator(struct Option * opt, const char ** error)
|
||||
@@ -115,23 +115,34 @@ void ivshmemOptionsInit(void)
|
||||
|
||||
bool ivshmemInit(struct IVSHMEM * dev)
|
||||
{
|
||||
// FIXME: split code from ivshmemOpen
|
||||
DEBUG_ASSERT(dev && !dev->opaque);
|
||||
|
||||
dev->size = 0;
|
||||
dev->mem = NULL;
|
||||
dev->opaque = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ivshmemOpen(struct IVSHMEM * dev)
|
||||
bool ivshmemOpen(struct IVSHMEM * dev, IVSHMEMCacheMode cacheMode)
|
||||
{
|
||||
return ivshmemOpenDev(dev, option_get_string("app", "shmFile"));
|
||||
return ivshmemOpenDev(dev, option_get_string("app", "shmFile"),
|
||||
cacheMode);
|
||||
}
|
||||
|
||||
bool ivshmemOpenDev(struct IVSHMEM * dev, const char * shmDevice)
|
||||
bool ivshmemOpenDev(struct IVSHMEM * dev, const char * shmDevice,
|
||||
IVSHMEMCacheMode cacheMode)
|
||||
{
|
||||
DEBUG_ASSERT(dev);
|
||||
DEBUG_ASSERT(dev && !dev->opaque && !dev->mem);
|
||||
|
||||
int devSize;
|
||||
int devFd;
|
||||
bool hasDMA;
|
||||
size_t devSize;
|
||||
int devFd;
|
||||
bool hasDMA;
|
||||
|
||||
/* POSIX mmap does not expose the Windows IVSHMEM driver's cache modes. */
|
||||
(void)cacheMode;
|
||||
|
||||
dev->size = 0;
|
||||
dev->mem = NULL;
|
||||
dev->opaque = NULL;
|
||||
|
||||
DEBUG_INFO("KVMFR Device : %s", shmDevice);
|
||||
@@ -147,14 +158,15 @@ bool ivshmemOpenDev(struct IVSHMEM * dev, const char * shmDevice)
|
||||
}
|
||||
|
||||
// get the device size
|
||||
devSize = ioctl(devFd, KVMFR_DMABUF_GETSIZE, 0);
|
||||
if (devSize < 0)
|
||||
const int size = ioctl(devFd, KVMFR_DMABUF_GETSIZE, 0);
|
||||
if (size <= 0)
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the device size");
|
||||
close(devFd);
|
||||
return false;
|
||||
}
|
||||
hasDMA = true;
|
||||
devSize = (size_t)size;
|
||||
hasDMA = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -175,7 +187,14 @@ bool ivshmemOpenDev(struct IVSHMEM * dev, const char * shmDevice)
|
||||
return false;
|
||||
}
|
||||
|
||||
devSize = st.st_size;
|
||||
if (st.st_size <= 0 || (uintmax_t)st.st_size > SIZE_MAX)
|
||||
{
|
||||
DEBUG_ERROR("Invalid shared memory size: %s", shmDevice);
|
||||
close(devFd);
|
||||
return false;
|
||||
}
|
||||
|
||||
devSize = (size_t)st.st_size;
|
||||
hasDMA = false;
|
||||
}
|
||||
|
||||
@@ -189,6 +208,14 @@ bool ivshmemOpenDev(struct IVSHMEM * dev, const char * shmDevice)
|
||||
}
|
||||
|
||||
struct IVSHMEMInfo * info = malloc(sizeof(*info));
|
||||
if (!info)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate IVSHMEM device state");
|
||||
munmap(map, devSize);
|
||||
close(devFd);
|
||||
return false;
|
||||
}
|
||||
|
||||
info->size = devSize;
|
||||
info->devFd = devFd;
|
||||
info->hasDMA = hasDMA;
|
||||
@@ -220,7 +247,10 @@ void ivshmemClose(struct IVSHMEM * dev)
|
||||
|
||||
void ivshmemFree(struct IVSHMEM * dev)
|
||||
{
|
||||
// FIXME: split code from ivshmemClose
|
||||
DEBUG_ASSERT(dev);
|
||||
|
||||
if (dev->opaque)
|
||||
ivshmemClose(dev);
|
||||
}
|
||||
|
||||
bool ivshmemHasDMA(struct IVSHMEM * dev)
|
||||
@@ -237,7 +267,7 @@ int ivshmemGetDMABuf(struct IVSHMEM * dev, uint64_t offset, uint64_t size)
|
||||
{
|
||||
DEBUG_ASSERT(ivshmemHasDMA(dev));
|
||||
DEBUG_ASSERT(dev && dev->opaque);
|
||||
DEBUG_ASSERT(offset + size <= dev->size);
|
||||
DEBUG_ASSERT(offset <= dev->size && size <= dev->size - offset);
|
||||
|
||||
static long pageSize = 0;
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
#include "ivshmem.h"
|
||||
|
||||
#include <setupapi.h>
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct IVSHMEMInfo
|
||||
{
|
||||
@@ -70,24 +71,57 @@ static int ivshmemComparator(const void * a_, const void * b_)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ivshmemCacheModeToDriver(IVSHMEMCacheMode cacheMode,
|
||||
UINT8 * driverMode)
|
||||
{
|
||||
switch (cacheMode)
|
||||
{
|
||||
case IVSHMEM_CACHE_MODE_NONCACHED:
|
||||
*driverMode = IVSHMEM_CACHE_NONCACHED;
|
||||
return true;
|
||||
|
||||
case IVSHMEM_CACHE_MODE_CACHED:
|
||||
*driverMode = IVSHMEM_CACHE_CACHED;
|
||||
return true;
|
||||
|
||||
case IVSHMEM_CACHE_MODE_WRITECOMBINED:
|
||||
*driverMode = IVSHMEM_CACHE_WRITECOMBINED;
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("Invalid IVSHMEM cache mode: %d", (int)cacheMode);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ivshmemInit(struct IVSHMEM * dev)
|
||||
{
|
||||
DEBUG_ASSERT(dev && !dev->opaque);
|
||||
DEBUG_ASSERT(dev && !dev->opaque && !dev->mem);
|
||||
|
||||
HANDLE handle;
|
||||
HDEVINFO devInfoSet;
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
|
||||
SP_DEVINFO_DATA devInfoData = {0};
|
||||
dev->size = 0;
|
||||
dev->mem = NULL;
|
||||
dev->opaque = NULL;
|
||||
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
HDEVINFO devInfoSet = INVALID_HANDLE_VALUE;
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
|
||||
SP_DEVINFO_DATA devInfoData = {0};
|
||||
SP_DEVICE_INTERFACE_DATA devInterfaceData = {0};
|
||||
Vector devices;
|
||||
|
||||
devInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IVSHMEM, NULL, NULL,
|
||||
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
if (devInfoSet == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DEBUG_WINERROR("SetupDiGetClassDevs failed", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
|
||||
if (!vector_create(&devices, sizeof(struct IVSHMEMData), 1))
|
||||
{
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_ERROR("Failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
@@ -95,8 +129,15 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
for (int i = 0; SetupDiEnumDeviceInfo(devInfoSet, i, &devInfoData); ++i)
|
||||
{
|
||||
struct IVSHMEMData * device = vector_push(&devices, NULL);
|
||||
if (!device)
|
||||
{
|
||||
vector_destroy(&devices);
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD bus, addr;
|
||||
DWORD bus;
|
||||
DWORD addr;
|
||||
if (!SetupDiGetDeviceRegistryProperty(devInfoSet, &devInfoData,
|
||||
SPDRP_BUSNUMBER, NULL, (void*) &bus, sizeof(bus), NULL))
|
||||
{
|
||||
@@ -117,16 +158,19 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
memcpy(&device->devInfoData, &devInfoData, sizeof(SP_DEVINFO_DATA));
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_NO_MORE_ITEMS)
|
||||
const DWORD enumError = GetLastError();
|
||||
if (enumError != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
vector_destroy(&devices);
|
||||
DEBUG_WINERROR("SetupDiEnumDeviceInfo failed", GetLastError());
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_WINERROR("SetupDiEnumDeviceInfo failed", enumError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vector_size(&devices) == 0)
|
||||
{
|
||||
vector_destroy(&devices);
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_ERROR("Failed to find any IVSHMEM devices, unable to continue");
|
||||
DEBUG_ERROR("Did you remember to add the device to your VM "
|
||||
"and is the driver installed?");
|
||||
@@ -145,15 +189,16 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
DEBUG_INFO(
|
||||
"IVSHMEM %" PRIuPTR "%c on bus 0x%lx, device 0x%lx, function 0x%lx",
|
||||
i,
|
||||
i == shmDevice ? '*' : ' ',
|
||||
i == (uintptr_t)shmDevice ? '*' : ' ',
|
||||
bus,
|
||||
addr >> 16,
|
||||
addr & 0xFFFF);
|
||||
}
|
||||
|
||||
if (shmDevice >= vector_size(&devices))
|
||||
if (shmDevice < 0 || (uintptr_t)shmDevice >= vector_size(&devices))
|
||||
{
|
||||
vector_destroy(&devices);
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_ERROR("os:shmDevice %d does not exist", shmDevice);
|
||||
return false;
|
||||
}
|
||||
@@ -165,7 +210,9 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
if (SetupDiEnumDeviceInterfaces(devInfoSet, &devInfoData,
|
||||
&GUID_DEVINTERFACE_IVSHMEM, 0, &devInterfaceData) == FALSE)
|
||||
{
|
||||
DEBUG_WINERROR("SetupDiEnumDeviceInterfaces failed", GetLastError());
|
||||
const DWORD error = GetLastError();
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_WINERROR("SetupDiEnumDeviceInterfaces failed", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -174,25 +221,37 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
NULL, 0, &reqSize, NULL);
|
||||
if (!reqSize)
|
||||
{
|
||||
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", GetLastError());
|
||||
const DWORD error = GetLastError();
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
infData = calloc(1, reqSize);
|
||||
if (!infData)
|
||||
{
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_ERROR("Failed to allocate IVSHMEM interface data");
|
||||
return false;
|
||||
}
|
||||
infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
if (!SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterfaceData, infData,
|
||||
reqSize, NULL, NULL))
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
free(infData);
|
||||
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", GetLastError());
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
handle = CreateFile(infData->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
free(infData);
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
DEBUG_WINERROR("CreateFile returned INVALID_HANDLE_VALUE", GetLastError());
|
||||
DEBUG_WINERROR("CreateFile returned INVALID_HANDLE_VALUE", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -200,6 +259,12 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
SetupDiDestroyDeviceInfoList(devInfoSet);
|
||||
|
||||
struct IVSHMEMInfo * info = malloc(sizeof(*info));
|
||||
if (!info)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
DEBUG_ERROR("Failed to allocate IVSHMEM device state");
|
||||
return false;
|
||||
}
|
||||
|
||||
info->handle = handle;
|
||||
dev->opaque = info;
|
||||
@@ -209,12 +274,16 @@ bool ivshmemInit(struct IVSHMEM * dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ivshmemOpen(struct IVSHMEM * dev)
|
||||
bool ivshmemOpen(struct IVSHMEM * dev, IVSHMEMCacheMode cacheMode)
|
||||
{
|
||||
DEBUG_ASSERT(dev && dev->opaque && !dev->mem);
|
||||
|
||||
struct IVSHMEMInfo * info = (struct IVSHMEMInfo *)dev->opaque;
|
||||
|
||||
UINT8 driverMode;
|
||||
if (!ivshmemCacheModeToDriver(cacheMode, &driverMode))
|
||||
return false;
|
||||
|
||||
IVSHMEM_SIZE size;
|
||||
if (!DeviceIoControl(info->handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size,
|
||||
sizeof(IVSHMEM_SIZE), NULL, NULL))
|
||||
@@ -223,8 +292,15 @@ bool ivshmemOpen(struct IVSHMEM * dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
IVSHMEM_MMAP_CONFIG config = { .cacheMode = IVSHMEM_CACHE_WRITECOMBINED };
|
||||
IVSHMEM_MMAP map = { 0 };
|
||||
const size_t mapSize = (size_t)size;
|
||||
if (!mapSize || (IVSHMEM_SIZE)mapSize != size)
|
||||
{
|
||||
DEBUG_ERROR("Invalid IVSHMEM size: %" PRIu64, (uint64_t)size);
|
||||
return false;
|
||||
}
|
||||
|
||||
IVSHMEM_MMAP_CONFIG config = { .cacheMode = driverMode };
|
||||
IVSHMEM_MMAP map = { 0 };
|
||||
if (!DeviceIoControl(
|
||||
info->handle,
|
||||
IOCTL_IVSHMEM_REQUEST_MMAP,
|
||||
@@ -236,14 +312,36 @@ bool ivshmemOpen(struct IVSHMEM * dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->size = (unsigned int)size;
|
||||
dev->mem = map.ptr;
|
||||
if (!map.ptr || map.size != size)
|
||||
{
|
||||
DEBUG_ERROR("IVSHMEM driver returned an invalid mapping");
|
||||
DeviceIoControl(info->handle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL,
|
||||
0, NULL, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->size = mapSize;
|
||||
dev->mem = map.ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ivshmemOpenDev(struct IVSHMEM * dev, const char * shmDev,
|
||||
IVSHMEMCacheMode cacheMode)
|
||||
{
|
||||
DEBUG_ASSERT(dev);
|
||||
(void)shmDev;
|
||||
(void)cacheMode;
|
||||
|
||||
DEBUG_ERROR("Opening an IVSHMEM device by path is not supported on Windows");
|
||||
return false;
|
||||
}
|
||||
|
||||
void ivshmemClose(struct IVSHMEM * dev)
|
||||
{
|
||||
DEBUG_ASSERT(dev && dev->opaque && dev->mem);
|
||||
DEBUG_ASSERT(dev);
|
||||
|
||||
if (!dev->opaque || !dev->mem)
|
||||
return;
|
||||
|
||||
struct IVSHMEMInfo * info = (struct IVSHMEMInfo *)dev->opaque;
|
||||
|
||||
@@ -257,10 +355,17 @@ void ivshmemClose(struct IVSHMEM * dev)
|
||||
|
||||
void ivshmemFree(struct IVSHMEM * dev)
|
||||
{
|
||||
DEBUG_ASSERT(dev && dev->opaque && !dev->mem);
|
||||
DEBUG_ASSERT(dev);
|
||||
|
||||
if (!dev->opaque)
|
||||
return;
|
||||
|
||||
if (dev->mem)
|
||||
ivshmemClose(dev);
|
||||
|
||||
struct IVSHMEMInfo * info = (struct IVSHMEMInfo *)dev->opaque;
|
||||
|
||||
CloseHandle(info->handle);
|
||||
free(info);
|
||||
dev->opaque = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user