[common] move ivshmem code into the common library

This commit is contained in:
Geoffrey McRae 2020-01-03 14:53:56 +11:00
parent c5baf212c8
commit 89d6ea0b5d
11 changed files with 446 additions and 361 deletions

View File

@ -1 +1 @@
B1-44-g42667ed83a+1 B1-44-gc5baf212c8+1

View File

@ -41,7 +41,6 @@ get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
include_directories( include_directories(
${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include ${CMAKE_BINARY_DIR}/include
${PROJECT_TOP}/vendor/ivshmem
${PKGCONFIG_INCLUDE_DIRS} ${PKGCONFIG_INCLUDE_DIRS}
${GMP_INCLUDE_DIR} ${GMP_INCLUDE_DIR}
) )

View File

@ -27,7 +27,3 @@ void app_quit();
// these must be implemented for each OS // these must be implemented for each OS
const char * os_getExecutable(); const char * os_getExecutable();
unsigned int os_shmemSize();
bool os_shmemMmap(void **ptr);
void os_shmemUnmap();

View File

@ -22,28 +22,24 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/option.h" #include "common/option.h"
#include "common/thread.h" #include "common/thread.h"
#include <assert.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pthread.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
struct app struct app
{ {
const char * executable; const char * executable;
unsigned int shmSize;
int shmFD;
void * shmMap;
}; };
static struct app app; struct app app;
int main(int argc, char * argv[])
{
app.executable = argv[0];
int result = app_main(argc, argv);
return result;
}
void sigHandler(int signo) void sigHandler(int signo)
{ {
@ -51,177 +47,8 @@ void sigHandler(int signo)
app_quit(); app_quit();
} }
static int uioOpenFile(const char * shmDevice, const char * file)
{
int len = snprintf(NULL, 0, "/sys/class/uio/%s/%s", shmDevice, file);
char * path = malloc(len + 1);
sprintf(path, "/sys/class/uio/%s/%s", shmDevice, file);
int fd = open(path, O_RDONLY);
if (fd < 0)
{
free(path);
return -1;
}
free(path);
return fd;
}
static char * uioGetName(const char * shmDevice)
{
int fd = uioOpenFile(shmDevice, "name");
if (fd < 0)
return NULL;
char * name = malloc(32);
int len = read(fd, name, 31);
if (len <= 0)
{
free(name);
close(fd);
return NULL;
}
name[len] = '\0';
close(fd);
while(len > 0 && name[len-1] == '\n')
{
--len;
name[len] = '\0';
}
return name;
}
static int shmOpenDev(const char * shmDevice)
{
int len = snprintf(NULL, 0, "/dev/%s", shmDevice);
char * path = malloc(len + 1);
sprintf(path, "/dev/%s", shmDevice);
int fd = open(path, O_RDWR, (mode_t)0600);
if (fd < 0)
{
DEBUG_ERROR("Failed to open: %s", path);
DEBUG_ERROR("Did you remmeber to modprobe the kvmfr module?");
free(path);
return -1;
}
free(path);
return fd;
}
static bool shmDeviceValidator(struct Option * opt, const char ** error)
{
char * name = uioGetName(opt->value.x_string);
if (!name)
{
*error = "Failed to get the uio device name";
return false;
}
if (strcmp(name, "KVMFR") != 0)
{
free(name);
*error = "Device is not a KVMFR device";
return false;
}
free(name);
return true;
}
static StringList shmDeviceGetValues(struct Option * option)
{
StringList sl = stringlist_new(true);
DIR * d = opendir("/sys/class/uio");
if (!d)
return sl;
struct dirent * dir;
while((dir = readdir(d)) != NULL)
{
if (dir->d_name[0] == '.')
continue;
char * name = uioGetName(dir->d_name);
if (!name)
continue;
if (strcmp(name, "KVMFR") == 0)
stringlist_push(sl, strdup(dir->d_name));
free(name);
}
closedir(d);
return sl;
}
int main(int argc, char * argv[])
{
app.executable = argv[0];
struct Option options[] =
{
{
.module = "os",
.name = "shmDevice",
.description = "The IVSHMEM device to use",
.type = OPTION_TYPE_STRING,
.value.x_string = "uio0",
.validator = shmDeviceValidator,
.getValues = shmDeviceGetValues
},
{0}
};
option_register(options);
int result = app_main(argc, argv);
os_shmemUnmap();
close(app.shmFD);
return result;
}
bool app_init() bool app_init()
{ {
const char * shmDevice = option_get_string("os", "shmDevice");
// get the device size
int fd = uioOpenFile(shmDevice, "maps/map0/size");
if (fd < 0)
{
DEBUG_ERROR("Failed to open %s/size", shmDevice);
DEBUG_ERROR("Did you remmeber to modprobe the kvmfr module?");
return false;
}
char size[32];
int len = read(fd, size, sizeof(size) - 1);
if (len <= 0)
{
DEBUG_ERROR("Failed to read the device size");
close(fd);
return false;
}
size[len] = '\0';
close(fd);
app.shmSize = strtoul(size, NULL, 16);
// open the device
app.shmFD = shmOpenDev(shmDevice);
app.shmMap = MAP_FAILED;
if (app.shmFD < 0)
return false;
DEBUG_INFO("KVMFR Device : %s", shmDevice);
signal(SIGINT, sigHandler); signal(SIGINT, sigHandler);
return true; return true;
} }
@ -230,34 +57,3 @@ const char * os_getExecutable()
{ {
return app.executable; return app.executable;
} }
unsigned int os_shmemSize()
{
return app.shmSize;
}
bool os_shmemMmap(void **ptr)
{
if (app.shmMap == MAP_FAILED)
{
app.shmMap = mmap(0, app.shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, app.shmFD, 0);
if (app.shmMap == MAP_FAILED)
{
const char * shmDevice = option_get_string("os", "shmDevice");
DEBUG_ERROR("Failed to map the shared memory device: %s", shmDevice);
return false;
}
}
*ptr = app.shmMap;
return true;
}
void os_shmemUnmap()
{
if (app.shmMap == MAP_FAILED)
return;
munmap(app.shmMap, app.shmSize);
app.shmMap = MAP_FAILED;
}

View File

@ -21,10 +21,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "windows/mousehook.h" #include "windows/mousehook.h"
#include <windows.h> #include <windows.h>
#include <setupapi.h>
#include <shellapi.h> #include <shellapi.h>
#include <fcntl.h> #include <fcntl.h>
#include <io.h>
#include "interface/platform.h" #include "interface/platform.h"
#include "common/debug.h" #include "common/debug.h"
@ -32,7 +30,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/option.h" #include "common/option.h"
#include "common/locking.h" #include "common/locking.h"
#include "common/thread.h" #include "common/thread.h"
#include "ivshmem.h"
#define ID_MENU_OPEN_LOG 3000 #define ID_MENU_OPEN_LOG 3000
#define ID_MENU_EXIT 3001 #define ID_MENU_EXIT 3001
@ -46,19 +43,11 @@ struct AppState
char ** argv; char ** argv;
char executable[MAX_PATH + 1]; char executable[MAX_PATH + 1];
HANDLE shmemHandle;
bool shmemOwned;
IVSHMEM_MMAP shmemMap;
HWND messageWnd; HWND messageWnd;
HMENU trayMenu; HMENU trayMenu;
}; };
static struct AppState app = static struct AppState app = {0};
{
.shmemHandle = INVALID_HANDLE_VALUE,
.shmemOwned = false,
.shmemMap = {0}
};
// undocumented API to adjust the system timer resolution (yes, its a nasty hack) // undocumented API to adjust the system timer resolution (yes, its a nasty hack)
typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution); typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution);
@ -180,13 +169,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
struct Option options[] = struct Option options[] =
{ {
{
.module = "os",
.name = "shmDevice",
.description = "The IVSHMEM device to use",
.type = OPTION_TYPE_INT,
.value.x_int = 0
},
{ {
.module = "os", .module = "os",
.name = "logFile", .name = "logFile",
@ -278,10 +260,6 @@ shutdown:
} }
finish: finish:
os_shmemUnmap();
if (app.shmemHandle != INVALID_HANDLE_VALUE)
CloseHandle(app.shmemHandle);
for(int i = 0; i < app.argc; ++i) for(int i = 0; i < app.argc; ++i)
free(app.argv[i]); free(app.argv[i]);
@ -292,7 +270,6 @@ finish:
bool app_init() bool app_init()
{ {
const int shmDevice = option_get_int ("os", "shmDevice");
const char * logFile = option_get_string("os", "logFile" ); const char * logFile = option_get_string("os", "logFile" );
// redirect stderr to a file // redirect stderr to a file
@ -314,56 +291,6 @@ bool app_init()
// get the performance frequency for spinlocks // get the performance frequency for spinlocks
QueryPerformanceFrequency(&app.perfFreq); QueryPerformanceFrequency(&app.perfFreq);
HDEVINFO deviceInfoSet;
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
memset(&deviceInterfaceData, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &GUID_DEVINTERFACE_IVSHMEM, shmDevice, &deviceInterfaceData) == FALSE)
{
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS)
{
DEBUG_WINERROR("Unable to enumerate the device, is it attached?", error);
return false;
}
DEBUG_WINERROR("SetupDiEnumDeviceInterfaces failed", error);
return false;
}
DWORD reqSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &reqSize, NULL);
if (!reqSize)
{
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", GetLastError());
return false;
}
infData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)calloc(reqSize, 1);
infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, infData, reqSize, NULL, NULL))
{
free(infData);
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", GetLastError());
return false;
}
app.shmemHandle = CreateFile(infData->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0);
if (app.shmemHandle == INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(deviceInfoSet);
free(infData);
DEBUG_WINERROR("CreateFile returned INVALID_HANDLE_VALUE", GetLastError());
return false;
}
free(infData);
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return true; return true;
} }
@ -371,56 +298,3 @@ const char * os_getExecutable()
{ {
return app.executable; return app.executable;
} }
unsigned int os_shmemSize()
{
IVSHMEM_SIZE size;
if (!DeviceIoControl(app.shmemHandle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size, sizeof(IVSHMEM_SIZE), NULL, NULL))
{
DEBUG_WINERROR("DeviceIoControl Failed", GetLastError());
return 0;
}
return (unsigned int)size;
}
bool os_shmemMmap(void **ptr)
{
if (app.shmemOwned)
{
*ptr = app.shmemMap.ptr;
return true;
}
IVSHMEM_MMAP_CONFIG config =
{
.cacheMode = IVSHMEM_CACHE_WRITECOMBINED
};
memset(&app.shmemMap, 0, sizeof(IVSHMEM_MMAP));
if (!DeviceIoControl(
app.shmemHandle,
IOCTL_IVSHMEM_REQUEST_MMAP,
&config, sizeof(IVSHMEM_MMAP_CONFIG),
&app.shmemMap, sizeof(IVSHMEM_MMAP),
NULL, NULL))
{
DEBUG_WINERROR("DeviceIoControl Failed", GetLastError());
return false;
}
*ptr = app.shmemMap.ptr;
app.shmemOwned = true;
return true;
}
void os_shmemUnmap()
{
if (!app.shmemOwned)
return;
if (!DeviceIoControl(app.shmemHandle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL, 0, NULL, NULL))
DEBUG_WINERROR("DeviceIoControl failed", GetLastError());
else
app.shmemOwned = false;
}

View File

@ -26,6 +26,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/KVMFR.h" #include "common/KVMFR.h"
#include "common/crash.h" #include "common/crash.h"
#include "common/thread.h" #include "common/thread.h"
#include "common/ivshmem.h"
#include <stdio.h> #include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
@ -324,6 +325,8 @@ int app_main(int argc, char * argv[])
if (!installCrashHandler(os_getExecutable())) if (!installCrashHandler(os_getExecutable()))
DEBUG_WARN("Failed to install the crash handler"); DEBUG_WARN("Failed to install the crash handler");
ivshmemOptionsInit();
// register capture interface options // register capture interface options
for(int i = 0; CaptureInterfaces[i]; ++i) for(int i = 0; CaptureInterfaces[i]; ++i)
if (CaptureInterfaces[i]->initOptions) if (CaptureInterfaces[i]->initOptions)
@ -350,25 +353,25 @@ int app_main(int argc, char * argv[])
if (!app_init()) if (!app_init())
return -1; return -1;
unsigned int shmemSize = os_shmemSize();
uint8_t * shmemMap = NULL;
int exitcode = 0;
DEBUG_INFO("Looking Glass Host (" BUILD_VERSION ")"); DEBUG_INFO("Looking Glass Host (" BUILD_VERSION ")");
DEBUG_INFO("IVSHMEM Size : %u MiB", shmemSize / 1048576);
if (!os_shmemMmap((void **)&shmemMap) || !shmemMap) struct IVSHMEM shmDev;
if (!ivshmemOpen(&shmDev))
{ {
DEBUG_ERROR("Failed to map the shared memory"); DEBUG_ERROR("Failed to open the IVSHMEM device");
return -1; return -1;
} }
DEBUG_INFO("IVSHMEM Address : 0x%" PRIXPTR, (uintptr_t)shmemMap);
app.shmHeader = (KVMFRHeader *)shmemMap; int exitcode = 0;
app.pointerData = (uint8_t *)ALIGN_UP(shmemMap + sizeof(KVMFRHeader)); DEBUG_INFO("IVSHMEM Size : %u MiB", shmDev.size / 1048576);
DEBUG_INFO("IVSHMEM Address : 0x%" PRIXPTR, (uintptr_t)shmDev.mem);
app.shmHeader = (KVMFRHeader *)shmDev.mem;
app.pointerData = (uint8_t *)ALIGN_UP(shmDev.mem + sizeof(KVMFRHeader));
app.pointerDataSize = 1048576; // 1MB fixed for pointer size, should be more then enough app.pointerDataSize = 1048576; // 1MB fixed for pointer size, should be more then enough
app.pointerOffset = app.pointerData - shmemMap; app.pointerOffset = app.pointerData - (uint8_t*)shmDev.mem;
app.frames = (uint8_t *)ALIGN_UP(app.pointerData + app.pointerDataSize); app.frames = (uint8_t *)ALIGN_UP(app.pointerData + app.pointerDataSize);
app.frameSize = ALIGN_DN((shmemSize - (app.frames - shmemMap)) / MAX_FRAMES); app.frameSize = ALIGN_DN((shmDev.size - (app.frames - (uint8_t*)shmDev.mem)) / MAX_FRAMES);
DEBUG_INFO("Max Cursor Size : %u MiB", app.pointerDataSize / 1048576); DEBUG_INFO("Max Cursor Size : %u MiB", app.pointerDataSize / 1048576);
DEBUG_INFO("Max Frame Size : %u MiB", app.frameSize / 1048576); DEBUG_INFO("Max Frame Size : %u MiB", app.frameSize / 1048576);
@ -377,7 +380,7 @@ int app_main(int argc, char * argv[])
for (int i = 0; i < MAX_FRAMES; ++i) for (int i = 0; i < MAX_FRAMES; ++i)
{ {
app.frame [i] = (FrameBuffer)(app.frames + i * app.frameSize); app.frame [i] = (FrameBuffer)(app.frames + i * app.frameSize);
app.frameOffset[i] = (uint8_t *)app.frame[i] - shmemMap; app.frameOffset[i] = (uint8_t *)app.frame[i] - (uint8_t*)shmDev.mem;
DEBUG_INFO("Frame %d : 0x%" PRIXPTR " (0x%08x)", i, (uintptr_t)app.frame[i], app.frameOffset[i]); DEBUG_INFO("Frame %d : 0x%" PRIXPTR " (0x%08x)", i, (uintptr_t)app.frame[i], app.frameOffset[i]);
} }
@ -472,7 +475,7 @@ exit:
iface->deinit(); iface->deinit();
iface->free(); iface->free();
fail: fail:
os_shmemUnmap(); ivshmemClose(&shmDev);
return exitcode; return exitcode;
} }

View File

@ -0,0 +1,35 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 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
*/
#pragma once
#include <stdbool.h>
struct IVSHMEM
{
unsigned int size;
void * mem;
// internal use
void * opaque;
};
void ivshmemOptionsInit();
bool ivshmemOpen(struct IVSHMEM * dev);
void ivshmemClose(struct IVSHMEM * dev);

View File

@ -10,6 +10,7 @@ add_library(lg_common_platform_code STATIC
sysinfo.c sysinfo.c
thread.c thread.c
event.c event.c
ivshmem.c
) )
if(ENABLE_BACKTRACE) if(ENABLE_BACKTRACE)

View File

@ -0,0 +1,227 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 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 "common/ivshmem.h"
#include <assert.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include "common/debug.h"
#include "common/option.h"
#include "common/stringutils.h"
struct IVSHMEMInfo
{
int fd;
int size;
};
static int uioOpenFile(const char * shmDevice, const char * file)
{
char * path;
alloc_sprintf(&path, "/sys/class/uio/%s/%s", shmDevice, file);
int fd = open(path, O_RDONLY);
if (fd < 0)
{
free(path);
return -1;
}
free(path);
return fd;
}
static char * uioGetName(const char * shmDevice)
{
int fd = uioOpenFile(shmDevice, "name");
if (fd < 0)
return NULL;
char * name = malloc(32);
int len = read(fd, name, 31);
if (len <= 0)
{
free(name);
close(fd);
return NULL;
}
name[len] = '\0';
close(fd);
while(len > 0 && name[len-1] == '\n')
{
--len;
name[len] = '\0';
}
return name;
}
static bool ivshmemDeviceValidator(struct Option * opt, const char ** error)
{
char * name = uioGetName(opt->value.x_string);
if (!name)
{
*error = "Failed to get the uio device name";
return false;
}
if (strcmp(name, "KVMFR") != 0)
{
free(name);
*error = "Device is not a KVMFR device";
return false;
}
free(name);
return true;
}
static StringList ivshmemDeviceGetValues(struct Option * option)
{
StringList sl = stringlist_new(true);
DIR * d = opendir("/sys/class/uio");
if (!d)
return sl;
struct dirent * dir;
while((dir = readdir(d)) != NULL)
{
if (dir->d_name[0] == '.')
continue;
char * name = uioGetName(dir->d_name);
if (!name)
continue;
if (strcmp(name, "KVMFR") == 0)
stringlist_push(sl, strdup(dir->d_name));
free(name);
}
closedir(d);
return sl;
}
void ivshmemOptionsInit()
{
struct Option options[] =
{
{
.module = "os",
.name = "shmDevice",
.description = "The IVSHMEM device to use",
.type = OPTION_TYPE_STRING,
.value.x_string = "uio0",
.validator = ivshmemDeviceValidator,
.getValues = ivshmemDeviceGetValues
},
{0}
};
option_register(options);
}
bool ivshmemOpen(struct IVSHMEM * dev)
{
assert(dev);
const char * shmDevice = option_get_string("os", "shmDevice");
unsigned int devSize;
int devFD;
DEBUG_INFO("KVMFR Device : %s", shmDevice);
{
// get the device size
int fd = uioOpenFile(shmDevice, "maps/map0/size");
if (fd < 0)
{
DEBUG_ERROR("Failed to open %s/size", shmDevice);
DEBUG_ERROR("Did you remmeber to modprobe the kvmfr module?");
return false;
}
char size[32];
int len = read(fd, size, sizeof(size) - 1);
if (len <= 0)
{
DEBUG_ERROR("Failed to read the device size");
close(fd);
return false;
}
size[len] = '\0';
close(fd);
devSize = strtoul(size, NULL, 16);
}
{
char * path;
alloc_sprintf(&path, "/dev/%s", shmDevice);
devFD = open(path, O_RDWR, (mode_t)0600);
if (devFD < 0)
{
DEBUG_ERROR("Failed to open: %s", path);
DEBUG_ERROR("Did you remmeber to modprobe the kvmfr module?");
free(path);
return false;
}
free(path);
}
void * map = mmap(0, devSize, PROT_READ | PROT_WRITE, MAP_SHARED, devFD, 0);
if (map == MAP_FAILED)
{
const char * shmDevice = option_get_string("os", "shmDevice");
DEBUG_ERROR("Failed to map the shared memory device: %s", shmDevice);
return false;
}
struct IVSHMEMInfo * info =
(struct IVSHMEMInfo *)malloc(sizeof(struct IVSHMEMInfo));
info->size = devSize;
info->fd = devFD;
dev->opaque = info;
dev->size = devSize;
dev->mem = map;
return false;
}
void ivshmemClose(struct IVSHMEM * dev)
{
assert(dev);
struct IVSHMEMInfo * info =
(struct IVSHMEMInfo *)dev->opaque;
munmap(dev->mem, info->size);
close(info->fd);
free(info);
}

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
project(lg_common_platform_code LANGUAGES C) project(lg_common_platform_code LANGUAGES C)
include_directories( include_directories(
${PROJECT_SOURCE_DIR}/include ${PROJECT_TOP}/vendor/ivshmem
) )
add_library(lg_common_platform_code STATIC add_library(lg_common_platform_code STATIC
@ -11,4 +11,5 @@ add_library(lg_common_platform_code STATIC
thread.c thread.c
event.c event.c
windebug.c windebug.c
ivshmem.c
) )

View File

@ -0,0 +1,153 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 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 "common/ivshmem.h"
#include "common/option.h"
#include "common/windebug.h"
#include <windows.h>
#include "ivshmem.h"
#include <assert.h>
#include <setupapi.h>
#include <io.h>
struct IVSHMEMInfo
{
HANDLE handle;
};
void ivshmemOptionsInit()
{
static struct Option options[] = {
{
.module = "os",
.name = "shmDevice",
.description = "The IVSHMEM device to use",
.type = OPTION_TYPE_INT,
.value.x_int = 0
},
{0}
};
option_register(options);
}
bool ivshmemOpen(struct IVSHMEM * dev)
{
assert(dev);
HANDLE devHandle;
{
HDEVINFO devInfoSet;
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
SP_DEVICE_INTERFACE_DATA devInterfaceData = {0};
devInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
const int shmDevice = option_get_int("os", "shmDevice");
if (SetupDiEnumDeviceInterfaces(devInfoSet, NULL, &GUID_DEVINTERFACE_IVSHMEM, shmDevice, &devInterfaceData) == FALSE)
{
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS)
{
DEBUG_WINERROR("Unable to enumerate the device, is it attached?", error);
return false;
}
DEBUG_WINERROR("SetupDiEnumDeviceInterfaces failed", error);
return false;
}
DWORD reqSize = 0;
SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterfaceData, NULL, 0, &reqSize, NULL);
if (!reqSize)
{
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", GetLastError());
return false;
}
infData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)calloc(reqSize, 1);
infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterfaceData, infData, reqSize, NULL, NULL))
{
free(infData);
DEBUG_WINERROR("SetupDiGetDeviceInterfaceDetail", GetLastError());
return false;
}
devHandle = CreateFile(infData->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0);
if (devHandle == INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(devInfoSet);
free(infData);
DEBUG_WINERROR("CreateFile returned INVALID_HANDLE_VALUE", GetLastError());
return false;
}
free(infData);
SetupDiDestroyDeviceInfoList(devInfoSet);
}
IVSHMEM_SIZE size;
if (!DeviceIoControl(devHandle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size, sizeof(IVSHMEM_SIZE), NULL, NULL))
{
DEBUG_WINERROR("DeviceIoControl Failed", GetLastError());
return 0;
}
IVSHMEM_MMAP_CONFIG config = { .cacheMode = IVSHMEM_CACHE_WRITECOMBINED };
IVSHMEM_MMAP map = { 0 };
if (!DeviceIoControl(
devHandle,
IOCTL_IVSHMEM_REQUEST_MMAP,
&config, sizeof(IVSHMEM_MMAP_CONFIG),
&map , sizeof(IVSHMEM_MMAP),
NULL, NULL))
{
DEBUG_WINERROR("DeviceIoControl Failed", GetLastError());
return false;
}
struct IVSHMEMInfo * info =
(struct IVSHMEMInfo *)malloc(sizeof(struct IVSHMEMInfo));
info->handle = devHandle;
dev->opaque = info;
dev->size = (unsigned int)size;
dev->mem = map.ptr;
return true;
}
void ivshmemClose(struct IVSHMEM * dev)
{
assert(dev);
struct IVSHMEMInfo * info =
(struct IVSHMEMInfo *)dev->opaque;
if (!DeviceIoControl(info->handle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL, 0, NULL, NULL))
DEBUG_WINERROR("DeviceIoControl failed", GetLastError());
free(info);
}