win-pvdrivers

view xennet/xennet.c @ 685:c13ccf5a629b

Fixed a bug in the dma routines which was causing memory corruption. In some cases when Windows gave an MDL that was longer than the buffer to be dma'd, the end of the buffer would be overwritten. The only time I am aware of this occuring is on one particular map in Call Of Duty 4.

Split out the dma routines from xenpci_pdo.c into xenpci_dma.c
author James Harper <james.harper@bendigoit.com.au>
date Wed Oct 14 14:46:39 2009 +1100 (2009-10-14)
parents ee9c59a5a06c
children f1bb26495379
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include <stdlib.h>
22 #include <io/xenbus.h>
23 #include "xennet.h"
25 /* ----- BEGIN Other people's code --------- */
26 /* from linux/include/linux/ctype.h, used under GPLv2 */
27 #define _U 0x01 /* upper */
28 #define _L 0x02 /* lower */
29 #define _D 0x04 /* digit */
30 #define _C 0x08 /* cntrl */
31 #define _P 0x10 /* punct */
32 #define _S 0x20 /* white space (space/lf/tab) */
33 #define _X 0x40 /* hex digit */
34 #define _SP 0x80 /* hard space (0x20) */
36 /* from linux/include/lib/ctype.c, used under GPLv2 */
37 unsigned char _ctype[] = {
38 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
39 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
40 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
41 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
42 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
43 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
44 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
45 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
46 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
47 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
48 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
49 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
50 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
51 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
52 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
53 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
54 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
55 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
56 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
57 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
58 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
59 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
60 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
61 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
63 /* from linux/include/linux/ctype.h, used under GPLv2 */
64 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
66 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
67 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
68 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
69 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
70 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
71 #define islower(c) ((__ismask(c)&(_L)) != 0)
72 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
73 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
74 #define isspace(c) ((__ismask(c)&(_S)) != 0)
75 #define isupper(c) ((__ismask(c)&(_U)) != 0)
76 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
78 #define TOLOWER(x) ((x) | 0x20)
80 /* from linux/lib/vsprintf.c, used under GPLv2 */
81 /* Copyright (C) 1991, 1992 Linus Torvalds
82 * Wirzenius wrote this portably, Torvalds fucked it up :-)
83 */
84 /**
85 * simple_strtoul - convert a string to an unsigned long
86 * @cp: The start of the string
87 * @endp: A pointer to the end of the parsed string will be placed here
88 * @base: The number base to use
89 */
90 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
91 {
92 unsigned long result = 0,value;
94 if (!base) {
95 base = 10;
96 if (*cp == '0') {
97 base = 8;
98 cp++;
99 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
100 cp++;
101 base = 16;
102 }
103 }
104 } else if (base == 16) {
105 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
106 cp += 2;
107 }
108 while (isxdigit(*cp) &&
109 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
110 result = result*base + value;
111 cp++;
112 }
113 if (endp)
114 *endp = (char *)cp;
115 return result;
116 }
117 /* end vsprintf.c code */
118 /* ----- END Other people's code --------- */
120 static NDIS_STATUS
121 XenNet_ConnectBackend(struct xennet_info *xi)
122 {
123 PUCHAR ptr;
124 UCHAR type;
125 PCHAR setting, value, value2;
126 UINT i;
127 ULONG backend_sg = 0;
128 ULONG backend_gso = 0;
130 FUNCTION_ENTER();
132 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
134 ptr = xi->config_page;
135 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
136 {
137 switch(type)
138 {
139 case XEN_INIT_TYPE_RING: /* frontend ring */
140 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
141 if (strcmp(setting, "tx-ring-ref") == 0)
142 {
143 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
144 } else if (strcmp(setting, "rx-ring-ref") == 0)
145 {
146 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
147 }
148 break;
149 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
150 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
151 if (strcmp(setting, "event-channel") == 0)
152 {
153 xi->event_channel = PtrToUlong(value);
154 }
155 break;
156 case XEN_INIT_TYPE_READ_STRING_FRONT:
157 break;
158 case XEN_INIT_TYPE_READ_STRING_BACK:
159 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
160 if (strcmp(setting, "mac") == 0)
161 {
162 char *s, *e;
163 s = value;
164 for (i = 0; i < ETH_ALEN; i++) {
165 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
166 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
167 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
168 }
169 s = e + 1;
170 }
171 if (!(xi->curr_mac_addr[0] & 0x02))
172 {
173 /* only copy if curr_mac_addr is not a LUA */
174 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
175 }
176 }
177 else if (strcmp(setting, "feature-sg") == 0)
178 {
179 if (atoi(value))
180 {
181 backend_sg = 1;
182 }
183 }
184 else if (strcmp(setting, "feature-gso-tcpv4") == 0)
185 {
186 if (atoi(value))
187 {
188 backend_gso = 1;
189 }
190 }
191 break;
192 case XEN_INIT_TYPE_VECTORS:
193 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
194 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
195 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
196 {
197 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
198 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
199 FUNCTION_ERROR_EXIT();
200 return NDIS_STATUS_ADAPTER_NOT_FOUND;
201 }
202 else
203 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
204 break;
205 case XEN_INIT_TYPE_STATE_PTR:
206 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
207 xi->device_state = (PXENPCI_DEVICE_STATE)value;
208 break;
209 default:
210 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
211 break;
212 }
213 }
214 if (xi->config_sg && !backend_sg)
215 {
216 KdPrint((__DRIVER_NAME " SG not supported by backend - disabling\n"));
217 xi->config_sg = 0;
218 }
219 if (xi->config_gso && !backend_gso)
220 {
221 KdPrint((__DRIVER_NAME " GSO not supported by backend - disabling\n"));
222 xi->config_gso = 0;
223 }
224 FUNCTION_EXIT();
226 return NDIS_STATUS_SUCCESS;
227 }
229 static DDKAPI VOID
230 XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
231 {
232 struct xennet_info *xi = context;
234 UNREFERENCED_PARAMETER(device_object);
236 FUNCTION_ENTER();
238 ASSERT(xi->resume_work_item);
239 IoFreeWorkItem(xi->resume_work_item);
240 xi->resume_work_item = NULL;
242 XenNet_TxResumeStart(xi);
243 XenNet_RxResumeStart(xi);
244 XenNet_ConnectBackend(xi);
245 XenNet_RxResumeEnd(xi);
246 XenNet_TxResumeEnd(xi);
247 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
248 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
249 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
250 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
252 FUNCTION_EXIT();
254 }
256 static VOID
257 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
258 {
259 struct xennet_info *xi = context;
260 KIRQL old_irql;
262 UNREFERENCED_PARAMETER(dpc);
263 UNREFERENCED_PARAMETER(arg1);
264 UNREFERENCED_PARAMETER(arg2);
266 FUNCTION_ENTER();
268 switch (xi->device_state->suspend_resume_state_pdo)
269 {
270 case SR_STATE_SUSPENDING:
271 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
272 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
273 if (xi->tx_id_free == NET_TX_RING_SIZE)
274 {
275 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
276 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
277 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
278 }
279 KeReleaseSpinLock(&xi->rx_lock, old_irql);
280 break;
281 case SR_STATE_RESUMING:
282 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
283 ASSERT(!xi->resume_work_item);
284 xi->resume_work_item = IoAllocateWorkItem(xi->fdo);
285 IoQueueWorkItem(xi->resume_work_item, XenNet_Resume, DelayedWorkQueue, xi);
286 break;
287 default:
288 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
289 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
290 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
291 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
292 break;
293 }
294 KeMemoryBarrier();
296 FUNCTION_EXIT();
297 }
299 static DDKAPI BOOLEAN
300 XenNet_HandleEvent(PVOID context)
301 {
302 struct xennet_info *xi = context;
303 ULONG suspend_resume_state_pdo;
305 //FUNCTION_ENTER();
306 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
307 KeMemoryBarrier();
308 // KdPrint((__DRIVER_NAME " connected = %d, inactive = %d, suspend_resume_state_pdo = %d\n",
309 // xi->connected, xi->inactive, suspend_resume_state_pdo));
310 if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
311 {
312 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
313 }
314 if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
315 {
316 KeInsertQueueDpc(&xi->tx_dpc, NULL, NULL);
317 KeInsertQueueDpc(&xi->rx_dpc, NULL, NULL);
318 }
319 //FUNCTION_EXIT();
320 return TRUE;
321 }
323 // Called at <= DISPATCH_LEVEL
324 static DDKAPI NDIS_STATUS
325 XenNet_Init(
326 OUT PNDIS_STATUS OpenErrorStatus,
327 OUT PUINT SelectedMediumIndex,
328 IN PNDIS_MEDIUM MediumArray,
329 IN UINT MediumArraySize,
330 IN NDIS_HANDLE MiniportAdapterHandle,
331 IN NDIS_HANDLE WrapperConfigurationContext
332 )
333 {
334 NDIS_STATUS status;
335 BOOLEAN medium_found = FALSE;
336 struct xennet_info *xi = NULL;
337 UINT nrl_length;
338 PNDIS_RESOURCE_LIST nrl;
339 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
340 KIRQL irq_level = 0;
341 ULONG irq_vector = 0;
342 ULONG irq_mode = 0;
343 NDIS_HANDLE config_handle;
344 NDIS_STRING config_param_name;
345 PNDIS_CONFIGURATION_PARAMETER config_param;
346 ULONG i;
347 PUCHAR ptr;
348 UCHAR type;
349 PCHAR setting, value;
350 ULONG length;
351 CHAR buf[128];
352 PVOID network_address;
353 UINT network_address_length;
355 UNREFERENCED_PARAMETER(OpenErrorStatus);
357 FUNCTION_ENTER();
359 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
361 length = NdisReadPciSlotInformation(MiniportAdapterHandle, 0, 0, &buf, 128);
362 KdPrint((__DRIVER_NAME " NdisReadPciSlotInformation = %d\n", length));
363 /* deal with medium stuff */
364 for (i = 0; i < MediumArraySize; i++)
365 {
366 if (MediumArray[i] == NdisMedium802_3)
367 {
368 medium_found = TRUE;
369 break;
370 }
371 }
372 if (!medium_found)
373 {
374 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
375 return NDIS_STATUS_UNSUPPORTED_MEDIA;
376 }
377 *SelectedMediumIndex = i;
379 /* Alloc memory for adapter private info */
380 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
381 if (!NT_SUCCESS(status))
382 {
383 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
384 status = NDIS_STATUS_RESOURCES;
385 goto err;
386 }
387 RtlZeroMemory(xi, sizeof(*xi));
388 xi->adapter_handle = MiniportAdapterHandle;
389 xi->rx_target = RX_DFL_MIN_TARGET;
390 xi->rx_min_target = RX_DFL_MIN_TARGET;
391 xi->rx_max_target = RX_MAX_TARGET;
392 xi->inactive = TRUE;
393 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi, 0,
394 #ifdef NDIS51_MINIPORT
395 NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
396 #endif
397 |NDIS_ATTRIBUTE_DESERIALIZE
398 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
399 |NDIS_ATTRIBUTE_BUS_MASTER,
400 NdisInterfaceInternal);
401 xi->multicast_list_size = 0;
403 nrl_length = 0;
404 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
405 NULL, (PUINT)&nrl_length);
406 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
407 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
408 if (status != NDIS_STATUS_SUCCESS)
409 {
410 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
411 return NDIS_STATUS_RESOURCES;
412 }
413 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
414 nrl, (PUINT)&nrl_length);
415 if (status != NDIS_STATUS_SUCCESS)
416 {
417 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
418 return NDIS_STATUS_RESOURCES;
419 }
420 xi->event_channel = 0;
421 xi->config_csum = 1;
422 xi->config_csum_rx_check = 1;
423 xi->config_sg = 1;
424 xi->config_gso = 61440;
425 xi->config_page = NULL;
426 xi->config_rx_interrupt_moderation = 0;
428 for (i = 0; i < nrl->Count; i++)
429 {
430 prd = &nrl->PartialDescriptors[i];
432 switch(prd->Type)
433 {
434 case CmResourceTypeInterrupt:
435 irq_vector = prd->u.Interrupt.Vector;
436 irq_level = (KIRQL)prd->u.Interrupt.Level;
437 irq_mode = (prd->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?NdisInterruptLatched:NdisInterruptLevelSensitive;
438 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x, irq_mode = %s\n", irq_vector, irq_level,
439 (irq_mode == NdisInterruptLatched)?"NdisInterruptLatched":"NdisInterruptLevelSensitive"));
440 break;
441 case CmResourceTypeMemory:
442 if (xi->config_page)
443 {
444 KdPrint(("More than one memory range\n"));
445 return NDIS_STATUS_RESOURCES;
446 }
447 else
448 {
449 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
450 if (!NT_SUCCESS(status))
451 {
452 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
453 NdisFreeMemory(nrl, nrl_length, 0);
454 return NDIS_STATUS_RESOURCES;
455 }
456 }
457 break;
458 }
459 }
460 NdisFreeMemory(nrl, nrl_length, 0);
461 if (!xi->config_page)
462 {
463 KdPrint(("No config page given\n"));
464 return NDIS_STATUS_RESOURCES;
465 }
467 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
469 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
470 &xi->lower_do, NULL, NULL);
471 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
473 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
474 NAME_SIZE, xi->dev_desc, &length);
475 if (!NT_SUCCESS(status))
476 {
477 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
478 status = NDIS_STATUS_FAILURE;
479 goto err;
480 }
482 ptr = xi->config_page;
483 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
484 {
485 switch(type)
486 {
487 case XEN_INIT_TYPE_VECTORS:
488 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
489 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
490 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
491 {
492 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
493 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
494 FUNCTION_ERROR_EXIT();
495 return NDIS_STATUS_FAILURE;
496 }
497 else
498 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
499 break;
500 case XEN_INIT_TYPE_STATE_PTR:
501 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
502 xi->device_state = (PXENPCI_DEVICE_STATE)value;
503 break;
504 case XEN_INIT_TYPE_ACTIVE:
505 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_ACTIVE\n"));
506 xi->inactive = FALSE;
507 break;
508 default:
509 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
510 break;
511 }
512 }
514 // now build config page
516 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
517 if (!NT_SUCCESS(status))
518 {
519 KdPrint(("Could not open config in registry (%08x)\n", status));
520 status = NDIS_STATUS_RESOURCES;
521 goto err;
522 }
524 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
525 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
526 if (!NT_SUCCESS(status))
527 {
528 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
529 xi->config_sg = 1;
530 }
531 else
532 {
533 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
534 xi->config_sg = config_param->ParameterData.IntegerData;
535 }
537 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
538 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
539 if (!NT_SUCCESS(status))
540 {
541 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
542 xi->config_gso = 0;
543 }
544 else
545 {
546 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
547 xi->config_gso = config_param->ParameterData.IntegerData;
548 if (xi->config_gso > 61440)
549 {
550 xi->config_gso = 61440;
551 KdPrint(("(clipped to %d)\n", xi->config_gso));
552 }
553 }
555 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
556 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
557 if (!NT_SUCCESS(status))
558 {
559 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
560 xi->config_csum = 1;
561 }
562 else
563 {
564 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
565 xi->config_csum = !!config_param->ParameterData.IntegerData;
566 }
568 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
569 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
570 if (!NT_SUCCESS(status))
571 {
572 KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
573 xi->config_csum_rx_check = 1;
574 }
575 else
576 {
577 KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
578 xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
579 }
581 NdisInitUnicodeString(&config_param_name, L"MTU");
582 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
583 if (!NT_SUCCESS(status))
584 {
585 KdPrint(("Could not read MTU value (%08x)\n", status));
586 xi->config_mtu = 1500;
587 }
588 else
589 {
590 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
591 xi->config_mtu = config_param->ParameterData.IntegerData;
592 }
594 NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
595 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
596 if (!NT_SUCCESS(status))
597 {
598 KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
599 xi->config_rx_interrupt_moderation = 1500;
600 }
601 else
602 {
603 KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
604 xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
605 }
608 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
609 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || !(((PUCHAR)network_address)[0] & 0x02))
610 {
611 KdPrint(("Could not read NetworkAddress value (%08x)\n", status));
612 memset(xi->curr_mac_addr, 0, ETH_ALEN);
613 }
614 else
615 {
616 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
617 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
618 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
619 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
620 }
622 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
624 NdisCloseConfiguration(config_handle);
626 ptr = xi->config_page;
627 // two XEN_INIT_TYPE_RUNs means go straight to XenbusStateConnected - skip XenbusStateInitialised
628 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
629 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
630 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
631 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
632 #pragma warning(suppress:4054)
633 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
634 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
635 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
636 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
637 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
638 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
639 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
640 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
641 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
642 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
643 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
644 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
645 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
647 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
648 if (!NT_SUCCESS(status))
649 {
650 KdPrint(("Failed to complete device configuration (%08x)\n", status));
651 goto err;
652 }
654 status = XenNet_ConnectBackend(xi);
656 if (!NT_SUCCESS(status))
657 {
658 KdPrint(("Failed to complete device configuration (%08x)\n", status));
659 goto err;
660 }
662 if (xi->config_sg)
663 {
664 status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE, xi->config_gso);
665 if (!NT_SUCCESS(status))
666 {
667 KdPrint(("NdisMInitializeScatterGatherDma failed (%08x), disabling\n", status));
668 xi->config_sg = 0;
669 }
670 }
671 else
672 {
673 status = NdisMAllocateMapRegisters(xi->adapter_handle, 0, NDIS_DMA_64BITS, 64, PAGE_SIZE);
674 if (status != NDIS_STATUS_SUCCESS)
675 {
676 KdPrint((__DRIVER_NAME " Cannot allocate Map Registers\n"));
677 }
678 /* without SG, GSO can be a maximum of PAGE_SIZE */
679 xi->config_gso = min(xi->config_gso, PAGE_SIZE);
680 }
682 XenNet_TxInit(xi);
683 XenNet_RxInit(xi);
685 xi->connected = TRUE;
687 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
689 FUNCTION_EXIT();
691 return NDIS_STATUS_SUCCESS;
693 err:
694 NdisFreeMemory(xi, 0, 0);
695 *OpenErrorStatus = status;
696 FUNCTION_ERROR_EXIT();
697 return status;
698 }
700 VOID
701 XenNet_PnPEventNotify(
702 IN NDIS_HANDLE MiniportAdapterContext,
703 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
704 IN PVOID InformationBuffer,
705 IN ULONG InformationBufferLength
706 )
707 {
708 UNREFERENCED_PARAMETER(MiniportAdapterContext);
709 UNREFERENCED_PARAMETER(PnPEvent);
710 UNREFERENCED_PARAMETER(InformationBuffer);
711 UNREFERENCED_PARAMETER(InformationBufferLength);
713 FUNCTION_CALLED();
714 }
716 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
717 VOID DDKAPI
718 XenNet_Shutdown(
719 IN NDIS_HANDLE MiniportAdapterContext
720 )
721 {
722 UNREFERENCED_PARAMETER(MiniportAdapterContext);
724 /* remember we are called at >= DIRQL here */
725 FUNCTION_CALLED();
726 }
728 /* Opposite of XenNet_Init */
729 VOID DDKAPI
730 XenNet_Halt(
731 IN NDIS_HANDLE MiniportAdapterContext
732 )
733 {
734 struct xennet_info *xi = MiniportAdapterContext;
736 FUNCTION_ENTER();
737 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
739 xi->shutting_down = TRUE;
740 KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
742 XenNet_TxShutdown(xi);
743 XenNet_RxShutdown(xi);
745 xi->connected = FALSE;
746 KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
748 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
750 if (!xi->config_sg)
751 {
752 NdisMFreeMapRegisters(xi->adapter_handle);
753 }
755 NdisFreeMemory(xi, 0, 0);
757 FUNCTION_EXIT();
758 }
760 NDIS_STATUS
761 XenNet_Reset(
762 PBOOLEAN AddressingReset,
763 NDIS_HANDLE MiniportAdapterContext
764 )
765 {
766 UNREFERENCED_PARAMETER(MiniportAdapterContext);
768 *AddressingReset = FALSE;
769 return NDIS_STATUS_SUCCESS;
770 }
772 dma_driver_extension_t *dma_driver_extension;
774 NTSTATUS DDKAPI
775 DriverEntry(
776 PDRIVER_OBJECT DriverObject,
777 PUNICODE_STRING RegistryPath
778 )
779 {
780 NTSTATUS status;
781 NDIS_HANDLE ndis_wrapper_handle = NULL;
782 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
784 FUNCTION_ENTER();
786 IoAllocateDriverObjectExtension(DriverObject, UlongToPtr(XEN_DMA_DRIVER_EXTENSION_MAGIC), sizeof(dma_driver_extension_t), &dma_driver_extension);
787 dma_driver_extension->need_virtual_address = NULL;
788 dma_driver_extension->get_alignment = NULL;
789 dma_driver_extension->max_sg_elements = 19; /* header + 18 fragments */
791 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
792 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
794 KdPrint((__DRIVER_NAME " NdisGetVersion = %x\n", NdisGetVersion()));
796 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
797 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
798 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
799 if (!ndis_wrapper_handle)
800 {
801 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper failed\n"));
802 return NDIS_STATUS_FAILURE;
803 }
804 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper succeeded\n"));
806 /* NDIS 5.1 driver */
807 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
808 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
810 KdPrint((__DRIVER_NAME " MajorNdisVersion = %d, MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
812 mini_chars.HaltHandler = XenNet_Halt;
813 mini_chars.InitializeHandler = XenNet_Init;
814 //mini_chars.ISRHandler = XenNet_InterruptIsr;
815 //mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
816 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
817 mini_chars.ResetHandler = XenNet_Reset;
818 mini_chars.SetInformationHandler = XenNet_SetInformation;
819 /* added in v.4 -- use multiple pkts interface */
820 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
821 mini_chars.SendPacketsHandler = XenNet_SendPackets;
822 mini_chars.CancelSendPacketsHandler = XenNet_CancelSendPackets;
824 #ifdef NDIS51_MINIPORT
825 /* added in v.5.1 */
826 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
827 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
828 #else
829 // something else here
830 #endif
832 /* set up upper-edge interface */
833 KdPrint((__DRIVER_NAME " about to call NdisMRegisterMiniport\n"));
834 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
835 KdPrint((__DRIVER_NAME " called NdisMRegisterMiniport\n"));
836 if (!NT_SUCCESS(status))
837 {
838 KdPrint((__DRIVER_NAME " NdisMRegisterMiniport failed, status = 0x%x\n", status));
839 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
840 return status;
841 }
843 FUNCTION_EXIT();
845 return status;
846 }