kvm-guest-drivers-windows

Форк
0
356 строк · 10.7 Кб
1
/*
2
 * This file contains balloon driver routines
3
 *
4
 * Copyright (c) 2009-2017  Red Hat, Inc.
5
 *
6
 * Author(s):
7
 *  Vadim Rozenfeld <vrozenfe@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 "precomp.h"
33

34
#if defined(EVENT_TRACING)
35
#include "balloon.tmh"
36
#endif
37

38
NTSTATUS
39
BalloonInit(
40
    IN WDFOBJECT    WdfDevice
41
            )
42
{
43
    NTSTATUS            status = STATUS_SUCCESS;
44
    PDEVICE_CONTEXT     devCtx = GetDeviceContext(WdfDevice);
45
    u64 u64HostFeatures;
46
    u64 u64GuestFeatures = 0;
47
    bool notify_stat_queue = false;
48
    VIRTIO_WDF_QUEUE_PARAM params[3];
49
    PVIOQUEUE vqs[3];
50
    ULONG nvqs;
51

52
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> BalloonInit\n");
53

54
    WdfObjectAcquireLock(WdfDevice);
55

56
    // inflate
57
    params[0].Interrupt = devCtx->WdfInterrupt;
58

59
    // deflate
60
    params[1].Interrupt = devCtx->WdfInterrupt;
61

62
    // stats
63
    params[2].Interrupt = devCtx->WdfInterrupt;
64

65
    u64HostFeatures = VirtIOWdfGetDeviceFeatures(&devCtx->VDevice);
66

67
    if (virtio_is_feature_enabled(u64HostFeatures, VIRTIO_BALLOON_F_STATS_VQ))
68
    {
69
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
70
            "Enable stats feature.\n");
71

72
        virtio_feature_enable(u64GuestFeatures, VIRTIO_BALLOON_F_STATS_VQ);
73
        nvqs = 3;
74
    }
75
    else
76
    {
77
        nvqs = 2;
78
    }
79

80
    status = VirtIOWdfSetDriverFeatures(&devCtx->VDevice, u64GuestFeatures, 0);
81
    if (NT_SUCCESS(status))
82
    {
83
        // initialize 2 or 3 queues
84
        status = VirtIOWdfInitQueues(&devCtx->VDevice, nvqs, vqs, params);
85
        if (NT_SUCCESS(status))
86
        {
87
            devCtx->InfVirtQueue = vqs[0];
88
            devCtx->DefVirtQueue = vqs[1];
89

90
            if (nvqs == 3)
91
            {
92
                VIO_SG  sg;
93

94
                devCtx->StatVirtQueue = vqs[2];
95

96
                sg.physAddr = VirtIOWdfDeviceGetPhysicalAddress(&devCtx->VDevice.VIODevice, devCtx->MemStats);
97
                sg.length = sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR;
98

99
                if (virtqueue_add_buf(
100
                    devCtx->StatVirtQueue, &sg, 1, 0, devCtx, NULL, 0) >= 0)
101
                {
102
                    notify_stat_queue = true;
103
                }
104
                else
105
                {
106
                    TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS,
107
                        "Failed to add buffer to stats queue.\n");
108
                }
109
            }
110
            VirtIOWdfSetDriverOK(&devCtx->VDevice);
111
        }
112
        else
113
        {
114
            TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS,
115
                "VirtIOWdfInitQueues failed with %x\n", status);
116
            VirtIOWdfSetDriverFailed(&devCtx->VDevice);
117
        }
118
    }
119
    else
120
    {
121
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS,
122
            "VirtIOWdfSetDriverFeatures failed with %x\n", status);
123
        VirtIOWdfSetDriverFailed(&devCtx->VDevice);
124
    }
125

126
    // notify the stat queue only after the virtual device has been fully initialized
127
    if (notify_stat_queue)
128
    {
129
        virtqueue_kick(devCtx->StatVirtQueue);
130
    }
131

132
    WdfObjectReleaseLock(WdfDevice);
133

134
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- BalloonInit\n");
135
    return status;
136
}
137

138
VOID
139
BalloonFill(
140
    IN WDFOBJECT WdfDevice,
141
    IN size_t num)
142
{
143
    PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice);
144
    PHYSICAL_ADDRESS LowAddress;
145
    PHYSICAL_ADDRESS HighAddress;
146
    PHYSICAL_ADDRESS SkipBytes;
147
    PPAGE_LIST_ENTRY pNewPageListEntry;
148
    PMDL pPageMdl;
149

150
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
151

152
    ctx->num_pfns = 0;
153

154
#ifndef BALLOON_INFLATE_IGNORE_LOWMEM
155
    if (IsLowMemory(WdfDevice))
156
    {
157
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
158
            "Low memory. Allocated pages: %d\n", ctx->num_pages);
159
        return;
160
    }
161
#endif // !BALLOON_INFLATE_IGNORE_LOWMEM
162

163
    num = min(num, PAGE_SIZE / sizeof(PFN_NUMBER));
164
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
165
        "Inflate balloon with %d pages.\n", num);
166

167
    LowAddress.QuadPart = 0;
168
    HighAddress.QuadPart = (ULONGLONG)-1;
169
    SkipBytes.QuadPart = 0;
170

171
    pPageMdl = MmAllocatePagesForMdlEx(LowAddress, HighAddress, SkipBytes,
172
        num * PAGE_SIZE, MmNonCached, MM_DONT_ZERO_ALLOCATION);
173

174
    if (pPageMdl == NULL)
175
    {
176
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
177
            "Failed to allocate pages.\n");
178
        return;
179
    }
180

181
    if (MmGetMdlByteCount(pPageMdl) != (num * PAGE_SIZE))
182
    {
183
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
184
            "Not all requested memory was allocated (%d/%d).\n",
185
            MmGetMdlByteCount(pPageMdl), num * PAGE_SIZE);
186
        MmFreePagesFromMdl(pPageMdl);
187
        ExFreePool(pPageMdl);
188
        return;
189
    }
190

191
    pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList(
192
        &ctx->LookAsideList);
193

194
    if (pNewPageListEntry == NULL)
195
    {
196
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS,
197
            "Failed to allocate list entry.\n");
198
        MmFreePagesFromMdl(pPageMdl);
199
        ExFreePool(pPageMdl);
200
        return;
201
    }
202

203
    pNewPageListEntry->PageMdl = pPageMdl;
204
    PushEntryList(&ctx->PageListHead, &(pNewPageListEntry->SingleListEntry));
205

206
    ctx->num_pfns = (ULONG)num;
207
    ctx->num_pages += ctx->num_pfns;
208

209
    RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl),
210
        ctx->num_pfns * sizeof(PFN_NUMBER));
211

212
    BalloonTellHost(WdfDevice, ctx->InfVirtQueue);
213

214
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
215
}
216

217
VOID
218
BalloonLeak(
219
    IN WDFOBJECT WdfDevice,
220
    IN size_t num
221
    )
222
{
223
    PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice);
224
    PPAGE_LIST_ENTRY pPageListEntry;
225
    PMDL pPageMdl;
226

227
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
228

229
    pPageListEntry = (PPAGE_LIST_ENTRY)PopEntryList(&ctx->PageListHead);
230
    if (pPageListEntry == NULL)
231
    {
232
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "No list entries.\n");
233
        return;
234
    }
235

236
    pPageMdl = pPageListEntry->PageMdl;
237

238
    num = MmGetMdlByteCount(pPageMdl) / PAGE_SIZE;
239
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
240
        "Deflate balloon with %d pages.\n", num);
241

242
    ctx->num_pfns = (ULONG)num;
243
    ctx->num_pages -= ctx->num_pfns;
244

245
    RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl),
246
        ctx->num_pfns * sizeof(PFN_NUMBER));
247

248
    MmFreePagesFromMdl(pPageMdl);
249
    ExFreePool(pPageMdl);
250
    ExFreeToNPagedLookasideList(&ctx->LookAsideList, pPageListEntry);
251

252
    BalloonTellHost(WdfDevice, ctx->DefVirtQueue);
253

254
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
255
}
256

257
VOID
258
BalloonTellHost(
259
    IN WDFOBJECT WdfDevice,
260
    IN PVIOQUEUE vq
261
    )
262
{
263
    VIO_SG              sg;
264
    PDEVICE_CONTEXT     devCtx = GetDeviceContext(WdfDevice);
265
    NTSTATUS            status;
266
    LARGE_INTEGER       timeout = {0};
267
    bool                do_notify;
268

269
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
270
    if (devCtx->SurpriseRemoval)
271
    {
272
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "<-- %s Skipped\n", __FUNCTION__);
273
        return;
274
    }
275

276
    sg.physAddr = VirtIOWdfDeviceGetPhysicalAddress(&devCtx->VDevice.VIODevice, devCtx->pfns_table);
277
    sg.length = sizeof(devCtx->pfns_table[0]) * devCtx->num_pfns;
278

279
    WdfSpinLockAcquire(devCtx->InfDefQueueLock);
280
    if (virtqueue_add_buf(vq, &sg, 1, 0, devCtx, NULL, 0) < 0)
281
    {
282
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "<-> %s :: Cannot add buffer\n", __FUNCTION__);
283
        WdfSpinLockRelease(devCtx->InfDefQueueLock);
284
        return;
285
    }
286
    do_notify = virtqueue_kick_prepare(vq);
287
    WdfSpinLockRelease(devCtx->InfDefQueueLock);
288

289
    if (do_notify)
290
    {
291
        virtqueue_notify(vq);
292
    }
293

294
    timeout.QuadPart = Int32x32To64(1000, -10000);
295
    status = KeWaitForSingleObject (
296
                &devCtx->HostAckEvent,
297
                Executive,
298
                KernelMode,
299
                FALSE,
300
                &timeout);
301
    ASSERT(NT_SUCCESS(status));
302
    if(STATUS_TIMEOUT == status)
303
    {
304
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "<--> TimeOut\n");
305
    }
306
}
307

308

309
VOID
310
BalloonTerm(
311
    IN WDFOBJECT    WdfDevice
312
    )
313
{
314
    PDEVICE_CONTEXT     devCtx = GetDeviceContext(WdfDevice);
315

316
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> BalloonTerm\n");
317

318
    WdfObjectAcquireLock(WdfDevice);
319

320
    VirtIOWdfDestroyQueues(&devCtx->VDevice);
321
    devCtx->StatVirtQueue = NULL;
322

323
    WdfObjectReleaseLock(WdfDevice);
324

325
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- BalloonTerm\n");
326
}
327

328
VOID
329
BalloonMemStats(
330
    IN WDFOBJECT WdfDevice
331
    )
332
{
333
    VIO_SG              sg;
334
    PDEVICE_CONTEXT     devCtx = GetDeviceContext(WdfDevice);
335
    bool                do_notify;
336

337
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
338

339
    sg.physAddr = VirtIOWdfDeviceGetPhysicalAddress(&devCtx->VDevice.VIODevice, devCtx->MemStats);
340
    sg.length = sizeof(BALLOON_STAT) * VIRTIO_BALLOON_S_NR;
341

342
    WdfSpinLockAcquire(devCtx->StatQueueLock);
343
    if (virtqueue_add_buf(devCtx->StatVirtQueue, &sg, 1, 0, devCtx, NULL, 0) < 0)
344
    {
345
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "<-> %s :: Cannot add buffer\n", __FUNCTION__);
346
    }
347
    do_notify = virtqueue_kick_prepare(devCtx->StatVirtQueue);
348
    WdfSpinLockRelease(devCtx->StatQueueLock);
349

350
    if (do_notify)
351
    {
352
        virtqueue_notify(devCtx->StatVirtQueue);
353
    }
354

355
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
356
}
357

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.