win-pvdrivers

view xennet/xennet.c @ 12:5712dede5a1b

add in xen public includes, so the extra step of copying them over is not needed
author Andy Grover <andy@groveronline.com>
date Wed Nov 28 14:44:10 2007 -0800 (2007-11-28)
parents 9e029b33b66b
children be8c09632f31
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover
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 "xennet.h"
23 #if !defined (NDIS51_MINIPORT)
24 #error requires NDIS 5.1 compilation environment
25 #endif
27 #define GRANT_INVALID_REF 0
29 #define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
30 #define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
32 struct xennet_info
33 {
34 PDEVICE_OBJECT pdo;
35 PDEVICE_OBJECT fdo;
36 PDEVICE_OBJECT lower_do;
37 WDFDEVICE *wdf_device;
39 WCHAR name[NAME_SIZE];
40 NDIS_HANDLE adapter_handle;
41 ULONG packet_filter;
42 UCHAR perm_mac_addr[ETH_ALEN];
43 UCHAR curr_mac_addr[ETH_ALEN];
45 char Path[128];
46 char BackendPath[128];
47 XEN_IFACE_EVTCHN EvtChnInterface;
48 XEN_IFACE_XENBUS XenBusInterface;
49 XEN_IFACE_XEN XenInterface;
50 XEN_IFACE_GNTTBL GntTblInterface;
52 struct netif_tx_front_ring tx;
53 struct netif_rx_front_ring rx;
55 /* do we need to keep track of these? */
56 struct netif_tx_sring *txs;
57 struct netif_rx_sring *rxs;
59 UINT irq;
60 SHORT event_channel;
62 grant_ref_t tx_ring_ref;
63 grant_ref_t rx_ring_ref;
64 };
66 /* need to do typedef so the DECLARE below works */
67 typedef struct _wdf_device_info
68 {
69 struct xennet_info *xennet_info;
70 } wdf_device_info;
72 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info, GetWdfDeviceInfo)
74 static PMDL
75 AllocatePages(int Pages)
76 {
77 PHYSICAL_ADDRESS Min;
78 PHYSICAL_ADDRESS Max;
79 PHYSICAL_ADDRESS Align;
80 PMDL Mdl;
82 KdPrint((__DRIVER_NAME " --> Allocate Pages\n"));
84 Min.QuadPart = 0;
85 Max.QuadPart = 0xFFFFFFFF;
86 Align.QuadPart = PAGE_SIZE;
88 Mdl = MmAllocatePagesForMdl(Min, Max, Align, Pages * PAGE_SIZE);
90 KdPrint((__DRIVER_NAME " <-- Allocate Pages (mdl = %08x)\n", Mdl));
92 return Mdl;
93 }
95 static PMDL
96 AllocatePage()
97 {
98 return AllocatePages(1);
99 }
101 static BOOLEAN
102 XenNet_Interrupt(
103 PKINTERRUPT Interrupt,
104 PVOID ServiceContext
105 )
106 {
107 struct xennet_info *xennet_info = ServiceContext;
108 KIRQL KIrql;
110 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
111 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
112 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
113 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
114 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
116 /* do something */
118 return TRUE;
119 }
121 VOID
122 XenNet_Halt(
123 IN NDIS_HANDLE MiniportAdapterContext
124 )
125 {
126 }
128 static NDIS_STATUS
129 XenNet_Init(
130 OUT PNDIS_STATUS OpenErrorStatus,
131 OUT PUINT SelectedMediumIndex,
132 IN PNDIS_MEDIUM MediumArray,
133 IN UINT MediumArraySize,
134 IN NDIS_HANDLE MiniportAdapterHandle,
135 IN NDIS_HANDLE WrapperConfigurationContext
136 )
137 {
138 NDIS_STATUS status;
139 UINT i;
140 BOOLEAN medium_found = FALSE;
141 struct xennet_info *xi = NULL;
142 UINT length;
143 WDF_OBJECT_ATTRIBUTES wdf_attrs;
144 PMDL mdl;
145 ULONG pfn;
147 /* deal with medium stuff */
148 for (i = 0; i < MediumArraySize; i++)
149 {
150 if (MediumArray[i] == NdisMedium802_3)
151 {
152 medium_found = TRUE;
153 break;
154 }
155 }
156 if (!medium_found)
157 {
158 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
159 return NDIS_STATUS_UNSUPPORTED_MEDIA;
160 }
161 *SelectedMediumIndex = i;
163 /* Alloc memory for adapter private info */
164 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
165 if (!NT_SUCCESS(status))
166 {
167 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
168 status = NDIS_STATUS_RESOURCES;
169 goto err;
170 }
171 RtlZeroMemory(xi, sizeof(*xi));
173 /* init xennet_info */
174 xi->adapter_handle = MiniportAdapterHandle;
175 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
176 &xi->lower_do, NULL, NULL);
178 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
179 NAME_SIZE, xi->name, &length);
180 if (!NT_SUCCESS(status))
181 {
182 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
183 status = NDIS_STATUS_FAILURE;
184 goto err;
185 }
187 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
188 0, NDIS_ATTRIBUTE_DESERIALIZE, NdisInterfaceInternal);
190 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdf_attrs, wdf_device_info);
192 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
193 xi->lower_do, xi->pdo, &xi->wdf_device);
194 if (!NT_SUCCESS(status))
195 {
196 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
197 status = NDIS_STATUS_FAILURE;
198 goto err;
199 }
201 GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
203 /* get lower (Xen) interfaces */
205 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
206 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
207 if(!NT_SUCCESS(status))
208 {
209 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
210 status = NDIS_STATUS_FAILURE;
211 goto err;
212 }
214 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
215 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
216 if(!NT_SUCCESS(status))
217 {
218 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
219 status = NDIS_STATUS_FAILURE;
220 goto err;
221 }
223 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
224 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
225 if(!NT_SUCCESS(status))
226 {
227 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
228 status = NDIS_STATUS_FAILURE;
229 goto err;
230 }
232 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
233 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
234 if(!NT_SUCCESS(status))
235 {
236 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
237 status = NDIS_STATUS_FAILURE;
238 goto err;
239 }
241 xi->event_channel = xi->EvtChnInterface.AllocUnbound(0);
242 xi->EvtChnInterface.Bind(xi->event_channel, XenNet_Interrupt, xi);
244 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
245 // or, allocate mem and then get mdl, then free mdl
246 mdl = AllocatePage();
247 pfn = *MmGetMdlPfnArray(mdl);
248 xi->txs = MmMapLockedPages(mdl, KernelMode);
249 SHARED_RING_INIT(xi->txs);
250 FRONT_RING_INIT(&xi->tx, xi->txs, PAGE_SIZE);
251 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(0, pfn, FALSE);
253 mdl = AllocatePage();
254 pfn = *MmGetMdlPfnArray(mdl);
255 xi->rxs = MmMapLockedPages(mdl, KernelMode);
256 SHARED_RING_INIT(xi->rxs);
257 FRONT_RING_INIT(&xi->rx, xi->rxs, PAGE_SIZE);
258 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(0, pfn, FALSE);
260 {
261 char *msg;
262 char **vif_devs;
263 char buffer[128];
264 // get mac addr
265 msg = xi->XenBusInterface.List(XBT_NIL, "device/vif", &vif_devs);
266 if (!msg)
267 {
268 for (i = 0; vif_devs[i]; i++)
269 {
270 RtlStringCbPrintfA(buffer, ARRAY_SIZE(buffer),
271 "device/vif/%s/state", vif_devs[i]);
272 KdPrint(("%s\n", buffer));
273 //XenVbd_HotPlugHandler(buffer, NULL);
274 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
275 }
276 }
277 }
279 return NDIS_STATUS_SUCCESS;
281 err:
282 NdisFreeMemory(xi, 0, 0);
283 return status;
284 }
286 NDIS_OID supported_oids[] =
287 {
288 OID_GEN_SUPPORTED_LIST,
289 OID_GEN_HARDWARE_STATUS,
290 OID_GEN_MEDIA_SUPPORTED,
291 OID_GEN_MEDIA_IN_USE,
292 OID_GEN_MAXIMUM_LOOKAHEAD,
293 OID_GEN_MAXIMUM_FRAME_SIZE,
294 OID_GEN_LINK_SPEED,
295 OID_GEN_TRANSMIT_BUFFER_SPACE,
296 OID_GEN_RECEIVE_BUFFER_SPACE,
297 OID_GEN_TRANSMIT_BLOCK_SIZE,
298 OID_GEN_RECEIVE_BLOCK_SIZE,
299 OID_GEN_VENDOR_ID,
300 OID_GEN_VENDOR_DESCRIPTION,
301 OID_GEN_CURRENT_PACKET_FILTER,
302 OID_GEN_CURRENT_LOOKAHEAD,
303 OID_GEN_DRIVER_VERSION,
304 OID_GEN_MAXIMUM_TOTAL_SIZE,
305 OID_GEN_MAC_OPTIONS,
306 OID_GEN_MEDIA_CONNECT_STATUS,
307 OID_GEN_MAXIMUM_SEND_PACKETS,
308 OID_802_3_PERMANENT_ADDRESS,
309 OID_802_3_CURRENT_ADDRESS,
310 OID_802_3_MULTICAST_LIST,
311 OID_802_3_MAXIMUM_LIST_SIZE,
312 };
314 NDIS_STATUS
315 XenNet_QueryInformation(
316 IN NDIS_HANDLE MiniportAdapterContext,
317 IN NDIS_OID Oid,
318 IN PVOID InformationBuffer,
319 IN ULONG InformationBufferLength,
320 OUT PULONG BytesWritten,
321 OUT PULONG BytesNeeded)
322 {
323 struct xennet_info *xi = MiniportAdapterContext;
324 UCHAR vendor_desc[] = XN_VENDOR_DESC;
325 ULONG temp_data;
326 PVOID data = &temp_data;
327 UINT len = sizeof(temp_data);
328 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
330 switch(Oid)
331 {
332 case OID_GEN_SUPPORTED_LIST:
333 data = supported_oids;
334 len = sizeof(supported_oids);
335 break;
336 case OID_GEN_HARDWARE_STATUS:
337 temp_data = NdisHardwareStatusReady;
338 break;
339 case OID_GEN_MEDIA_SUPPORTED:
340 temp_data = NdisMedium802_3;
341 break;
342 case OID_GEN_MEDIA_IN_USE:
343 temp_data = NdisMedium802_3;
344 break;
345 case OID_GEN_MAXIMUM_LOOKAHEAD:
346 temp_data = XN_DATA_SIZE;
347 break;
348 case OID_GEN_MAXIMUM_FRAME_SIZE:
349 temp_data = XN_MAX_PKT_SIZE;
350 break;
351 case OID_GEN_LINK_SPEED:
352 temp_data = 10000000; /* 1Gb */
353 break;
354 case OID_GEN_TRANSMIT_BUFFER_SPACE:
355 /* pkts times sizeof ring, maybe? */
356 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
357 break;
358 case OID_GEN_RECEIVE_BUFFER_SPACE:
359 /* pkts times sizeof ring, maybe? */
360 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
361 break;
362 case OID_GEN_TRANSMIT_BLOCK_SIZE:
363 temp_data = XN_MAX_PKT_SIZE;
364 break;
365 case OID_GEN_RECEIVE_BLOCK_SIZE:
366 temp_data = XN_MAX_PKT_SIZE;
367 break;
368 case OID_GEN_VENDOR_ID:
369 temp_data = XENSOURCE_MAC_HDR;
370 break;
371 case OID_GEN_VENDOR_DESCRIPTION:
372 data = vendor_desc;
373 len = sizeof(vendor_desc);
374 break;
375 case OID_GEN_CURRENT_PACKET_FILTER:
376 temp_data = xi->packet_filter;
377 break;
378 case OID_GEN_CURRENT_LOOKAHEAD:
379 temp_data = XN_MAX_PKT_SIZE;
380 break;
381 case OID_GEN_DRIVER_VERSION:
382 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
383 len = 2;
384 break;
385 case OID_GEN_MAXIMUM_TOTAL_SIZE:
386 temp_data = XN_MAX_PKT_SIZE;
387 break;
388 case OID_GEN_MAC_OPTIONS:
389 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
390 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
391 NDIS_MAC_OPTION_NO_LOOPBACK;
392 break;
393 case OID_GEN_MEDIA_CONNECT_STATUS:
394 /* how can we not be connected?? */
395 temp_data = NdisMediaStateConnected;
396 break;
397 case OID_GEN_MAXIMUM_SEND_PACKETS:
398 temp_data = XN_MAX_SEND_PKTS;
399 break;
400 case OID_802_3_PERMANENT_ADDRESS:
401 data = xi->perm_mac_addr;
402 len = ETH_ALEN;
403 break;
404 case OID_802_3_CURRENT_ADDRESS:
405 data = xi->curr_mac_addr;
406 len = ETH_ALEN;
407 break;
408 case OID_802_3_MULTICAST_LIST:
409 data = NULL;
410 len = 0;
411 case OID_802_3_MAXIMUM_LIST_SIZE:
412 temp_data = 0; /* no mcast support */
413 break;
414 default:
415 KdPrint(("Unknown OID 0x%x\n", Oid));
416 status = NDIS_STATUS_NOT_SUPPORTED;
417 }
419 if (!NT_SUCCESS(status))
420 {
421 return status;
422 }
424 if (len > InformationBufferLength)
425 {
426 *BytesNeeded = len;
427 return NDIS_STATUS_BUFFER_TOO_SHORT;
428 }
430 *BytesWritten = len;
431 if (len)
432 {
433 NdisMoveMemory(InformationBuffer, data, len);
434 }
436 KdPrint(("Got OID 0x%x\n", Oid));
438 return status;
439 }
441 NDIS_STATUS
442 XenNet_SetInformation(
443 IN NDIS_HANDLE MiniportAdapterContext,
444 IN NDIS_OID Oid,
445 IN PVOID InformationBuffer,
446 IN ULONG InformationBufferLength,
447 OUT PULONG BytesRead,
448 OUT PULONG BytesNeeded
449 )
450 {
451 KdPrint((__FUNCTION__ " called\n"));
452 return NDIS_STATUS_SUCCESS;
453 }
455 VOID
456 XenNet_ReturnPacket(
457 IN NDIS_HANDLE MiniportAdapterContext,
458 IN PNDIS_PACKET Packet
459 )
460 {
461 KdPrint((__FUNCTION__ " called\n"));
462 }
464 VOID
465 XenNet_SendPackets(
466 IN NDIS_HANDLE MiniportAdapterContext,
467 IN PPNDIS_PACKET PacketArray,
468 IN UINT NumberOfPackets
469 )
470 {
471 /* for each packet:
472 req_prod_pvt is the next entry in the cmd ring to use
473 add pkt to array of saved packets
474 fill out tx request for the first part of skb
475 add to grant table
476 do flags for csum etc
477 gso (later)
478 inc req_prod_pvt
479 frags
480 possibly notify
481 network_tx)buf_gc
482 stop netif if no more room
483 */
484 struct xennet_info *xi = MiniportAdapterContext;
485 PNDIS_PACKET curr_packet;
486 UINT i;
487 UINT table_entry;
489 KdPrint((__FUNCTION__ " called\n"));
491 for (i = 0; i < NumberOfPackets; i++)
492 {
493 curr_packet = PacketArray[i];
494 ASSERT(curr_packet);
496 table_entry = xi->tx.req_prod_pvt;
497 }
499 }
501 VOID
502 XenNet_PnPEventNotify(
503 IN NDIS_HANDLE MiniportAdapterContext,
504 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
505 IN PVOID InformationBuffer,
506 IN ULONG InformationBufferLength
507 )
508 {
509 KdPrint((__FUNCTION__ " called\n"));
510 }
512 VOID
513 XenNet_Shutdown(
514 IN NDIS_HANDLE MiniportAdapterContext
515 )
516 {
517 KdPrint((__FUNCTION__ " called\n"));
518 }
520 NTSTATUS
521 DriverEntry(
522 PDRIVER_OBJECT DriverObject,
523 PUNICODE_STRING RegistryPath
524 )
525 {
526 NTSTATUS status;
527 WDF_DRIVER_CONFIG config;
528 NDIS_HANDLE ndis_wrapper_handle;
529 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
531 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
533 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
534 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
536 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
537 &config, WDF_NO_HANDLE);
538 if (!NT_SUCCESS(status))
539 {
540 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
541 return status;
542 }
544 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
545 if (!ndis_wrapper_handle)
546 {
547 KdPrint(("NdisMInitializeWrapper failed\n"));
548 return NDIS_STATUS_FAILURE;
549 }
551 /* NDIS 5.1 driver */
552 mini_chars.MajorNdisVersion = 5;
553 mini_chars.MinorNdisVersion = 1;
555 mini_chars.HaltHandler = XenNet_Halt;
556 mini_chars.InitializeHandler = XenNet_Init;
557 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
558 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
559 mini_chars.ResetHandler = NULL; //TODO: fill in
560 mini_chars.SetInformationHandler = XenNet_SetInformation;
561 /* added in v.4 -- use multiple pkts interface */
562 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
563 mini_chars.SendPacketsHandler = XenNet_SendPackets;
564 /* added in v.5.1 */
565 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
566 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
568 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
570 /* set up upper-edge interface */
571 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
572 if (!NT_SUCCESS(status))
573 {
574 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
575 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
576 return status;
577 }
579 return status;
580 }