win-pvdrivers

view xennet/xennet.h @ 1099:27bd2a5a4704

License change from GPL to BSD
author James Harper <james.harper@bendigoit.com.au>
date Thu Mar 13 13:38:31 2014 +1100 (2014-03-13)
parents 05ece536b204
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
4 Copyright (c) 2014, James Harper
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of James Harper nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
30 #pragma warning(disable: 4201)
31 #pragma warning(disable: 4214)
33 #include <ntddk.h>
34 #include <wdm.h>
35 #define NDIS_MINIPORT_DRIVER 1
36 #if NTDDI_VERSION < NTDDI_WINXP
37 # define NDIS50_MINIPORT 1
38 #elif NTDDI_VERSION < NTDDI_VISTA
39 # define NDIS51_MINIPORT 1
40 #else
41 # define NDIS61_MINIPORT 1
42 #endif
43 #include <ndis.h>
44 #define NTSTRSAFE_LIB
45 #include <ntstrsafe.h>
46 #include <liblfds.h>
48 #define VENDOR_DRIVER_VERSION_MAJOR 0
49 #define VENDOR_DRIVER_VERSION_MINOR 11
51 #define MAX_LINK_SPEED 10000000000L /* there is not really any theoretical maximum... */
53 #define VENDOR_DRIVER_VERSION (((VENDOR_DRIVER_VERSION_MAJOR) << 16) | (VENDOR_DRIVER_VERSION_MINOR))
55 #define __DRIVER_NAME "XenNet"
57 //#define PACKET_NEXT_PACKET_FIELD MiniportReservedEx[sizeof(PVOID)] // RX & TX
58 //#define PACKET_FIRST_PB_FIELD MiniportReservedEx[0] // RX
59 #define PACKET_NEXT_PACKET_FIELD MiniportReservedEx[0] // RX & TX
60 #define PACKET_FIRST_PB_FIELD MiniportReservedEx[sizeof(PVOID)] // RX
61 #define PACKET_LIST_ENTRY_FIELD MiniportReservedEx[sizeof(PVOID)] // TX (2 entries)
62 #define PACKET_NEXT_PACKET(_packet) (*(PNDIS_PACKET *)&(_packet)->PACKET_NEXT_PACKET_FIELD)
63 #define PACKET_LIST_ENTRY(_packet) (*(PLIST_ENTRY)&(_packet)->PACKET_LIST_ENTRY_FIELD)
64 #define PACKET_FIRST_PB(_packet) (*(shared_buffer_t **)&(_packet)->PACKET_FIRST_PB_FIELD)
66 #define NB_LIST_ENTRY_FIELD MiniportReserved[0] // TX (2 entries)
67 #define NB_FIRST_PB_FIELD MiniportReserved[0] // RX
68 #define NB_NBL_FIELD MiniportReserved[2] // TX
69 #define NB_LIST_ENTRY(_nb) (*(PLIST_ENTRY)&(_nb)->NB_LIST_ENTRY_FIELD)
70 #define NB_NBL(_nb) (*(PNET_BUFFER_LIST *)&(_nb)->NB_NBL_FIELD)
71 #define NB_FIRST_PB(_nb) (*(shared_buffer_t **)&(_nb)->NB_FIRST_PB_FIELD)
73 #define NBL_REF_FIELD MiniportReserved[0] // TX
74 #define NBL_REF(_nbl) (*(ULONG_PTR *)&(_nbl)->NBL_REF_FIELD)
76 #define NDIS_STATUS_RESOURCES_MAX_LENGTH 64
78 #include <xen_windows.h>
79 #include <memory.h>
80 #include <grant_table.h>
81 #include <event_channel.h>
82 #include <hvm/params.h>
83 #include <hvm/hvm_op.h>
84 #include <xen_public.h>
85 #include <io/ring.h>
86 #include <io/netif.h>
87 #include <io/xenbus.h>
88 #include <stdlib.h>
89 #define XENNET_POOL_TAG (ULONG) 'XenN'
91 /* Xen macros use these, so they need to be redefined to Win equivs */
92 #define wmb() KeMemoryBarrier()
93 #define mb() KeMemoryBarrier()
95 #define GRANT_INVALID_REF 0
97 #define NAME_SIZE 64
99 #define ETH_ALEN 6
101 static FORCEINLINE USHORT
102 GET_NET_USHORT(USHORT data) {
103 return (data << 8) | (data >> 8);
104 }
106 static FORCEINLINE USHORT
107 GET_NET_PUSHORT(PVOID pdata) {
108 return (*((PUSHORT)pdata) << 8) | (*((PUSHORT)pdata) >> 8);
109 }
111 static FORCEINLINE VOID
112 SET_NET_USHORT(PVOID ptr, USHORT data) {
113 *((PUSHORT)ptr) = GET_NET_USHORT(data);
114 }
116 static FORCEINLINE ULONG
117 GET_NET_ULONG(ULONG data) {
118 ULONG tmp;
120 tmp = ((data & 0x00ff00ff) << 8) | ((data & 0xff00ff00) >> 8);
121 return (tmp << 16) | (tmp >> 16);
122 }
124 static FORCEINLINE ULONG
125 GET_NET_PULONG(PVOID pdata) {
126 ULONG tmp;
128 tmp = ((*((PULONG)pdata) & 0x00ff00ff) << 8) | ((*((PULONG)pdata) & 0xff00ff00) >> 8);
129 return (tmp << 16) | (tmp >> 16);
130 }
132 static FORCEINLINE VOID
133 SET_NET_ULONG(PVOID ptr, ULONG data) {
134 *((PULONG)ptr) = GET_NET_ULONG(data);
135 }
136 /*
137 #define GET_NET_ULONG(x) ((GET_NET_USHORT(x) << 16) | GET_NET_USHORT(((PUCHAR)&x)[2]))
138 #define SET_NET_ULONG(y, x) *((ULONG *)&(y)) = ((GET_NET_USHORT(x) << 16) | GET_NET_USHORT(((PUCHAR)&x)[2]))
139 */
141 #define SUPPORTED_PACKET_FILTERS (\
142 NDIS_PACKET_TYPE_DIRECTED | \
143 NDIS_PACKET_TYPE_MULTICAST | \
144 NDIS_PACKET_TYPE_BROADCAST | \
145 NDIS_PACKET_TYPE_PROMISCUOUS | \
146 NDIS_PACKET_TYPE_ALL_MULTICAST)
148 /* couldn't get regular xen ring macros to work...*/
149 #define __NET_RING_SIZE(type, _sz) \
150 (__RD32( \
151 (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
152 / sizeof(union type##_sring_entry)))
154 #define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
155 #define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
157 #pragma warning(disable: 4127) // conditional expression is constant
159 #define MIN_LARGE_SEND_SEGMENTS 4
161 /* TODO: crank this up if we support higher mtus? */
162 #define XN_HDR_SIZE 14
163 #define XN_MAX_DATA_SIZE 1500
164 #define XN_MIN_FRAME_SIZE 60
165 #define XN_MAX_FRAME_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
166 /*
167 #if !defined(OFFLOAD_LARGE_SEND)
168 #define XN_MAX_PKT_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
169 #else
170 #define XN_MAX_PKT_SIZE MAX_LARGE_SEND_OFFLOAD
171 #endif
172 */
174 #define XN_MAX_SEND_PKTS 16
176 #define XENSOURCE_MAC_HDR 0x00163E
177 #define XN_VENDOR_DESC "Xensource"
178 #define MAX_XENBUS_STR_LEN 128
180 //#define RX_MIN_TARGET 8
181 #define RX_DEFAULT_TARGET 256
182 //#define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
183 #define RX_MAX_PB_FREELIST (NET_RX_RING_SIZE * 4)
184 #define RX_PACKET_MAX (NET_RX_RING_SIZE * 4)
185 #define RX_PACKET_HIGH_WATER_MARK (RX_PACKET_MAX * 3 / 4)
187 //#define MAX_BUFFERS_PER_PACKET NET_RX_RING_SIZE
189 #define MIN_ETH_HEADER_LENGTH 14
190 #define MAX_ETH_HEADER_LENGTH 14
191 #define MIN_IP4_HEADER_LENGTH 20
192 #define MAX_IP4_HEADER_LENGTH (15 * 4)
193 #define MIN_TCP_HEADER_LENGTH 20
194 #define MAX_TCP_HEADER_LENGTH (15 * 4)
195 #define MAX_PKT_HEADER_LENGTH (MAX_ETH_HEADER_LENGTH + MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
197 #define MIN_LOOKAHEAD_LENGTH (MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
198 //#define MAX_LOOKAHEAD_LENGTH PAGE_SIZE
199 /* optimise the size of header buffers */
200 #define MAX_LOOKAHEAD_LENGTH (512 - sizeof(shared_buffer_t) - MAX_ETH_HEADER_LENGTH)
202 #define LINUX_MAX_SG_ELEMENTS 18
204 #define PAGE_LIST_SIZE (max(NET_RX_RING_SIZE, NET_TX_RING_SIZE) * 4)
205 #define MULTICAST_LIST_MAX_SIZE 32
207 #define TX_HEADER_BUFFER_SIZE 512
208 #define TX_COALESCE_BUFFERS (NET_TX_RING_SIZE)
210 /* split incoming large packets into MSS sized chunks */
211 #define RX_LSO_SPLIT_MSS 0
212 /* split incoming large packets in half, to not invoke the delayed ack timer */
213 #define RX_LSO_SPLIT_HALF 1
214 /* don't split incoming large packets. not really useful */
215 #define RX_LSO_SPLIT_NONE 2
217 #define DEVICE_STATE_DISCONNECTED 0 /* -> INITIALISING */
218 #define DEVICE_STATE_INITIALISING 1 /* -> ACTIVE or INACTIVE */
219 #define DEVICE_STATE_INACTIVE 2
220 #define DEVICE_STATE_ACTIVE 3 /* -> DISCONNECTING */
221 #define DEVICE_STATE_DISCONNECTING 4 /* -> DISCONNECTED */
223 struct _shared_buffer_t;
225 typedef struct _shared_buffer_t shared_buffer_t;
227 struct _shared_buffer_t {
228 struct netif_rx_response rsp;
229 shared_buffer_t *next;
230 grant_ref_t gref;
231 //USHORT offset;
232 PVOID virtual;
233 PMDL mdl;
234 //USHORT id;
235 volatile LONG ref_count;
236 };
238 typedef struct {
239 #if NTDDI_VERSION < NTDDI_VISTA
240 PNDIS_PACKET packet; /* only set on the last packet */
241 #else
242 PNET_BUFFER packet; /* only set on the last packet */
243 #endif
244 PVOID *cb;
245 grant_ref_t gref;
246 } tx_shadow_t;
248 typedef struct {
249 ULONG parse_result;
250 PMDL first_mdl;
251 MDL first_mdl_storage;
252 PPFN_NUMBER first_mdl_pfns[17]; /* maximum possible packet size */
253 PMDL curr_mdl;
254 shared_buffer_t *first_pb;
255 shared_buffer_t *curr_pb;
256 PUCHAR first_mdl_virtual;
257 //ULONG mdl_count;
258 ULONG first_mdl_offset;
259 ULONG first_mdl_length;
260 ULONG curr_mdl_offset;
261 USHORT mss;
262 //NDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
263 BOOLEAN csum_blank;
264 BOOLEAN data_validated;
265 BOOLEAN split_required;
266 UCHAR ip_version;
267 PUCHAR header;
268 ULONG header_length;
269 UCHAR ip_proto;
270 BOOLEAN ip_has_options;
271 ULONG total_length;
272 USHORT ip4_header_length;
273 USHORT ip4_length;
274 USHORT tcp_header_length;
275 BOOLEAN tcp_has_options;
276 USHORT tcp_length;
277 USHORT tcp_remaining;
278 ULONG tcp_seq;
279 BOOLEAN is_multicast;
280 BOOLEAN is_broadcast;
281 /* anything past here doesn't get cleared automatically by the ClearPacketInfo */
282 UCHAR header_data[MAX_LOOKAHEAD_LENGTH + MAX_ETH_HEADER_LENGTH];
283 } packet_info_t;
285 struct xennet_info
286 {
287 ULONG device_state;
289 /* Base device vars */
290 PDEVICE_OBJECT pdo;
291 PDEVICE_OBJECT fdo;
292 PDEVICE_OBJECT lower_do;
293 // WCHAR dev_desc[NAME_SIZE];
295 /* NDIS-related vars */
296 NDIS_HANDLE adapter_handle;
297 ULONG packet_filter;
298 uint8_t perm_mac_addr[ETH_ALEN];
299 uint8_t curr_mac_addr[ETH_ALEN];
300 ULONG current_lookahead;
302 /* Misc. Xen vars */
303 XN_HANDLE handle;
305 evtchn_port_t event_channel;
306 ULONG backend_state;
307 KEVENT backend_event;
308 UCHAR multicast_list[MULTICAST_LIST_MAX_SIZE][6];
309 ULONG multicast_list_size;
310 KDPC rxtx_dpc;
312 /* tx related - protected by tx_lock */
313 KSPIN_LOCK tx_lock; /* always acquire rx_lock before tx_lock */
314 LIST_ENTRY tx_waiting_pkt_list;
315 netif_tx_sring_t *tx_sring;
316 grant_ref_t tx_sring_gref;
317 struct netif_tx_front_ring tx_ring;
318 ULONG tx_ring_free;
319 tx_shadow_t tx_shadows[NET_TX_RING_SIZE];
320 ULONG tx_outstanding;
321 ULONG tx_id_free;
322 USHORT tx_id_list[NET_TX_RING_SIZE];
323 NPAGED_LOOKASIDE_LIST tx_lookaside_list;
324 KEVENT tx_idle_event;
326 /* rx_related - protected by rx_lock */
327 KSPIN_LOCK rx_lock; /* always acquire rx_lock before tx_lock */
328 netif_rx_sring_t *rx_sring;
329 grant_ref_t rx_sring_gref;
330 struct netif_rx_front_ring rx_ring;
331 ULONG rx_id_free;
332 packet_info_t *rxpi;
333 #if NTDDI_VERSION < NTDDI_VISTA
334 #else
335 NDIS_HANDLE rx_nbl_pool;
336 #endif
337 NDIS_HANDLE rx_packet_pool;
338 volatile LONG rx_pb_free;
339 struct stack_state *rx_pb_stack;
340 volatile LONG rx_hb_free;
341 struct stack_state *rx_hb_stack;
342 shared_buffer_t *rx_ring_pbs[NET_RX_RING_SIZE];
343 /* Receive-ring batched refills. */
344 ULONG rx_target;
345 ULONG rx_max_target;
346 ULONG rx_min_target;
347 shared_buffer_t *rx_partial_buf;
348 BOOLEAN rx_partial_extra_info_flag ;
349 BOOLEAN rx_partial_more_data_flag;
350 KEVENT rx_idle_event;
351 /* how many packets are in the net stack atm */
352 LONG rx_outstanding;
355 /* config vars from registry */
356 /* the frontend_* indicate our willingness to support */
357 BOOLEAN frontend_sg_supported;
358 BOOLEAN frontend_csum_supported;
359 ULONG frontend_gso_value;
360 ULONG frontend_mtu_value;
361 ULONG frontend_gso_rx_split_type; /* RX_LSO_SPLIT_* */
363 BOOLEAN backend_sg_supported;
364 BOOLEAN backend_csum_supported;
365 ULONG backend_gso_value;
367 BOOLEAN current_sg_supported;
368 BOOLEAN current_csum_supported;
369 ULONG current_gso_value;
370 ULONG current_mtu_value;
371 ULONG current_gso_rx_split_type;
373 BOOLEAN config_csum_rx_check;
374 BOOLEAN config_csum_rx_dont_fix;
375 BOOLEAN config_rx_coalesce;
377 #if NTDDI_VERSION < NTDDI_VISTA
378 NDIS_TASK_TCP_IP_CHECKSUM setting_csum;
379 #else
380 #endif
382 /* config stuff calculated from the above */
383 ULONG config_max_pkt_size;
385 /* stats */
386 #if NTDDI_VERSION < NTDDI_VISTA
387 ULONG64 stat_tx_ok;
388 ULONG64 stat_rx_ok;
389 ULONG64 stat_tx_error;
390 ULONG64 stat_rx_error;
391 ULONG64 stat_rx_no_buffer;
392 #else
393 NDIS_STATISTICS_INFO stats;
394 #endif
396 } typedef xennet_info_t;
398 extern USHORT ndis_os_major_version;
399 extern USHORT ndis_os_minor_version;
401 typedef NDIS_STATUS (*XEN_OID_REQUEST)(NDIS_HANDLE context, PVOID information_buffer, ULONG information_buffer_length, PULONG bytes_read, PULONG bytes_needed);
403 struct xennet_oids_t {
404 ULONG oid;
405 char *oid_name;
406 ULONG min_length;
407 XEN_OID_REQUEST query_routine;
408 XEN_OID_REQUEST set_routine;
409 };
411 extern struct xennet_oids_t xennet_oids[];
413 #if NTDDI_VERSION < NTDDI_VISTA
414 NDIS_STATUS
415 XenNet_QueryInformation(
416 IN NDIS_HANDLE MiniportAdapterContext,
417 IN NDIS_OID Oid,
418 IN PVOID InformationBuffer,
419 IN ULONG InformationBufferLength,
420 OUT PULONG BytesWritten,
421 OUT PULONG BytesNeeded);
423 NDIS_STATUS
424 XenNet_SetInformation(
425 IN NDIS_HANDLE MiniportAdapterContext,
426 IN NDIS_OID Oid,
427 IN PVOID InformationBuffer,
428 IN ULONG InformationBufferLength,
429 OUT PULONG BytesRead,
430 OUT PULONG BytesNeeded
431 );
433 VOID
434 XenNet_SendPackets(
435 IN NDIS_HANDLE MiniportAdapterContext,
436 IN PPNDIS_PACKET PacketArray,
437 IN UINT NumberOfPackets
438 );
440 VOID
441 XenNet_ReturnPacket(
442 IN NDIS_HANDLE MiniportAdapterContext,
443 IN PNDIS_PACKET Packet
444 );
445 #else
447 MINIPORT_OID_REQUEST XenNet_OidRequest;
448 MINIPORT_CANCEL_OID_REQUEST XenNet_CancelOidRequest;
450 MINIPORT_SEND_NET_BUFFER_LISTS XenNet_SendNetBufferLists;
451 MINIPORT_CANCEL_SEND XenNet_CancelSend;
453 MINIPORT_RETURN_NET_BUFFER_LISTS XenNet_ReturnNetBufferLists;
454 #endif
456 NTSTATUS XenNet_Connect(PVOID context, BOOLEAN suspend);
457 NTSTATUS XenNet_Disconnect(PVOID context, BOOLEAN suspend);
458 VOID XenNet_DeviceCallback(PVOID context, ULONG callback_type, PVOID value);
461 BOOLEAN XenNet_RxInit(xennet_info_t *xi);
462 VOID XenNet_RxShutdown(xennet_info_t *xi);
463 BOOLEAN XenNet_RxBufferCheck(struct xennet_info *xi);
465 BOOLEAN XenNet_TxInit(xennet_info_t *xi);
466 BOOLEAN XenNet_TxShutdown(xennet_info_t *xi);
467 VOID XenNet_TxBufferGC(struct xennet_info *xi, BOOLEAN dont_set_event);
470 /* return values */
471 #define PARSE_OK 0
472 #define PARSE_TOO_SMALL 1 /* first buffer is too small */
473 #define PARSE_UNKNOWN_TYPE 2
475 BOOLEAN XenNet_BuildHeader(packet_info_t *pi, PVOID header, ULONG new_header_size);
476 VOID XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR buffer, ULONG min_header_size);
477 BOOLEAN XenNet_FilterAcceptPacket(struct xennet_info *xi, packet_info_t *pi);
479 BOOLEAN XenNet_CheckIpHeaderSum(PUCHAR header, USHORT ip4_header_length);
480 VOID XenNet_SumIpHeader(PUCHAR header, USHORT ip4_header_length);
482 static __forceinline VOID
483 XenNet_ClearPacketInfo(packet_info_t *pi) {
484 RtlZeroMemory(pi, sizeof(packet_info_t) - FIELD_OFFSET(packet_info_t, header_data));
485 }
487 /* Get some data from the current packet, but don't cross a page boundry. */
488 static __forceinline ULONG
489 XenNet_QueryData(packet_info_t *pi, ULONG length) {
490 ULONG offset_in_page;
492 if (length > MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset)
493 length = MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset;
495 offset_in_page = (MmGetMdlByteOffset(pi->curr_mdl) + pi->curr_mdl_offset) & (PAGE_SIZE - 1);
496 if (offset_in_page + length > PAGE_SIZE)
497 length = PAGE_SIZE - offset_in_page;
499 return length;
500 }
502 /* Move the pointers forward by the given amount. No error checking is done. */
503 static __forceinline VOID
504 XenNet_EatData(packet_info_t *pi, ULONG length) {
505 pi->curr_mdl_offset += length;
506 if (pi->curr_mdl_offset >= MmGetMdlByteCount(pi->curr_mdl)) {
507 pi->curr_mdl_offset -= MmGetMdlByteCount(pi->curr_mdl);
508 #if NTDDI_VERSION < NTDDI_VISTA
509 NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
510 #else
511 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
512 #endif
513 }
514 }