kvm-guest-drivers-windows
208 строк · 7.0 Кб
1/*
2* Implementation of virtio_system_ops VirtioLib callbacks
3*
4* Copyright (c) 2016-2017 Red Hat, Inc.
5*
6* Author(s):
7* Ladi Prosek <lprosek@redhat.com>
8*
9* Redistribution and use in source and binary forms, with or without
10* modification, are permitted provided that the following conditions
11* are met :
12* 1. Redistributions of source code must retain the above copyright
13* notice, this list of conditions and the following disclaimer.
14* 2. Redistributions in binary form must reproduce the above copyright
15* notice, this list of conditions and the following disclaimer in the
16* documentation and / or other materials provided with the distribution.
17* 3. Neither the names of the copyright holders nor the names of their contributors
18* may be used to endorse or promote products derived from this software
19* without specific prior written permission.
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30* SUCH DAMAGE.
31*/
32#include "osdep.h"
33#include "virtio_pci.h"
34#include "VirtIOWdf.h"
35#include "private.h"
36
37static void *mem_alloc_contiguous_pages(void *context, size_t size)
38{
39PVIRTIO_WDF_DRIVER pWdfDriver = context;
40
41return VirtIOWdfDeviceAllocDmaMemory(&pWdfDriver->VIODevice, size, 0);
42}
43
44static void mem_free_contiguous_pages(void *context, void *virt)
45{
46PVIRTIO_WDF_DRIVER pWdfDriver = context;
47
48VirtIOWdfDeviceFreeDmaMemory(&pWdfDriver->VIODevice, virt);
49}
50
51static ULONGLONG mem_get_physical_address(void *context, void *virt)
52{
53PVIRTIO_WDF_DRIVER pWdfDriver = context;
54PHYSICAL_ADDRESS pa;
55
56pa = VirtIOWdfDeviceGetPhysicalAddress(&pWdfDriver->VIODevice, virt);
57
58if (!pa.QuadPart) {
59DPrintf(0, "%s WARNING: got zero physical address\n", __FUNCTION__);
60}
61return pa.QuadPart;
62}
63
64static void *mem_alloc_nonpaged_block(void *context, size_t size)
65{
66PVIRTIO_WDF_DRIVER pWdfDriver = (PVIRTIO_WDF_DRIVER)context;
67
68PVOID addr = ExAllocatePoolUninitialized(
69NonPagedPool,
70size,
71pWdfDriver->MemoryTag);
72if (addr) {
73RtlZeroMemory(addr, size);
74}
75return addr;
76}
77
78static void mem_free_nonpaged_block(void *context, void *addr)
79{
80PVIRTIO_WDF_DRIVER pWdfDriver = (PVIRTIO_WDF_DRIVER)context;
81
82ExFreePoolWithTag(
83addr,
84pWdfDriver->MemoryTag);
85}
86
87static int pci_read_config_byte(void *context, int where, u8 *bVal)
88{
89return PCIReadConfig((PVIRTIO_WDF_DRIVER)context, where, bVal, sizeof(*bVal));
90}
91
92static int pci_read_config_word(void *context, int where, u16 *wVal)
93{
94return PCIReadConfig((PVIRTIO_WDF_DRIVER)context, where, wVal, sizeof(*wVal));
95}
96
97static int pci_read_config_dword(void *context, int where, u32 *dwVal)
98{
99return PCIReadConfig((PVIRTIO_WDF_DRIVER)context, where, dwVal, sizeof(*dwVal));
100}
101
102static PVIRTIO_WDF_BAR find_bar(void *context, int bar)
103{
104PVIRTIO_WDF_DRIVER pWdfDriver = (PVIRTIO_WDF_DRIVER)context;
105PSINGLE_LIST_ENTRY iter = &pWdfDriver->PCIBars;
106
107while (iter->Next != NULL) {
108PVIRTIO_WDF_BAR pBar = CONTAINING_RECORD(iter->Next, VIRTIO_WDF_BAR, ListEntry);
109if (pBar->iBar == bar) {
110return pBar;
111}
112iter = iter->Next;
113}
114return NULL;
115}
116
117static size_t pci_get_resource_len(void *context, int bar)
118{
119PVIRTIO_WDF_BAR pBar = find_bar(context, bar);
120return (pBar ? pBar->uLength : 0);
121}
122
123static void *pci_map_address_range(void *context, int bar, size_t offset, size_t maxlen)
124{
125PVIRTIO_WDF_BAR pBar = find_bar(context, bar);
126if (pBar) {
127if (pBar->pBase == NULL) {
128ASSERT(!pBar->bPortSpace);
129#if defined(NTDDI_WINTHRESHOLD) && (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
130pBar->pBase = MmMapIoSpaceEx(
131pBar->BasePA,
132pBar->uLength,
133PAGE_READWRITE | PAGE_NOCACHE);
134#else
135pBar->pBase = MmMapIoSpace(pBar->BasePA, pBar->uLength, MmNonCached);
136#endif
137}
138if (pBar->pBase != NULL && offset < pBar->uLength) {
139return (char *)pBar->pBase + offset;
140}
141}
142return NULL;
143}
144
145static u16 vdev_get_msix_vector(void *context, int queue)
146{
147PVIRTIO_WDF_DRIVER pWdfDriver = (PVIRTIO_WDF_DRIVER)context;
148u16 vector = VIRTIO_MSI_NO_VECTOR;
149
150if (queue >= 0) {
151/* queue interrupt */
152if (pWdfDriver->pQueueParams != NULL) {
153vector = PCIGetMSIInterruptVector(pWdfDriver->pQueueParams[queue].Interrupt);
154}
155}
156else {
157/* on-device-config-change interrupt */
158vector = PCIGetMSIInterruptVector(pWdfDriver->ConfigInterrupt);
159}
160
161return vector;
162}
163
164static void vdev_sleep(void *context, unsigned int msecs)
165{
166NTSTATUS status = STATUS_UNSUCCESSFUL;
167
168UNREFERENCED_PARAMETER(context);
169
170if (KeGetCurrentIrql() <= APC_LEVEL) {
171LARGE_INTEGER delay;
172delay.QuadPart = Int32x32To64(msecs, -10000);
173status = KeDelayExecutionThread(KernelMode, FALSE, &delay);
174}
175
176if (!NT_SUCCESS(status)) {
177/* fall back to busy wait if we're not allowed to sleep */
178KeStallExecutionProcessor(1000 * msecs);
179}
180}
181
182extern u32 ReadVirtIODeviceRegister(ULONG_PTR ulRegister);
183extern void WriteVirtIODeviceRegister(ULONG_PTR ulRegister, u32 ulValue);
184extern u8 ReadVirtIODeviceByte(ULONG_PTR ulRegister);
185extern void WriteVirtIODeviceByte(ULONG_PTR ulRegister, u8 bValue);
186extern u16 ReadVirtIODeviceWord(ULONG_PTR ulRegister);
187extern void WriteVirtIODeviceWord(ULONG_PTR ulRegister, u16 bValue);
188
189VirtIOSystemOps VirtIOWdfSystemOps = {
190.vdev_read_byte = ReadVirtIODeviceByte,
191.vdev_read_word = ReadVirtIODeviceWord,
192.vdev_read_dword = ReadVirtIODeviceRegister,
193.vdev_write_byte = WriteVirtIODeviceByte,
194.vdev_write_word = WriteVirtIODeviceWord,
195.vdev_write_dword = WriteVirtIODeviceRegister,
196.mem_alloc_contiguous_pages = mem_alloc_contiguous_pages,
197.mem_free_contiguous_pages = mem_free_contiguous_pages,
198.mem_get_physical_address = mem_get_physical_address,
199.mem_alloc_nonpaged_block = mem_alloc_nonpaged_block,
200.mem_free_nonpaged_block = mem_free_nonpaged_block,
201.pci_read_config_byte = pci_read_config_byte,
202.pci_read_config_word = pci_read_config_word,
203.pci_read_config_dword = pci_read_config_dword,
204.pci_get_resource_len = pci_get_resource_len,
205.pci_map_address_range = pci_map_address_range,
206.vdev_get_msix_vector = vdev_get_msix_vector,
207.vdev_sleep = vdev_sleep,
208};
209