From 89d6ea0b5d197e664ebef78f95bc3c88495e04f3 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Fri, 3 Jan 2020 14:53:56 +1100 Subject: [PATCH] [common] move ivshmem code into the common library --- VERSION | 2 +- c-host/CMakeLists.txt | 1 - c-host/include/interface/platform.h | 6 +- c-host/platform/Linux/src/platform.c | 220 +------------------- c-host/platform/Windows/src/platform.c | 128 +----------- c-host/src/app.c | 31 +-- common/include/common/ivshmem.h | 35 ++++ common/src/platform/linux/CMakeLists.txt | 1 + common/src/platform/linux/ivshmem.c | 227 +++++++++++++++++++++ common/src/platform/windows/CMakeLists.txt | 3 +- common/src/platform/windows/ivshmem.c | 153 ++++++++++++++ 11 files changed, 446 insertions(+), 361 deletions(-) create mode 100644 common/include/common/ivshmem.h create mode 100644 common/src/platform/linux/ivshmem.c create mode 100644 common/src/platform/windows/ivshmem.c diff --git a/VERSION b/VERSION index 03de805f..23de0444 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -B1-44-g42667ed83a+1 \ No newline at end of file +B1-44-gc5baf212c8+1 \ No newline at end of file diff --git a/c-host/CMakeLists.txt b/c-host/CMakeLists.txt index 776de9c1..37f78e9d 100644 --- a/c-host/CMakeLists.txt +++ b/c-host/CMakeLists.txt @@ -41,7 +41,6 @@ get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE) include_directories( ${PROJECT_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${PROJECT_TOP}/vendor/ivshmem ${PKGCONFIG_INCLUDE_DIRS} ${GMP_INCLUDE_DIR} ) diff --git a/c-host/include/interface/platform.h b/c-host/include/interface/platform.h index 8e4f201d..5decd32c 100644 --- a/c-host/include/interface/platform.h +++ b/c-host/include/interface/platform.h @@ -26,8 +26,4 @@ bool app_init(); void app_quit(); // these must be implemented for each OS -const char * os_getExecutable(); - -unsigned int os_shmemSize(); -bool os_shmemMmap(void **ptr); -void os_shmemUnmap(); +const char * os_getExecutable(); \ No newline at end of file diff --git a/c-host/platform/Linux/src/platform.c b/c-host/platform/Linux/src/platform.c index 5a6ea044..2313c618 100644 --- a/c-host/platform/Linux/src/platform.c +++ b/c-host/platform/Linux/src/platform.c @@ -22,28 +22,24 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "common/option.h" #include "common/thread.h" -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include struct app { 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) { @@ -51,177 +47,8 @@ void sigHandler(int signo) 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() { - 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); return true; } @@ -229,35 +56,4 @@ bool app_init() const char * os_getExecutable() { 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; } \ No newline at end of file diff --git a/c-host/platform/Windows/src/platform.c b/c-host/platform/Windows/src/platform.c index 1715d540..b03a07b3 100644 --- a/c-host/platform/Windows/src/platform.c +++ b/c-host/platform/Windows/src/platform.c @@ -21,10 +21,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "windows/mousehook.h" #include -#include #include #include -#include #include "interface/platform.h" #include "common/debug.h" @@ -32,7 +30,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "common/option.h" #include "common/locking.h" #include "common/thread.h" -#include "ivshmem.h" #define ID_MENU_OPEN_LOG 3000 #define ID_MENU_EXIT 3001 @@ -46,19 +43,11 @@ struct AppState char ** argv; char executable[MAX_PATH + 1]; - HANDLE shmemHandle; - bool shmemOwned; - IVSHMEM_MMAP shmemMap; HWND messageWnd; HMENU trayMenu; }; -static struct AppState app = -{ - .shmemHandle = INVALID_HANDLE_VALUE, - .shmemOwned = false, - .shmemMap = {0} -}; +static struct AppState app = {0}; // undocumented API to adjust the system timer resolution (yes, its a nasty hack) 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[] = { - { - .module = "os", - .name = "shmDevice", - .description = "The IVSHMEM device to use", - .type = OPTION_TYPE_INT, - .value.x_int = 0 - }, { .module = "os", .name = "logFile", @@ -278,10 +260,6 @@ shutdown: } finish: - os_shmemUnmap(); - - if (app.shmemHandle != INVALID_HANDLE_VALUE) - CloseHandle(app.shmemHandle); for(int i = 0; i < app.argc; ++i) free(app.argv[i]); @@ -292,7 +270,6 @@ finish: bool app_init() { - const int shmDevice = option_get_int ("os", "shmDevice"); const char * logFile = option_get_string("os", "logFile" ); // redirect stderr to a file @@ -314,113 +291,10 @@ bool app_init() // get the performance frequency for spinlocks 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; } const char * os_getExecutable() { 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; } \ No newline at end of file diff --git a/c-host/src/app.c b/c-host/src/app.c index ec383fe6..a201b085 100644 --- a/c-host/src/app.c +++ b/c-host/src/app.c @@ -26,6 +26,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "common/KVMFR.h" #include "common/crash.h" #include "common/thread.h" +#include "common/ivshmem.h" #include #include @@ -324,6 +325,8 @@ int app_main(int argc, char * argv[]) if (!installCrashHandler(os_getExecutable())) DEBUG_WARN("Failed to install the crash handler"); + ivshmemOptionsInit(); + // register capture interface options for(int i = 0; CaptureInterfaces[i]; ++i) if (CaptureInterfaces[i]->initOptions) @@ -350,25 +353,25 @@ int app_main(int argc, char * argv[]) if (!app_init()) return -1; - unsigned int shmemSize = os_shmemSize(); - uint8_t * shmemMap = NULL; - int exitcode = 0; - 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; } - DEBUG_INFO("IVSHMEM Address : 0x%" PRIXPTR, (uintptr_t)shmemMap); - app.shmHeader = (KVMFRHeader *)shmemMap; - app.pointerData = (uint8_t *)ALIGN_UP(shmemMap + sizeof(KVMFRHeader)); + int exitcode = 0; + 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.pointerOffset = app.pointerData - shmemMap; + app.pointerOffset = app.pointerData - (uint8_t*)shmDev.mem; 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 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) { 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]); } @@ -472,7 +475,7 @@ exit: iface->deinit(); iface->free(); fail: - os_shmemUnmap(); + ivshmemClose(&shmDev); return exitcode; } diff --git a/common/include/common/ivshmem.h b/common/include/common/ivshmem.h new file mode 100644 index 00000000..fe63f74d --- /dev/null +++ b/common/include/common/ivshmem.h @@ -0,0 +1,35 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2020 Geoffrey McRae +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 + +struct IVSHMEM +{ + unsigned int size; + void * mem; + + // internal use + void * opaque; +}; + +void ivshmemOptionsInit(); +bool ivshmemOpen(struct IVSHMEM * dev); +void ivshmemClose(struct IVSHMEM * dev); \ No newline at end of file diff --git a/common/src/platform/linux/CMakeLists.txt b/common/src/platform/linux/CMakeLists.txt index 81cd4aca..c0d2ec84 100644 --- a/common/src/platform/linux/CMakeLists.txt +++ b/common/src/platform/linux/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(lg_common_platform_code STATIC sysinfo.c thread.c event.c + ivshmem.c ) if(ENABLE_BACKTRACE) diff --git a/common/src/platform/linux/ivshmem.c b/common/src/platform/linux/ivshmem.c new file mode 100644 index 00000000..77cd59cb --- /dev/null +++ b/common/src/platform/linux/ivshmem.c @@ -0,0 +1,227 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2020 Geoffrey McRae +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 +#include +#include +#include +#include +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/common/src/platform/windows/CMakeLists.txt b/common/src/platform/windows/CMakeLists.txt index 8702d35e..09d6b878 100644 --- a/common/src/platform/windows/CMakeLists.txt +++ b/common/src/platform/windows/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) project(lg_common_platform_code LANGUAGES C) include_directories( - ${PROJECT_SOURCE_DIR}/include + ${PROJECT_TOP}/vendor/ivshmem ) add_library(lg_common_platform_code STATIC @@ -11,4 +11,5 @@ add_library(lg_common_platform_code STATIC thread.c event.c windebug.c + ivshmem.c ) diff --git a/common/src/platform/windows/ivshmem.c b/common/src/platform/windows/ivshmem.c new file mode 100644 index 00000000..f993a015 --- /dev/null +++ b/common/src/platform/windows/ivshmem.c @@ -0,0 +1,153 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2020 Geoffrey McRae +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 +#include "ivshmem.h" + +#include +#include +#include + +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); +} \ No newline at end of file