diff options
author | Alon Levy <alevy@redhat.com> | 2010-12-30 13:48:52 +0200 |
---|---|---|
committer | Arnon Gilboa <agilboa@agilboa.usersys.redhat.com> | 2011-01-11 17:18:47 +0200 |
commit | 0f92cbea70efc5366465fdb52e44fd4c727b45ac (patch) | |
tree | 70d352b7bc9e551b15713fc7b43ddf3cd8cbe508 /vdservice | |
parent | 935330f996535f7d59963978fc8fdb17bf1d75cb (diff) |
vdi_port refactor: introduce old pci_vdi_port
This patch is a little dirty due to EOL convertion to windows format.
+ add pci_vdi_port with PCIVDIPort taken from last commit before
changing to virtio-serial (a17ccbf323768c3cb977f0f062366ba7cf7f19db)
+ move handle_error to VDIPort (identical in VIRTIOVDIPort and PCIVDIPort)
+ make VDService create first a virtio, then init, the pci, then init,
stopping when the first init succeeds, and reporting to log which was
created.
Diffstat (limited to 'vdservice')
-rw-r--r-- | vdservice/pci_vdi_port.cpp | 124 | ||||
-rw-r--r-- | vdservice/pci_vdi_port.h | 54 | ||||
-rw-r--r-- | vdservice/vdi_port.cpp | 150 | ||||
-rw-r--r-- | vdservice/vdi_port.h | 3 | ||||
-rw-r--r-- | vdservice/vdservice.cpp | 30 | ||||
-rw-r--r-- | vdservice/vdservice.vcproj | 16 | ||||
-rw-r--r-- | vdservice/virtio_vdi_port.cpp | 15 |
7 files changed, 306 insertions, 86 deletions
diff --git a/vdservice/pci_vdi_port.cpp b/vdservice/pci_vdi_port.cpp new file mode 100644 index 0000000..3baefd9 --- /dev/null +++ b/vdservice/pci_vdi_port.cpp @@ -0,0 +1,124 @@ +/* + 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 + +#define CTL_CODE(DeviceType, Function, Method, Access) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +#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); + } +} + +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: %u", GetLastError()); + return false; + } + _event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_event == NULL) { + vd_printf("CreateEvent() failed: %u", GetLastError()); + return false; + } + if (!DeviceIoControl(_handle, IOCTL_RED_TUNNEL_SET_EVENT, &_event, sizeof(_event), + NULL, 0, &io_ret_len, NULL)) { + vd_printf("DeviceIoControl() failed: %u", 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; +} + +void 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. +} diff --git a/vdservice/pci_vdi_port.h b/vdservice/pci_vdi_port.h new file mode 100644 index 0000000..40a0589 --- /dev/null +++ b/vdservice/pci_vdi_port.h @@ -0,0 +1,54 @@ +/* + 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) + +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 1; }
+ virtual void fill_events(HANDLE *handle) { + handle[0] = _event; + } + virtual void 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 index f9fbcdf..9638dc0 100644 --- a/vdservice/vdi_port.cpp +++ b/vdservice/vdi_port.cpp @@ -1,76 +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; -} + 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;
+}
-size_t VDIPort::ring_read(void* buf, size_t size) +int VDIPort::handle_error() { - 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); - } + 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: %u", GetLastError()); + return VDI_PORT_ERROR; } - _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE; - return n + m; } diff --git a/vdservice/vdi_port.h b/vdservice/vdi_port.h index cc4cb53..63b04bb 100644 --- a/vdservice/vdi_port.h +++ b/vdservice/vdi_port.h @@ -49,6 +49,7 @@ public: 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 *handle) = 0; @@ -57,6 +58,8 @@ public: virtual int read() = 0; protected: + int handle_error(); + VDIPortBuffer _write; VDIPortBuffer _read; }; diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp index 7b0cadb..175587c 100644 --- a/vdservice/vdservice.cpp +++ b/vdservice/vdservice.cpp @@ -23,6 +23,7 @@ #include <tlhelp32.h> #include "vdcommon.h" #include "virtio_vdi_port.h" +#include "pci_vdi_port.h" //#define DEBUG_VDSERVICE @@ -401,6 +402,16 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[]) #endif //DEBUG_VDSERVICE } +VDIPort *create_virtio_vdi_port() +{ + return new VirtioVDIPort(); +} + +VDIPort *create_pci_vdi_port() +{ + return new PCIVDIPort(); +} + bool VDService::execute() { SECURITY_ATTRIBUTES sec_attr; @@ -434,12 +445,25 @@ bool VDService::execute() CloseHandle(pipe); return false; } - _vdi_port = new VirtioVDIPort(); - if (!_vdi_port->init()) { - delete _vdi_port; + + bool init = false; + { + VDIPort* (*creators[])(void) = { create_virtio_vdi_port, create_pci_vdi_port }; + for (int i = 0 ; i < sizeof(creators)/sizeof(creators[0]); ++i) { + _vdi_port = creators[i](); + init = _vdi_port->init(); + if (init) { + break; + } + delete _vdi_port; + } + } + if (!init) { + vd_printf("Failed to create VDIPort instance"); CloseHandle(pipe); return false; } + vd_printf("created %s", _vdi_port->name()); _events_count = VD_STATIC_EVENTS_COUNT + _vdi_port->get_num_events() + 1 /*for agent*/; _events = new HANDLE[_events_count]; _events_vdi_port_base = VD_STATIC_EVENTS_COUNT; diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj index 32ec7c8..bbb1b75 100644 --- a/vdservice/vdservice.vcproj +++ b/vdservice/vdservice.vcproj @@ -335,6 +335,10 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
+ RelativePath=".\pci_vdi_port.h"
+ >
+ </File>
+ <File
RelativePath=".\resource.h"
>
</File>
@@ -350,6 +354,10 @@ RelativePath="..\common\vdlog.h"
>
</File>
+ <File
+ RelativePath=".\virtio_vdi_port.h"
+ >
+ </File>
</Filter>
<Filter
Name="Resource Files"
@@ -367,6 +375,10 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
+ RelativePath=".\pci_vdi_port.cpp"
+ >
+ </File>
+ <File
RelativePath=".\vdi_port.cpp"
>
</File>
@@ -378,6 +390,10 @@ RelativePath=".\vdservice.cpp"
>
</File>
+ <File
+ RelativePath=".\virtio_vdi_port.cpp"
+ >
+ </File>
</Filter>
</Files>
<Globals>
diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp index 278a88b..4f24a26 100644 --- a/vdservice/virtio_vdi_port.cpp +++ b/vdservice/virtio_vdi_port.cpp @@ -48,7 +48,6 @@ VirtioVDIPort::~VirtioVDIPort() bool VirtioVDIPort::init() { - vd_printf("creating VirtioVDIPort"); _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (_handle == INVALID_HANDLE_VALUE) { @@ -156,17 +155,3 @@ void VirtioVDIPort::read_completion() _read.bytes = bytes; _read.pending = false; } - -int VirtioVDIPort::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: %u", GetLastError()); - return VDI_PORT_ERROR; - } -} |