--- vdagent/pci_vdi_port.cpp | 132 +++++++++++++++++++++++++++++ vdagent/pci_vdi_port.h | 59 +++++++++++++ vdagent/vdi_port.cpp | 90 ++++++++++++++++++++ vdagent/vdi_port.h | 75 ++++++++++++++++ vdagent/virtio_vdi_port.cpp | 187 +++++++++++++++++++++++++++++++++++++++++ vdagent/virtio_vdi_port.h | 33 +++++++ vdservice/pci_vdi_port.cpp | 132 ----------------------------- vdservice/pci_vdi_port.h | 59 ------------- vdservice/vdi_port.cpp | 90 -------------------- vdservice/vdi_port.h | 75 ---------------- vdservice/virtio_vdi_port.cpp | 187 ----------------------------------------- vdservice/virtio_vdi_port.h | 33 ------- 12 files changed, 576 insertions(+), 576 deletions(-) create mode 100644 vdagent/pci_vdi_port.cpp create mode 100644 vdagent/pci_vdi_port.h create mode 100644 vdagent/vdi_port.cpp create mode 100644 vdagent/vdi_port.h create mode 100644 vdagent/virtio_vdi_port.cpp create mode 100644 vdagent/virtio_vdi_port.h delete mode 100644 vdservice/pci_vdi_port.cpp delete mode 100644 vdservice/pci_vdi_port.h delete mode 100644 vdservice/vdi_port.cpp delete mode 100644 vdservice/vdi_port.h delete mode 100644 vdservice/virtio_vdi_port.cpp delete mode 100644 vdservice/virtio_vdi_port.h diff --git a/vdagent/pci_vdi_port.cpp b/vdagent/pci_vdi_port.cpp new file mode 100644 index 0000000..7466fbc --- /dev/null +++ b/vdagent/pci_vdi_port.cpp @@ -0,0 +1,132 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdio.h" +#include "pci_vdi_port.h" +#include "vdlog.h" + +#define VDI_PORT_DEV_NAME TEXT("\\\\.\\VDIPort") +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define METHOD_BUFFERED 0 +#define FILE_ANY_ACCESS 0 + +#ifndef CTL_CODE +//With mingw, this is defined in winioctl.h +#define CTL_CODE(DeviceType, Function, Method, Access) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) +#endif + +#define FIRST_AVAIL_IO_FUNC 0x800 +#define RED_TUNNEL_CTL_FUNC FIRST_AVAIL_IO_FUNC + +#define IOCTL_RED_TUNNEL_SET_EVENT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, RED_TUNNEL_CTL_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +PCIVDIPort::PCIVDIPort() + : _handle (INVALID_HANDLE_VALUE) + , _event (NULL) +{ +} + +PCIVDIPort::~PCIVDIPort() +{ + if (_handle != INVALID_HANDLE_VALUE) { + CloseHandle(_handle); + } + if (_event) { + CloseHandle(_event); + } +} + +void PCIVDIPort::fill_events(HANDLE* handles) { + handles[PCI_VDI_PORT_EVENT] = _event; +} + +bool PCIVDIPort::init() +{ + DWORD io_ret_len; + _handle = CreateFile(VDI_PORT_DEV_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + if (_handle == INVALID_HANDLE_VALUE) { + vd_printf("CreateFile() failed: %lu", GetLastError()); + return false; + } + _event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_event == NULL) { + vd_printf("CreateEvent() failed: %lu", GetLastError()); + return false; + } + if (!DeviceIoControl(_handle, IOCTL_RED_TUNNEL_SET_EVENT, &_event, sizeof(_event), + NULL, 0, &io_ret_len, NULL)) { + vd_printf("DeviceIoControl() failed: %lu", GetLastError()); + return false; + } + return true; +} + +int PCIVDIPort::write() +{ + int size; + int n; + + if (_write.start == _write.end) { + return 0; + } + if (_write.start < _write.end) { + size = (int)(_write.end - _write.start); + } else { + size = (int)(&_write.ring[BUF_SIZE] - _write.start); + } + if (!WriteFile(_handle, _write.start, size, (LPDWORD)&n, NULL)) { + return handle_error(); + } + _write.start = _write.ring + (_write.start - _write.ring + n) % BUF_SIZE; + return n; +} + +int PCIVDIPort::read() +{ + int size; + int n; + + if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) { + return 0; + } + if (_read.start == _read.end) { + _read.start = _read.end = _read.ring; + } + if (_read.start <= _read.end) { + size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end)); + } else { + size = (int)(_read.start - _read.end - 1); + } + if (!ReadFile(_handle, _read.end, size, (LPDWORD)&n, NULL)) { + return handle_error(); + } + _read.end = _read.ring + (_read.end - _read.ring + n) % BUF_SIZE; + return n; +} + +bool PCIVDIPort::handle_event(int event) +{ + // do nothing - the event merely serves to wake us up, then we call read/write + // at VDService::execute start of while(_running) loop. + return true; +} diff --git a/vdagent/pci_vdi_port.h b/vdagent/pci_vdi_port.h new file mode 100644 index 0000000..fcc76dc --- /dev/null +++ b/vdagent/pci_vdi_port.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _H_PCI_VDI_PORT +#define _H_PCI_VDI_PORT + +#include "vdi_port.h" + +#define BUF_READ (1 << 0) +#define BUF_WRITE (1 << 1) +#define BUF_ALL (BUF_READ | BUF_WRITE) + +enum { + PCI_VDI_PORT_EVENT = 0, + PCI_VDI_PORT_EVENT_COUNT +}; + +class PCIVDIPort : public VDIPort { +public: + PCIVDIPort(); + ~PCIVDIPort(); + virtual bool init(); + virtual const char *name() { + return "PCIVDIPort"; + } + virtual int write(); + virtual int read(); + virtual unsigned get_num_events() { return PCI_VDI_PORT_EVENT_COUNT; } + virtual void fill_events(HANDLE* handles); + virtual bool handle_event(int event); + +private: + HANDLE _handle; + HANDLE _event; +}; + +// Ring notes: +// _end is one after the end of data +// _start==_end means empty ring +// _start-1==_end (modulo) means full ring +// _start-1 is never used +// ring_write & read on right side of the ring (update _end) +// ring_read & write from left (update _start) + +#endif diff --git a/vdagent/vdi_port.cpp b/vdagent/vdi_port.cpp new file mode 100644 index 0000000..bd5ea05 --- /dev/null +++ b/vdagent/vdi_port.cpp @@ -0,0 +1,90 @@ +#include "vdlog.h" +#include "vdi_port.h" + +VDIPort::VDIPort() +{ + ZeroMemory(&_write, offsetof(VDIPortBuffer, ring)); + _write.start = _write.end = _write.ring; + ZeroMemory(&_read, offsetof(VDIPortBuffer, ring)); + _read.start = _read.end = _read.ring; +} + +size_t VDIPort::read_ring_size() +{ + return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE; +} + +size_t VDIPort::write_ring_free_space() +{ + return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE; +} + +size_t VDIPort::ring_write(const void* buf, size_t size) +{ + size_t free_size = (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE; + size_t n; + + if (size > free_size) { + size = free_size; + } + if (_write.end < _write.start) { + memcpy(_write.end, buf, size); + } else { + n = MIN(size, (size_t)(&_write.ring[BUF_SIZE] - _write.end)); + memcpy(_write.end, buf, n); + if (size > n) { + memcpy(_write.ring, (uint8_t*)buf + n, size - n); + } + } + _write.end = _write.ring + (_write.end - _write.ring + size) % BUF_SIZE; + return size; +} + +size_t VDIPort::read_ring_continuous_remaining_size() +{ + DWORD size; + + if (_read.start <= _read.end) { + size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end)); + } else { + size = (DWORD)(_read.start - _read.end - 1); + } + return size; +} + +size_t VDIPort::ring_read(void* buf, size_t size) +{ + size_t n; + size_t m = 0; + + if (_read.start == _read.end) { + return 0; + } + if (_read.start < _read.end) { + n = MIN(size, (size_t)(_read.end - _read.start)); + memcpy(buf, _read.start, n); + } else { + n = MIN(size, (size_t)(&_read.ring[BUF_SIZE] - _read.start)); + memcpy(buf, _read.start, n); + if (size > n) { + m = MIN(size - n, (size_t)(_read.end - _read.ring)); + memcpy((uint8_t*)buf + n, _read.ring, m); + } + } + _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE; + return n + m; +} + +int VDIPort::handle_error() +{ + switch (GetLastError()) { + case ERROR_CONNECTION_INVALID: + vd_printf("port reset"); + _write.start = _write.end = _write.ring; + _read.start = _read.end = _read.ring; + return VDI_PORT_RESET; + default: + vd_printf("port io failed: %lu", GetLastError()); + return VDI_PORT_ERROR; + } +} diff --git a/vdagent/vdi_port.h b/vdagent/vdi_port.h new file mode 100644 index 0000000..a0fb20e --- /dev/null +++ b/vdagent/vdi_port.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _H_VDI_PORT +#define _H_VDI_PORT + +#include <windows.h> +#include <stdint.h> + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +#define BUF_SIZE (1024 * 1024) + +#define VDI_PORT_BLOCKED 0 +#define VDI_PORT_RESET -1 +#define VDI_PORT_ERROR -2 + +// Ring notes: +// _end is one after the end of data +// _start==_end means empty ring +// _start-1==_end (modulo) means full ring +// _start-1 is never used +// ring_write & read on right side of the ring (update _end) +// ring_read & write from left (update _start) + +typedef struct VDIPortBuffer { + OVERLAPPED overlap; + uint8_t* start; + uint8_t* end; + bool pending; + int bytes; + uint8_t ring[BUF_SIZE]; +} VDIPortBuffer; + +class VDIPort { +public: + VDIPort(); + virtual ~VDIPort() {} + + size_t ring_write(const void* buf, size_t size); + size_t write_ring_free_space(); + size_t ring_read(void* buf, size_t size); + size_t read_ring_size(); + size_t read_ring_continuous_remaining_size(); + + virtual const char *name() = 0; + virtual bool init() = 0; + virtual unsigned get_num_events() = 0; + virtual void fill_events(HANDLE* handles) = 0; + virtual bool handle_event(int event) = 0; + virtual int write() = 0; + virtual int read() = 0; + +protected: + int handle_error(); + + VDIPortBuffer _write; + VDIPortBuffer _read; +}; + +#endif diff --git a/vdagent/virtio_vdi_port.cpp b/vdagent/virtio_vdi_port.cpp new file mode 100644 index 0000000..be5568a --- /dev/null +++ b/vdagent/virtio_vdi_port.cpp @@ -0,0 +1,187 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdio.h" +#include "virtio_vdi_port.h" +#include "vdlog.h" + +#define VIOSERIAL_PORT_PATH L"\\\\.\\Global\\com.redhat.spice.0" + +// Current limitation of virtio-serial windows driver (RHBZ 617000) +#define VIOSERIAL_PORT_MAX_WRITE_BYTES 2048 + +VirtioVDIPort* VirtioVDIPort::_singleton; + +VirtioVDIPort::VirtioVDIPort() + : VDIPort() + , _handle (INVALID_HANDLE_VALUE) +{ + _singleton = this; +} + +VirtioVDIPort::~VirtioVDIPort() +{ + if (_handle != INVALID_HANDLE_VALUE) { + CloseHandle(_handle); + } + if (_read.overlap.hEvent) { + CloseHandle(_read.overlap.hEvent); + } + if (_write.overlap.hEvent) { + CloseHandle(_write.overlap.hEvent); + } +} + +void VirtioVDIPort::fill_events(HANDLE* handles) { + handles[VIRTIO_VDI_PORT_EVENT_WRITE] = _write.overlap.hEvent; + handles[VIRTIO_VDI_PORT_EVENT_READ] = _read.overlap.hEvent; +} + +bool VirtioVDIPort::handle_event(int event) { + bool ret; + + switch (event) { + case VIRTIO_VDI_PORT_EVENT_WRITE: + ret = write_completion(); + break; + case VIRTIO_VDI_PORT_EVENT_READ: + ret = read_completion(); + break; + default: + vd_printf("ERROR: unexpected event %d", event); + ret = false; + } + return ret; +} + +bool VirtioVDIPort::init() +{ + _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (_handle == INVALID_HANDLE_VALUE) { + vd_printf("CreateFile() %ls failed: %lu", VIOSERIAL_PORT_PATH, GetLastError()); + return false; + } + _write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_write.overlap.hEvent == NULL) { + vd_printf("CreateEvent() failed: %lu", GetLastError()); + return false; + } + _read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_read.overlap.hEvent == NULL) { + vd_printf("CreateEvent() failed: %lu", GetLastError()); + return false; + } + return true; +} + +int VirtioVDIPort::write() +{ + int size; + int ret; + + //FIXME: return VDI_PORT_NO_DATA + if (_write.start == _write.end) { + return 0; + } + if (!_write.pending) { + if (_write.start < _write.end) { + size = (int)(_write.end - _write.start); + } else { + size = (int)(&_write.ring[BUF_SIZE] - _write.start); + } + size = MIN(size, VIOSERIAL_PORT_MAX_WRITE_BYTES); + _write.pending = true; + if (WriteFile(_handle, _write.start, size, NULL, &_write.overlap)) { + write_completion(); + } if (GetLastError() != ERROR_IO_PENDING) { + return handle_error(); + } + } + ret = _write.bytes; + _write.bytes = 0; + return ret; +} + +bool VirtioVDIPort::write_completion() +{ + DWORD bytes; + + if (!_write.pending) { + return true; + } + if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) { + vd_printf("GetOverlappedResult failed: %lu", GetLastError()); + return false; + } + _write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE; + _write.bytes = bytes; + _write.pending = false; + return true; +} + +int VirtioVDIPort::read() +{ + int size; + int ret; + + if (!_read.pending) { + //FIXME: read_ring_continuous_remaining_size? return VDI_PORT_BUFFER_FULL + if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) { + vd_printf("DEBUG: buffer full"); + return 0; + } + if (_read.start == _read.end) { + _read.start = _read.end = _read.ring; + } + if (_read.start <= _read.end) { + size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end)); + } else { + size = (int)(_read.start - _read.end - 1); + } + _read.pending = true; + if (ReadFile(_handle, _read.end, size, NULL, &_read.overlap)) { + read_completion(); + } else if (GetLastError() != ERROR_IO_PENDING) { + return handle_error(); + } + } + ret = _read.bytes; + _read.bytes = 0; + return ret; +} + +bool VirtioVDIPort::read_completion() +{ + DWORD bytes; + + if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE)) { + DWORD err = GetLastError(); + + if (err == ERROR_OPERATION_ABORTED || err == ERROR_NO_SYSTEM_RESOURCES) { + _read.pending = false; + return true; + } else if (err != ERROR_MORE_DATA) { + vd_printf("GetOverlappedResult failed: %lu", err); + return false; + } + } + _read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE; + _read.bytes = bytes; + _read.pending = false; + return true; +} diff --git a/vdagent/virtio_vdi_port.h b/vdagent/virtio_vdi_port.h new file mode 100644 index 0000000..d72edf4 --- /dev/null +++ b/vdagent/virtio_vdi_port.h @@ -0,0 +1,33 @@ +#ifndef _H_VIRTIO_VDI_PORT +#define _H_VIRTIO_VDI_PORT + +#include "vdi_port.h" + +enum { + VIRTIO_VDI_PORT_EVENT_WRITE=0, + VIRTIO_VDI_PORT_EVENT_READ, + VIRTIO_VDI_PORT_EVENT_COUNT +}; + +class VirtioVDIPort : public VDIPort { +public: + VirtioVDIPort(); + ~VirtioVDIPort(); + virtual const char *name() { return "VirtioVDIPort"; } + virtual bool init(); + virtual unsigned get_num_events() { return VIRTIO_VDI_PORT_EVENT_COUNT; } + virtual void fill_events(HANDLE* handles); + virtual bool handle_event(int event); + virtual int write(); + virtual int read(); + +private: + bool write_completion(); + bool read_completion(); + +private: + static VirtioVDIPort* _singleton; + HANDLE _handle; +}; + +#endif //_H_VIRTIO_VDI_PORT diff --git a/vdservice/pci_vdi_port.cpp b/vdservice/pci_vdi_port.cpp deleted file mode 100644 index 7466fbc..0000000 --- a/vdservice/pci_vdi_port.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "stdio.h" -#include "pci_vdi_port.h" -#include "vdlog.h" - -#define VDI_PORT_DEV_NAME TEXT("\\\\.\\VDIPort") -#define FILE_DEVICE_UNKNOWN 0x00000022 -#define METHOD_BUFFERED 0 -#define FILE_ANY_ACCESS 0 - -#ifndef CTL_CODE -//With mingw, this is defined in winioctl.h -#define CTL_CODE(DeviceType, Function, Method, Access) ( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) -#endif - -#define FIRST_AVAIL_IO_FUNC 0x800 -#define RED_TUNNEL_CTL_FUNC FIRST_AVAIL_IO_FUNC - -#define IOCTL_RED_TUNNEL_SET_EVENT \ - CTL_CODE(FILE_DEVICE_UNKNOWN, RED_TUNNEL_CTL_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -PCIVDIPort::PCIVDIPort() - : _handle (INVALID_HANDLE_VALUE) - , _event (NULL) -{ -} - -PCIVDIPort::~PCIVDIPort() -{ - if (_handle != INVALID_HANDLE_VALUE) { - CloseHandle(_handle); - } - if (_event) { - CloseHandle(_event); - } -} - -void PCIVDIPort::fill_events(HANDLE* handles) { - handles[PCI_VDI_PORT_EVENT] = _event; -} - -bool PCIVDIPort::init() -{ - DWORD io_ret_len; - _handle = CreateFile(VDI_PORT_DEV_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, NULL); - if (_handle == INVALID_HANDLE_VALUE) { - vd_printf("CreateFile() failed: %lu", GetLastError()); - return false; - } - _event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_event == NULL) { - vd_printf("CreateEvent() failed: %lu", GetLastError()); - return false; - } - if (!DeviceIoControl(_handle, IOCTL_RED_TUNNEL_SET_EVENT, &_event, sizeof(_event), - NULL, 0, &io_ret_len, NULL)) { - vd_printf("DeviceIoControl() failed: %lu", GetLastError()); - return false; - } - return true; -} - -int PCIVDIPort::write() -{ - int size; - int n; - - if (_write.start == _write.end) { - return 0; - } - if (_write.start < _write.end) { - size = (int)(_write.end - _write.start); - } else { - size = (int)(&_write.ring[BUF_SIZE] - _write.start); - } - if (!WriteFile(_handle, _write.start, size, (LPDWORD)&n, NULL)) { - return handle_error(); - } - _write.start = _write.ring + (_write.start - _write.ring + n) % BUF_SIZE; - return n; -} - -int PCIVDIPort::read() -{ - int size; - int n; - - if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) { - return 0; - } - if (_read.start == _read.end) { - _read.start = _read.end = _read.ring; - } - if (_read.start <= _read.end) { - size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end)); - } else { - size = (int)(_read.start - _read.end - 1); - } - if (!ReadFile(_handle, _read.end, size, (LPDWORD)&n, NULL)) { - return handle_error(); - } - _read.end = _read.ring + (_read.end - _read.ring + n) % BUF_SIZE; - return n; -} - -bool PCIVDIPort::handle_event(int event) -{ - // do nothing - the event merely serves to wake us up, then we call read/write - // at VDService::execute start of while(_running) loop. - return true; -} diff --git a/vdservice/pci_vdi_port.h b/vdservice/pci_vdi_port.h deleted file mode 100644 index fcc76dc..0000000 --- a/vdservice/pci_vdi_port.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - 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, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _H_PCI_VDI_PORT -#define _H_PCI_VDI_PORT - -#include "vdi_port.h" - -#define BUF_READ (1 << 0) -#define BUF_WRITE (1 << 1) -#define BUF_ALL (BUF_READ | BUF_WRITE) - -enum { - PCI_VDI_PORT_EVENT = 0, - PCI_VDI_PORT_EVENT_COUNT -}; - -class PCIVDIPort : public VDIPort { -public: - PCIVDIPort(); - ~PCIVDIPort(); - virtual bool init(); - virtual const char *name() { - return "PCIVDIPort"; - } - virtual int write(); - virtual int read(); - virtual unsigned get_num_events() { return PCI_VDI_PORT_EVENT_COUNT; } - virtual void fill_events(HANDLE* handles); - virtual bool handle_event(int event); - -private: - HANDLE _handle; - HANDLE _event; -}; - -// Ring notes: -// _end is one after the end of data -// _start==_end means empty ring -// _start-1==_end (modulo) means full ring -// _start-1 is never used -// ring_write & read on right side of the ring (update _end) -// ring_read & write from left (update _start) - -#endif diff --git a/vdservice/vdi_port.cpp b/vdservice/vdi_port.cpp deleted file mode 100644 index bd5ea05..0000000 --- a/vdservice/vdi_port.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "vdlog.h" -#include "vdi_port.h" - -VDIPort::VDIPort() -{ - ZeroMemory(&_write, offsetof(VDIPortBuffer, ring)); - _write.start = _write.end = _write.ring; - ZeroMemory(&_read, offsetof(VDIPortBuffer, ring)); - _read.start = _read.end = _read.ring; -} - -size_t VDIPort::read_ring_size() -{ - return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE; -} - -size_t VDIPort::write_ring_free_space() -{ - return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE; -} - -size_t VDIPort::ring_write(const void* buf, size_t size) -{ - size_t free_size = (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE; - size_t n; - - if (size > free_size) { - size = free_size; - } - if (_write.end < _write.start) { - memcpy(_write.end, buf, size); - } else { - n = MIN(size, (size_t)(&_write.ring[BUF_SIZE] - _write.end)); - memcpy(_write.end, buf, n); - if (size > n) { - memcpy(_write.ring, (uint8_t*)buf + n, size - n); - } - } - _write.end = _write.ring + (_write.end - _write.ring + size) % BUF_SIZE; - return size; -} - -size_t VDIPort::read_ring_continuous_remaining_size() -{ - DWORD size; - - if (_read.start <= _read.end) { - size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end)); - } else { - size = (DWORD)(_read.start - _read.end - 1); - } - return size; -} - -size_t VDIPort::ring_read(void* buf, size_t size) -{ - size_t n; - size_t m = 0; - - if (_read.start == _read.end) { - return 0; - } - if (_read.start < _read.end) { - n = MIN(size, (size_t)(_read.end - _read.start)); - memcpy(buf, _read.start, n); - } else { - n = MIN(size, (size_t)(&_read.ring[BUF_SIZE] - _read.start)); - memcpy(buf, _read.start, n); - if (size > n) { - m = MIN(size - n, (size_t)(_read.end - _read.ring)); - memcpy((uint8_t*)buf + n, _read.ring, m); - } - } - _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE; - return n + m; -} - -int VDIPort::handle_error() -{ - switch (GetLastError()) { - case ERROR_CONNECTION_INVALID: - vd_printf("port reset"); - _write.start = _write.end = _write.ring; - _read.start = _read.end = _read.ring; - return VDI_PORT_RESET; - default: - vd_printf("port io failed: %lu", GetLastError()); - return VDI_PORT_ERROR; - } -} diff --git a/vdservice/vdi_port.h b/vdservice/vdi_port.h deleted file mode 100644 index a0fb20e..0000000 --- a/vdservice/vdi_port.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - 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, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _H_VDI_PORT -#define _H_VDI_PORT - -#include <windows.h> -#include <stdint.h> - -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -#define BUF_SIZE (1024 * 1024) - -#define VDI_PORT_BLOCKED 0 -#define VDI_PORT_RESET -1 -#define VDI_PORT_ERROR -2 - -// Ring notes: -// _end is one after the end of data -// _start==_end means empty ring -// _start-1==_end (modulo) means full ring -// _start-1 is never used -// ring_write & read on right side of the ring (update _end) -// ring_read & write from left (update _start) - -typedef struct VDIPortBuffer { - OVERLAPPED overlap; - uint8_t* start; - uint8_t* end; - bool pending; - int bytes; - uint8_t ring[BUF_SIZE]; -} VDIPortBuffer; - -class VDIPort { -public: - VDIPort(); - virtual ~VDIPort() {} - - size_t ring_write(const void* buf, size_t size); - size_t write_ring_free_space(); - size_t ring_read(void* buf, size_t size); - size_t read_ring_size(); - size_t read_ring_continuous_remaining_size(); - - virtual const char *name() = 0; - virtual bool init() = 0; - virtual unsigned get_num_events() = 0; - virtual void fill_events(HANDLE* handles) = 0; - virtual bool handle_event(int event) = 0; - virtual int write() = 0; - virtual int read() = 0; - -protected: - int handle_error(); - - VDIPortBuffer _write; - VDIPortBuffer _read; -}; - -#endif diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp deleted file mode 100644 index be5568a..0000000 --- a/vdservice/virtio_vdi_port.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "stdio.h" -#include "virtio_vdi_port.h" -#include "vdlog.h" - -#define VIOSERIAL_PORT_PATH L"\\\\.\\Global\\com.redhat.spice.0" - -// Current limitation of virtio-serial windows driver (RHBZ 617000) -#define VIOSERIAL_PORT_MAX_WRITE_BYTES 2048 - -VirtioVDIPort* VirtioVDIPort::_singleton; - -VirtioVDIPort::VirtioVDIPort() - : VDIPort() - , _handle (INVALID_HANDLE_VALUE) -{ - _singleton = this; -} - -VirtioVDIPort::~VirtioVDIPort() -{ - if (_handle != INVALID_HANDLE_VALUE) { - CloseHandle(_handle); - } - if (_read.overlap.hEvent) { - CloseHandle(_read.overlap.hEvent); - } - if (_write.overlap.hEvent) { - CloseHandle(_write.overlap.hEvent); - } -} - -void VirtioVDIPort::fill_events(HANDLE* handles) { - handles[VIRTIO_VDI_PORT_EVENT_WRITE] = _write.overlap.hEvent; - handles[VIRTIO_VDI_PORT_EVENT_READ] = _read.overlap.hEvent; -} - -bool VirtioVDIPort::handle_event(int event) { - bool ret; - - switch (event) { - case VIRTIO_VDI_PORT_EVENT_WRITE: - ret = write_completion(); - break; - case VIRTIO_VDI_PORT_EVENT_READ: - ret = read_completion(); - break; - default: - vd_printf("ERROR: unexpected event %d", event); - ret = false; - } - return ret; -} - -bool VirtioVDIPort::init() -{ - _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (_handle == INVALID_HANDLE_VALUE) { - vd_printf("CreateFile() %ls failed: %lu", VIOSERIAL_PORT_PATH, GetLastError()); - return false; - } - _write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_write.overlap.hEvent == NULL) { - vd_printf("CreateEvent() failed: %lu", GetLastError()); - return false; - } - _read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_read.overlap.hEvent == NULL) { - vd_printf("CreateEvent() failed: %lu", GetLastError()); - return false; - } - return true; -} - -int VirtioVDIPort::write() -{ - int size; - int ret; - - //FIXME: return VDI_PORT_NO_DATA - if (_write.start == _write.end) { - return 0; - } - if (!_write.pending) { - if (_write.start < _write.end) { - size = (int)(_write.end - _write.start); - } else { - size = (int)(&_write.ring[BUF_SIZE] - _write.start); - } - size = MIN(size, VIOSERIAL_PORT_MAX_WRITE_BYTES); - _write.pending = true; - if (WriteFile(_handle, _write.start, size, NULL, &_write.overlap)) { - write_completion(); - } if (GetLastError() != ERROR_IO_PENDING) { - return handle_error(); - } - } - ret = _write.bytes; - _write.bytes = 0; - return ret; -} - -bool VirtioVDIPort::write_completion() -{ - DWORD bytes; - - if (!_write.pending) { - return true; - } - if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) { - vd_printf("GetOverlappedResult failed: %lu", GetLastError()); - return false; - } - _write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE; - _write.bytes = bytes; - _write.pending = false; - return true; -} - -int VirtioVDIPort::read() -{ - int size; - int ret; - - if (!_read.pending) { - //FIXME: read_ring_continuous_remaining_size? return VDI_PORT_BUFFER_FULL - if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) { - vd_printf("DEBUG: buffer full"); - return 0; - } - if (_read.start == _read.end) { - _read.start = _read.end = _read.ring; - } - if (_read.start <= _read.end) { - size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end)); - } else { - size = (int)(_read.start - _read.end - 1); - } - _read.pending = true; - if (ReadFile(_handle, _read.end, size, NULL, &_read.overlap)) { - read_completion(); - } else if (GetLastError() != ERROR_IO_PENDING) { - return handle_error(); - } - } - ret = _read.bytes; - _read.bytes = 0; - return ret; -} - -bool VirtioVDIPort::read_completion() -{ - DWORD bytes; - - if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE)) { - DWORD err = GetLastError(); - - if (err == ERROR_OPERATION_ABORTED || err == ERROR_NO_SYSTEM_RESOURCES) { - _read.pending = false; - return true; - } else if (err != ERROR_MORE_DATA) { - vd_printf("GetOverlappedResult failed: %lu", err); - return false; - } - } - _read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE; - _read.bytes = bytes; - _read.pending = false; - return true; -} diff --git a/vdservice/virtio_vdi_port.h b/vdservice/virtio_vdi_port.h deleted file mode 100644 index d72edf4..0000000 --- a/vdservice/virtio_vdi_port.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _H_VIRTIO_VDI_PORT -#define _H_VIRTIO_VDI_PORT - -#include "vdi_port.h" - -enum { - VIRTIO_VDI_PORT_EVENT_WRITE=0, - VIRTIO_VDI_PORT_EVENT_READ, - VIRTIO_VDI_PORT_EVENT_COUNT -}; - -class VirtioVDIPort : public VDIPort { -public: - VirtioVDIPort(); - ~VirtioVDIPort(); - virtual const char *name() { return "VirtioVDIPort"; } - virtual bool init(); - virtual unsigned get_num_events() { return VIRTIO_VDI_PORT_EVENT_COUNT; } - virtual void fill_events(HANDLE* handles); - virtual bool handle_event(int event); - virtual int write(); - virtual int read(); - -private: - bool write_completion(); - bool read_completion(); - -private: - static VirtioVDIPort* _singleton; - HANDLE _handle; -}; - -#endif //_H_VIRTIO_VDI_PORT -- 1.7.4.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel