├── src ├── usr.sbin │ └── ndisload │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ndisload.8 │ │ └── ndisload.c ├── sys │ ├── modules │ │ └── ndis │ │ │ ├── .gitignore │ │ │ └── Makefile │ ├── compat │ │ └── ndis │ │ │ ├── loader.h │ │ │ ├── hal_var.h │ │ │ ├── resource_var.h │ │ │ ├── usbd_var.h │ │ │ ├── subr_hal.c │ │ │ ├── winx_wrap.S │ │ │ ├── pe_var.h │ │ │ ├── subr_pe.c │ │ │ ├── kern_windrv.c │ │ │ └── kern_ndis.c │ └── dev │ │ └── if_ndis │ │ ├── if_ndis_usb.c │ │ ├── if_ndisvar.h │ │ ├── if_ndis_pccard.c │ │ └── if_ndis_pci.c └── share │ └── man │ └── man4 │ └── ndis.4 ├── Makefile ├── TODO └── README.md /src/usr.sbin/ndisload/.gitignore: -------------------------------------------------------------------------------- 1 | ndisload 2 | *.o 3 | ndisload.8.gz 4 | -------------------------------------------------------------------------------- /src/sys/modules/ndis/.gitignore: -------------------------------------------------------------------------------- 1 | *.h 2 | *.kld 3 | *.ko 4 | *.o 5 | @ 6 | export_syms 7 | machine 8 | x86 9 | -------------------------------------------------------------------------------- /src/usr.sbin/ndisload/Makefile: -------------------------------------------------------------------------------- 1 | # $FreeBSD$ 2 | 3 | .PATH: ${.CURDIR}/../../sys/compat/ndis 4 | 5 | PROG= ndisload 6 | SRCS= ndisload.c 7 | SRCS+= subr_pe.c 8 | BINDIR= /usr/sbin 9 | 10 | MAN= ndisload.8 11 | 12 | DPADD= ${LIBL} 13 | LDADD= -ll 14 | 15 | CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys/compat/ndis 16 | 17 | .include 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd src/usr.sbin/ndisload && make 3 | cd src/sys/modules/ndis && make 4 | install: 5 | rm -f /boot/kernel/if_ndis.ko /boot/kernel/if_ndis.ko.symbols 6 | cd src/sys/modules/ndis && make install 7 | cd src/usr.sbin/ndisload && make install 8 | clean: 9 | cd src/sys/modules/ndis && make clean 10 | cd src/usr.sbin/ndisload && make clean 11 | load: 12 | cd src/sys/modules/ndis && make load 13 | unload: 14 | cd src/sys/modules/ndis && make unload 15 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | improve/extend ndisload utility: 2 | - adding registry entries 3 | - unloading drivers 4 | - list loaded drivers 5 | 6 | PCMCIA support? Does it work for you? 7 | USB support is broken, additionaly detaching device will panic or deadlock kernel 8 | Auto roaming is broken: if association timeouts we may be in ASSOC state forever - add callout? 9 | Suspend/Resume support? Does device still work after suspend/resume? 10 | Improve and test: wpa_supplicant -Dbsd 11 | Support 6.X NDIS API 12 | -------------------------------------------------------------------------------- /src/sys/modules/ndis/Makefile: -------------------------------------------------------------------------------- 1 | # $FreeBSD$ 2 | 3 | .PATH: ${.CURDIR}/../../compat/ndis 4 | .PATH: ${.CURDIR}/../../dev/if_ndis 5 | 6 | KMOD= ndis 7 | SRCS= subr_pe.c subr_ndis.c subr_hal.c subr_ntoskrnl.c kern_ndis.c 8 | SRCS+= kern_windrv.c subr_usbd.c 9 | SRCS+= device_if.h bus_if.h pci_if.h vnode_if.h opt_usb.h 10 | SRCS+= winx_wrap.S 11 | SRCS+= if_ndis.c if_ndis_pci.c if_ndis_pccard.c if_ndis_usb.c 12 | SRCS+= device_if.h bus_if.h pci_if.h card_if.h 13 | SRCS+= opt_usb.h opt_ndis.h opt_wlan.h 14 | 15 | CFLAGS+=-I${.CURDIR}/../../../sys/dev/if_ndis 16 | CFLAGS+=-I${.CURDIR}/../../../sys/compat/ndis 17 | 18 | CLEANFILES+=@ machine x86 19 | 20 | WERROR= 21 | 22 | .include 23 | -------------------------------------------------------------------------------- /src/usr.sbin/ndisload/ndisload.8: -------------------------------------------------------------------------------- 1 | .\"- 2 | .\" Copyright (c) 2011 Paul B. Mahol 3 | .\" All rights reserved 4 | .\" 5 | .\" Redistribution and use in source and binary forms, with or without 6 | .\" modification, are permitted provided that the following conditions 7 | .\" are met: 8 | .\" 1. Redistributions of source code must retain the above copyright 9 | .\" notice, this list of conditions and the following disclaimer. 10 | .\" 2. Redistributions in binary form must reproduce the above copyright 11 | .\" notice, this list of conditions and the following disclaimer in the 12 | .\" documentation and/or other materials provided with the distribution. 13 | .\" 14 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 | .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 | .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | .\" 25 | .\" $FreeBSD$ 26 | .\" 27 | .Dd November 14, 2011 28 | .Dt NDISLOAD 8 29 | .Os 30 | .Sh NAME 31 | .Nm ndisload 32 | .Nd load 33 | .Tn Windows\[rg] 34 | NDIS driver 35 | .Sh SYNOPSIS 36 | .Nm 37 | .Op Ar /path/to/SYS 38 | .Sh DESCRIPTION 39 | FIXME 40 | .Nm 41 | .Sh SEE ALSO 42 | .Xr ndis 4 , 43 | .Xr kldload 8 44 | .Sh HISTORY 45 | The 46 | .Nm 47 | utility first appeared in 48 | .Fx 10.0 . 49 | .Sh AUTHORS 50 | The 51 | .Nm 52 | utility was written by 53 | .An Paul B. Mahol Aq onemda@gmail.com . 54 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/loader.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2011 Paul B. Mahol 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef _LOADER_H_ 27 | #define _LOADER_H_ 28 | 29 | typedef struct { 30 | void *img; 31 | size_t len; 32 | char bustype; 33 | uint16_t vendor; 34 | uint16_t device; 35 | uint32_t subsys; 36 | char *name; 37 | size_t namelen; 38 | void *devlist; 39 | void *regvals; 40 | } ndis_load_driver_args_t; 41 | 42 | typedef struct { 43 | void *img; 44 | } ndis_unload_driver_args_t; 45 | 46 | typedef struct { 47 | void *img; 48 | char bustype; 49 | uint16_t vendor; 50 | uint16_t device; 51 | uint32_t subsys; 52 | char *name; 53 | size_t namelen; 54 | void *devlist; 55 | void *regvals; 56 | } ndis_list_drivers_args_t; 57 | 58 | #define NDIS_LOAD_DRIVER _IOW('c', 1, ndis_load_driver_args_t) 59 | #define NDIS_UNLOAD_DRIVER _IOW('c', 2, ndis_unload_driver_args_t) 60 | #define NDIS_LIST_DRIVERS _IOR('c', 3, ndis_list_drivers_args_t) 61 | 62 | #endif /* _LOADER_H_ */ 63 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/hal_var.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * $FreeBSD$ 33 | */ 34 | 35 | #ifndef _HAL_VAR_H_ 36 | #define _HAL_VAR_H_ 37 | 38 | extern struct image_patch_table hal_functbl[]; 39 | 40 | void hal_libfini(void); 41 | void hal_libinit(void); 42 | uint8_t KeGetCurrentIrql(void); 43 | uint8_t KfAcquireSpinLock(unsigned long *); 44 | void KfLowerIrql(uint8_t); 45 | uint8_t KfRaiseIrql(uint8_t); 46 | void KfReleaseSpinLock(unsigned long *, uint8_t); 47 | 48 | #endif /* _HAL_VAR_H_ */ 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## NDISulator 2 | NDISulator is a FreeBSD kernel module + userland tool which make it possible to use MS Windows network card drivers in FreeBSD. 3 | This software has some fixes and improvements comparing to ndis module available in FreeBSD base system. 4 | 5 | This software supports NDIS version 5.1 what means it can be used with Windows XP and Windows Server 2000/2003 drivers. 6 | 7 | ### Requirements 8 | * make sure you use recent **FreeBSD CURRENT** kernel and world (this git branch last tested at **10 Aug 2015** with **FreeBSD 11.0-CURRENT r286579**) 9 | * make sure FreeBSD source tree is available in /usr/src 10 | * make sure you use the same "arch" of MS Windows drivers as your FreeBSD installation (i.e. 64 bit driver for amd64 case; 32 bit driver for i386 case) 11 | 12 | ### Git branches 13 | Please select proper ndisulator branch for your FreeBSD system: 14 | - **master** branch is intended to be used with **FreeBSD CURRENT** 15 | - **freebsd-10-stable** branch is intended to be used with **FreeBSD 10-STABLE** 16 | - **freebsd-9-stable** branch is intended to be used with **FreeBSD 9-STABLE** 17 | 18 | ### How to use: 19 | * To build NDISulator you have to run: 20 | ``` 21 | make 22 | ``` 23 | 24 | * To install NDISulator (**ndis** kernel module + **ndisload** binary) you have to run as root: 25 | ``` 26 | make install 27 | ``` 28 | 29 | * To load ndis kernel module you have to run following command as root: 30 | ``` 31 | kldload ndis 32 | ``` 33 | 34 | * To load windows miniport driver (.sys file) you have to use **ndisload** binary (there is no need to generate kernel module based on .inf + .sys files like it is necessary for ndis from FreeBSD base system) 35 | ``` 36 | ndisload [-p|-u|-P -s -n -v -d ] 37 | ndisload flags: 38 | -p = PCI device 39 | -u = USB device 40 | -P = PCMCIA device 41 | -s PATH = path to windows miniport driver (.sys file) 42 | -n NAME = device name (any name you like) 43 | -v VENDOR_ID = last 4 hex digits of "chip" value in "pciconf" output 44 | -d DEVICE_ID = first 4 hex digits of "chip" value in "pciconf" output 45 | ``` 46 | Don't forget to add "0x" prefix if you just copying vendor/device id values from pciconf output 47 | 48 | **Example of ndisload use:** 49 | ``` 50 | none@pci0:0:3:0: class=0x020000 card=0x11001af4 chip=0x813910ec rev=0x20 hdr=0x00 51 | vendor = 'Realtek Semiconductor Co., Ltd.' 52 | device = 'RTL-8139/8139C/8139C+' 53 | class = network 54 | subclass = ethernet 55 | ``` 56 | Correct ndisload command for device above: 57 | ``` 58 | ndisload -p -s /root/rl8139/Rtnic64.sys -n test_dev -v 0x10ec -d 0x8139 59 | ``` 60 | 61 | * If all steps completed successfully at this point you should see new interface named **ndis0** 62 | 63 | 64 | ### How to revert to stock ndis: 65 | ``` 66 | rm -f /usr/sbin/ndisload /usr/share/man/man8/ndisload.8.gz 67 | cd /usr/src/sys/modules/ndis && make && make install && make cleandir 68 | cd /usr/src/sys/modules/if_ndis && make && make install && make cleandir 69 | cd /usr/src/usr.sbin/ndiscvt && make && make install && make cleandir 70 | ``` 71 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/resource_var.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * $FreeBSD$ 33 | */ 34 | 35 | #ifndef _RESOURCE_VAR_H_ 36 | #define _RESOURCE_VAR_H_ 37 | 38 | #define CmResourceTypeNull 0 39 | #define CmResourceTypePort 1 40 | #define CmResourceTypeInterrupt 2 41 | #define CmResourceTypeMemory 3 42 | #define CmResourceTypeDma 4 43 | #define CmResourceTypeDeviceSpecific 5 44 | #define CmResourceTypeBusNumber 6 45 | #define CmResourceTypeMaximum 7 46 | #define CmResourceTypeNonArbitrated 128 47 | #define CmResourceTypeConfigData 128 48 | #define CmResourceTypeDevicePrivate 129 49 | #define CmResourceTypePcCardConfig 130 50 | 51 | enum cm_share_disposition { 52 | CM_RESOURCE_SHARE_UNDETERMINED = 0, 53 | CM_RESOURCE_SHARE_DEVICE_EXCLUSIVE, 54 | CM_RESOURCE_SHARE_DRIVER_EXCLUSIVE, 55 | CM_RESOURCE_SHARE_SHARED 56 | }; 57 | 58 | /* Define the bit masks for Flags when type is CmResourceTypeInterrupt */ 59 | #define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 60 | #define CM_RESOURCE_INTERRUPT_LATCHED 1 61 | 62 | /* Define the bit masks for Flags when type is CmResourceTypeMemory */ 63 | #define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 64 | #define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 65 | #define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 66 | #define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 67 | #define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 68 | #define CM_RESOURCE_MEMORY_24 0x0010 69 | #define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 70 | 71 | /* Define the bit masks for Flags when type is CmResourceTypePort */ 72 | #define CM_RESOURCE_PORT_MEMORY 0x0000 73 | #define CM_RESOURCE_PORT_IO 0x0001 74 | #define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 75 | #define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 76 | #define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 77 | #define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 78 | #define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 79 | #define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 80 | 81 | /* Define the bit masks for Flags when type is CmResourceTypeDma */ 82 | #define CM_RESOURCE_DMA_8 0x0000 83 | #define CM_RESOURCE_DMA_16 0x0001 84 | #define CM_RESOURCE_DMA_32 0x0002 85 | #define CM_RESOURCE_DMA_8_AND_16 0x0004 86 | #define CM_RESOURCE_DMA_BUS_MASTER 0x0008 87 | #define CM_RESOURCE_DMA_TYPE_A 0x0010 88 | #define CM_RESOURCE_DMA_TYPE_B 0x0020 89 | #define CM_RESOURCE_DMA_TYPE_F 0x0040 90 | 91 | struct cm_partial_resource_desc { 92 | uint8_t type; 93 | uint8_t sharedisp; 94 | uint16_t flags; 95 | union { 96 | struct { 97 | uint64_t start; 98 | uint32_t len; 99 | } generic; 100 | struct { 101 | uint64_t start; 102 | uint32_t len; 103 | } port; 104 | struct { 105 | uint32_t level; 106 | uint32_t vector; 107 | uint32_t affinity; 108 | } intr; 109 | struct { 110 | uint64_t start; 111 | uint32_t len; 112 | } mem; 113 | struct { 114 | uint32_t chan; 115 | uint32_t port; 116 | uint32_t rsvd; 117 | } dmachan; 118 | struct { 119 | uint32_t data[3]; 120 | } devpriv; 121 | struct { 122 | uint32_t datasize; 123 | uint32_t rsvd1; 124 | uint32_t rsvd2; 125 | } devspec; 126 | } u __attribute__((packed)); 127 | }; 128 | 129 | struct cm_partial_resource_list { 130 | uint16_t version; 131 | uint16_t revision; 132 | uint32_t count; 133 | struct cm_partial_resource_desc partial_descs[1]; 134 | }; 135 | 136 | struct cm_full_resource_list { 137 | uint32_t type; 138 | uint32_t busnum; 139 | struct cm_partial_resource_desc partiallist; 140 | }; 141 | 142 | struct cm_resource_list { 143 | uint32_t count; 144 | struct cm_full_resource_list rlist; 145 | }; 146 | 147 | #endif /* _RESOURCE_VAR_H_ */ 148 | -------------------------------------------------------------------------------- /src/share/man/man4/ndis.4: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2003 2 | .\" Bill Paul . All rights reserved. 3 | .\" 4 | .\" Redistribution and use in source and binary forms, with or without 5 | .\" modification, are permitted provided that the following conditions 6 | .\" are met: 7 | .\" 1. Redistributions of source code must retain the above copyright 8 | .\" notice, this list of conditions and the following disclaimer. 9 | .\" 2. Redistributions in binary form must reproduce the above copyright 10 | .\" notice, this list of conditions and the following disclaimer in the 11 | .\" documentation and/or other materials provided with the distribution. 12 | .\" 3. All advertising materials mentioning features or use of this software 13 | .\" must display the following acknowledgement: 14 | .\" This product includes software developed by Bill Paul. 15 | .\" 4. Neither the name of the author nor the names of any co-contributors 16 | .\" may be used to endorse or promote products derived from this software 17 | .\" without specific prior written permission. 18 | .\" 19 | .\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 20 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | .\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 23 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29 | .\" THE POSSIBILITY OF SUCH DAMAGE. 30 | .\" 31 | .\" $FreeBSD$ 32 | .\" 33 | .Dd February 8, 2010 34 | .Dt NDIS 4 35 | .Os 36 | .Sh NAME 37 | .Nm ndis 38 | .Nd NDIS miniport driver wrapper 39 | .Sh SYNOPSIS 40 | To compile this driver into the kernel, 41 | place the following lines in your 42 | kernel configuration file: 43 | .Bd -ragged -offset indent 44 | .Cd "options NDISAPI" 45 | .Cd "device ndis" 46 | .Cd "device pccard" 47 | .Cd "device usb" 48 | .Cd "device wlan" 49 | .Ed 50 | .Pp 51 | Alternatively, to load the driver as a 52 | module at boot time, place the following line in 53 | .Xr loader.conf 5 : 54 | .Bd -literal -offset indent 55 | if_ndis_load="YES" 56 | .Ed 57 | .Sh DESCRIPTION 58 | The 59 | .Nm 60 | driver is a wrapper designed to allow binary 61 | .Tn Windows\[rg] 62 | NDIS miniport 63 | network drivers to be used with 64 | .Fx . 65 | The 66 | .Nm 67 | driver is provided in source code form and must be combined with 68 | the 69 | .Tn Windows\[rg] 70 | driver supplied with your network adapter. 71 | The 72 | .Nm 73 | driver uses the 74 | .Nm ndisapi 75 | kernel subsystem to relocate and link the 76 | .Tn Windows\[rg] 77 | binary so 78 | that it can be used in conjunction with native code. 79 | The 80 | .Nm ndisapi 81 | subsystem provides an interface between the NDIS API and the 82 | .Fx 83 | networking infrastructure. 84 | The 85 | .Tn Windows\[rg] 86 | driver is essentially 87 | fooled into thinking it is running on 88 | .Tn Windows\[rg] . 89 | Note that this 90 | means the 91 | .Nm 92 | driver is only useful on x86 machines. 93 | .Pp 94 | To build a functional driver, the user must have a copy of the 95 | driver distribution media for his or her card. 96 | From this distribution, 97 | the user must extract two files: the 98 | .Pa .SYS 99 | file containing the driver 100 | binary code, and its companion 101 | .Pa .INF 102 | file, which contains the 103 | definitions for driver-specific registry keys and other installation 104 | data such as device identifiers. 105 | These two files can be converted 106 | into a kernel module file using the 107 | .Xr ndisgen 8 108 | utility. 109 | This file contains a binary image of the driver plus 110 | registry key data. 111 | When the 112 | .Nm 113 | driver loads, it will create 114 | .Xr sysctl 3 115 | nodes for each registry key extracted from the 116 | .Pa .INF 117 | file. 118 | .Pp 119 | The 120 | .Nm 121 | driver is designed to support mainly Ethernet and wireless 122 | network devices with PCI, PCMCIA and USB bus attachments. 123 | (Cardbus 124 | devices are also supported as a subset of PCI.) 125 | It can 126 | support many different media types and speeds. 127 | One limitation 128 | however, is that there is no consistent way to learn if an 129 | Ethernet device is operating in full or half duplex mode. 130 | The NDIS API allows for a generic means for determining link 131 | state and speed, but not the duplex setting. 132 | There may be 133 | driver-specific registry keys to control the media setting 134 | which can be configured via the 135 | .Xr sysctl 8 136 | command. 137 | .Pp 138 | The 139 | .Nm 140 | driver supports 141 | .Cm station 142 | and 143 | .Cm adhoc 144 | mode operation. 145 | Only one virtual interface may be configured at any time. 146 | For more information on configuring this device, see 147 | .Xr ifconfig 8 . 148 | .Sh DIAGNOSTICS 149 | .Bl -diag 150 | .It "ndis%d: watchdog timeout" 151 | A packet was queued for transmission and a transmit command was 152 | issued, however the device failed to acknowledge the transmission 153 | before a timeout expired. 154 | .El 155 | .Sh EXAMPLES 156 | Join a specific BSS network with WEP encryption: 157 | .Bd -literal -offset indent 158 | ifconfig wlan0 create wlandev ndis0 159 | ifconfig wlan0 inet 192.168.0.20 netmask 0xffffff00 ssid my_net \e 160 | wepmode on wepkey 0x8736639624 weptxkey 1 up 161 | .Ed 162 | .Pp 163 | Join/create an 802.11 IBSS network with network name 164 | .Dq Li my_net : 165 | .Bd -literal -offset indent 166 | ifconfig wlan0 create wlandev ndis0 wlanmode adhoc 167 | ifconfig wlan0 inet 192.168.0.22 netmask 0xffffff00 ssid my_net up 168 | .Ed 169 | .Sh SEE ALSO 170 | .Xr altq 4 , 171 | .Xr arp 4 , 172 | .Xr ifconfig 8 , 173 | .Xr intro 4 , 174 | .Xr ndiscvt 8 , 175 | .Xr ndisgen 8 , 176 | .Xr netintro 4 , 177 | .Xr ng_ether 4 , 178 | .Xr pccard 4 , 179 | .Xr pci 4 , 180 | .Xr usb 4 , 181 | .Xr wlan 4 , 182 | .Xr wpa_supplicant 8 183 | .Rs 184 | .%T "NDIS 5.1 specification" 185 | .%U http://www.microsoft.com 186 | .Re 187 | .Sh HISTORY 188 | The 189 | .Nm 190 | device driver first appeared in 191 | .Fx 5.3 . 192 | .Sh AUTHORS 193 | The 194 | .Nm 195 | driver was written by 196 | .An Bill Paul Aq wpaul@windriver.com . 197 | -------------------------------------------------------------------------------- /src/sys/dev/if_ndis/if_ndis_usb.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include "pe_var.h" 58 | #include "resource_var.h" 59 | #include "ntoskrnl_var.h" 60 | #include "ndis_var.h" 61 | #include "usbd_var.h" 62 | #include "if_ndisvar.h" 63 | 64 | MODULE_DEPEND(ndis, usb, 1, 1, 1); 65 | 66 | static int ndis_attach_usb(device_t); 67 | static int ndis_detach_usb(device_t); 68 | static int ndis_devcompare_usb(enum ndis_bus_type, 69 | struct ndis_device_type *, device_t); 70 | static int ndis_probe_usb(device_t); 71 | static struct resource_list *ndis_get_resource_list(device_t, device_t); 72 | 73 | static device_method_t ndis_usb_methods[] = { 74 | DEVMETHOD(device_probe, ndis_probe_usb), 75 | DEVMETHOD(device_attach, ndis_attach_usb), 76 | DEVMETHOD(device_detach, ndis_detach_usb), 77 | DEVMETHOD(device_shutdown, ndis_shutdown), 78 | DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 79 | DEVMETHOD_END 80 | }; 81 | 82 | driver_t ndis_usb_driver = { 83 | "ndis", 84 | ndis_usb_methods, 85 | sizeof(struct ndis_softc) 86 | }; 87 | 88 | DRIVER_MODULE(ndis, uhub, ndis_usb_driver, ndis_devclass, ndisdrv_modevent, 0); 89 | 90 | static int 91 | ndis_devcompare_usb(enum ndis_bus_type bustype, 92 | struct ndis_device_type *t, device_t dev) 93 | { 94 | struct usb_attach_arg *uaa; 95 | 96 | if (bustype != NDIS_PNPBUS) 97 | return (FALSE); 98 | 99 | uaa = device_get_ivars(dev); 100 | for (; t->name != NULL; t++) { 101 | if ((uaa->info.idVendor == t->vendor) && 102 | (uaa->info.idProduct == t->device)) { 103 | device_set_desc(dev, t->name); 104 | return (TRUE); 105 | } 106 | } 107 | 108 | return (FALSE); 109 | } 110 | 111 | static int 112 | ndis_probe_usb(device_t dev) 113 | { 114 | struct usb_attach_arg *uaa; 115 | struct drvdb_ent *db; 116 | 117 | uaa = device_get_ivars(dev); 118 | if (uaa->usb_mode != USB_MODE_HOST || 119 | uaa->info.bConfigIndex != NDISUSB_CONFIG_NO || 120 | uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX || 121 | windrv_lookup(0, "USB Bus") == NULL) 122 | return (ENXIO); 123 | 124 | db = windrv_match((matchfuncptr)ndis_devcompare_usb, dev); 125 | if (db == NULL) 126 | return (ENXIO); 127 | uaa->driver_ivar = db; 128 | 129 | return (0); 130 | } 131 | 132 | static int 133 | ndis_attach_usb(device_t dev) 134 | { 135 | const struct drvdb_ent *db; 136 | struct ndisusb_softc *dummy; 137 | struct usb_attach_arg *uaa; 138 | struct ndis_softc *sc; 139 | struct ndis_device_type *t; 140 | struct driver_object *drv; 141 | int devidx = 0; 142 | 143 | device_set_usb_desc(dev); 144 | dummy = device_get_softc(dev); 145 | uaa = device_get_ivars(dev); 146 | db = uaa->driver_ivar; 147 | sc = (struct ndis_softc *)dummy; 148 | sc->ndis_dev = dev; 149 | mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF); 150 | sc->ndis_dobj = db->windrv_object; 151 | sc->ndis_regvals = db->windrv_regvals; 152 | sc->ndis_bus_type = NDIS_PNPBUS; 153 | sc->ndisusb_dev = uaa->device; 154 | 155 | drv = windrv_lookup(0, "USB Bus"); 156 | windrv_create_pdo(drv, dev); 157 | 158 | /* Figure out exactly which device we matched. */ 159 | for (t = db->windrv_devlist; t->name != NULL; t++, devidx++) { 160 | if ((uaa->info.idVendor == t->vendor) && 161 | (uaa->info.idProduct == t->device)) { 162 | sc->ndis_devidx = devidx; 163 | break; 164 | } 165 | } 166 | 167 | if (ndis_attach(dev) != 0) 168 | return (ENXIO); 169 | 170 | return (0); 171 | } 172 | 173 | static int 174 | ndis_detach_usb(device_t dev) 175 | { 176 | struct ndis_softc *sc; 177 | struct ndisusb_ep *ne; 178 | int i; 179 | 180 | sc = device_get_softc(dev); 181 | sc->ndisusb_status |= NDISUSB_STATUS_DETACH; 182 | 183 | ndis_pnp_event_nic(sc, NDIS_DEVICE_PNP_EVENT_SURPRISE_REMOVED, 0); 184 | 185 | if (sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP) { 186 | usbd_transfer_unsetup(sc->ndisusb_dread_ep.ne_xfer, 1); 187 | usbd_transfer_unsetup(sc->ndisusb_dwrite_ep.ne_xfer, 1); 188 | } 189 | for (i = 0; i < NDISUSB_ENDPT_MAX; i++) { 190 | ne = &sc->ndisusb_ep[i]; 191 | usbd_transfer_unsetup(ne->ne_xfer, 1); 192 | } 193 | 194 | ndis_detach(dev); 195 | 196 | mtx_destroy(&sc->ndisusb_mtx); 197 | return (0); 198 | } 199 | 200 | static struct resource_list * 201 | ndis_get_resource_list(device_t dev, device_t child) 202 | { 203 | struct ndis_softc *sc; 204 | 205 | sc = device_get_softc(dev); 206 | return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev)); 207 | } 208 | -------------------------------------------------------------------------------- /src/sys/dev/if_ndis/if_ndisvar.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * $FreeBSD$ 33 | */ 34 | 35 | #ifndef _IF_NDISVAR_H_ 36 | #define _IF_NDISVAR_H_ 37 | 38 | #include 39 | 40 | extern devclass_t ndis_devclass; 41 | 42 | int ndis_attach(device_t); 43 | int ndis_detach(device_t); 44 | int ndis_resume(device_t); 45 | int ndis_shutdown(device_t); 46 | int ndis_suspend(device_t); 47 | int ndisdrv_modevent(module_t, int, void *); 48 | void ndis_free_amem(void *); 49 | 50 | struct ndis_oid_data { /* For setting/getting OIDs from userspace. */ 51 | uint32_t oid; 52 | uint32_t len; 53 | }; 54 | 55 | struct ndis_shmem { 56 | struct list_entry ndis_list; 57 | bus_dma_tag_t ndis_stag; 58 | bus_dmamap_t ndis_smap; 59 | void *ndis_saddr; 60 | uint64_t ndis_paddr; 61 | }; 62 | 63 | struct ndis_cfglist { 64 | struct ndis_cfg ndis_cfg; 65 | struct sysctl_oid *ndis_oid; 66 | TAILQ_ENTRY(ndis_cfglist) link; 67 | }; 68 | TAILQ_HEAD(nch, ndis_cfglist); 69 | 70 | #define NDIS_INITIALIZED(sc) (sc->ndis_block->device_ctx != NULL) 71 | #define NDIS_80211(sc) \ 72 | sc->ndis_physical_medium == NDIS_PHYSICAL_MEDIUM_WIRELESS_LAN 73 | 74 | #define NDIS_NEXT_TXIDX(x) ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts 75 | 76 | #define NDIS_EVENTS 4 77 | #define NDIS_EVTINC(x) (x) = ((x) + 1) % NDIS_EVENTS 78 | 79 | struct ndis_evt { 80 | uint32_t ne_sts; 81 | uint32_t ne_len; 82 | char *ne_buf; 83 | }; 84 | 85 | struct ndis_vap { 86 | struct ieee80211vap vap; 87 | int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); 88 | }; 89 | 90 | #define NDIS_VAP(vap) ((struct ndis_vap *)(vap)) 91 | 92 | #define NDIS_PACKET_TX_TIMEOUT 5 93 | 94 | #define NDISUSB_CONFIG_NO 0 95 | #define NDISUSB_IFACE_INDEX 0 96 | 97 | struct ndisusb_ep { 98 | struct usb_xfer *ne_xfer[1]; 99 | struct list_entry ne_active; 100 | struct list_entry ne_pending; 101 | unsigned long ne_lock; 102 | uint8_t ne_dirin; 103 | }; 104 | 105 | struct ndisusb_xfer { 106 | struct ndisusb_ep *nx_ep; 107 | void *nx_priv; 108 | uint8_t *nx_urbbuf; 109 | uint32_t nx_urbactlen; 110 | uint32_t nx_urblen; 111 | uint8_t nx_shortxfer; 112 | struct list_entry nx_next; 113 | }; 114 | 115 | struct ndisusb_xferdone { 116 | struct ndisusb_xfer *nd_xfer; 117 | usb_error_t nd_status; 118 | struct list_entry nd_donelist; 119 | }; 120 | 121 | struct ndisusb_task { 122 | unsigned nt_type; 123 | #define NDISUSB_TASK_TSTART 0 124 | #define NDISUSB_TASK_IRPCANCEL 1 125 | #define NDISUSB_TASK_VENDOR 2 126 | void *nt_ctx; 127 | struct list_entry nt_tasklist; 128 | }; 129 | 130 | struct ndis_softc { 131 | struct ifnet *ndis_ifp; 132 | struct ifmedia ifmedia; /* media info */ 133 | u_long ndis_hwassist; 134 | uint32_t ndis_v4tx; 135 | uint32_t ndis_v4rx; 136 | bus_space_handle_t ndis_bhandle; 137 | bus_space_tag_t ndis_btag; 138 | void *ndis_intrhand; 139 | struct resource *ndis_irq; 140 | struct resource *ndis_res; 141 | struct resource *ndis_res_io; 142 | int ndis_io_rid; 143 | struct resource *ndis_res_mem; 144 | int ndis_mem_rid; 145 | struct resource *ndis_res_altmem; 146 | int ndis_altmem_rid; 147 | struct resource *ndis_res_am; 148 | int ndis_am_rid; 149 | struct resource *ndis_res_cm; 150 | struct resource_list ndis_rl; 151 | uint32_t ndis_rescnt; 152 | struct mtx ndis_mtx; 153 | device_t ndis_dev; 154 | struct ndis_miniport_block *ndis_block; 155 | struct ndis_miniport_characteristics *ndis_chars; 156 | struct callout ndis_scan_callout; 157 | struct callout ndis_stat_callout; 158 | uint32_t ndis_maxpkts; 159 | uint32_t ndis_txidx; 160 | uint32_t ndis_txpending; 161 | struct ndis_packet **ndis_txarray; 162 | struct ndis_packet_pool *ndis_txpool; 163 | uint8_t ndis_sc; 164 | struct ndis_cfg *ndis_regvals; 165 | struct nch ndis_cfglist_head; 166 | enum ndis_physical_medium ndis_physical_medium; 167 | uint32_t ndis_devidx; 168 | enum ndis_bus_type ndis_bus_type; 169 | struct driver_object *ndis_dobj; 170 | struct io_workitem *ndis_tickitem; 171 | struct io_workitem *ndis_startitem; 172 | struct io_workitem *ndis_resetitem; 173 | struct io_workitem *ndis_inputitem; 174 | struct nt_kdpc ndis_rxdpc; 175 | bus_dma_tag_t ndis_parent_tag; 176 | struct list_entry ndis_shlist; 177 | bus_dma_tag_t ndis_mtag; 178 | bus_dma_tag_t ndis_ttag; 179 | bus_dmamap_t *ndis_mmaps; 180 | bus_dmamap_t *ndis_tmaps; 181 | uint32_t ndis_mmapcnt; 182 | struct ndis_evt ndis_evt[NDIS_EVENTS]; 183 | uint32_t ndis_evtpidx; 184 | uint32_t ndis_evtcidx; 185 | struct ifqueue ndis_rxqueue; 186 | unsigned long ndis_rxlock; 187 | 188 | int (*ndis_newstate)(struct ieee80211com *, 189 | enum ieee80211_state, int); 190 | uint8_t ndis_tx_timer; 191 | uint32_t ndis_hang_timer; 192 | 193 | struct usb_device *ndisusb_dev; 194 | struct mtx ndisusb_mtx; 195 | struct ndisusb_ep ndisusb_dread_ep; 196 | struct ndisusb_ep ndisusb_dwrite_ep; 197 | #define NDISUSB_GET_ENDPT(addr) \ 198 | ((UE_GET_DIR(addr) >> 7) | (UE_GET_ADDR(addr) << 1)) 199 | #define NDISUSB_ENDPT_MAX ((UE_ADDR + 1) * 2) 200 | struct ndisusb_ep ndisusb_ep[NDISUSB_ENDPT_MAX]; 201 | struct io_workitem *ndisusb_xferdoneitem; 202 | struct list_entry ndisusb_xferdonelist; 203 | unsigned long ndisusb_xferdonelock; 204 | struct io_workitem *ndisusb_taskitem; 205 | struct list_entry ndisusb_tasklist; 206 | unsigned long ndisusb_tasklock; 207 | int ndisusb_status; 208 | #define NDISUSB_STATUS_DETACH 0x1 209 | #define NDISUSB_STATUS_SETUP_EP 0x2 210 | }; 211 | 212 | #define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx) 213 | #define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx) 214 | #define NDIS_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->ndis_mtx, t) 215 | #define NDISUSB_LOCK(_sc) mtx_lock(&(_sc)->ndisusb_mtx) 216 | #define NDISUSB_UNLOCK(_sc) mtx_unlock(&(_sc)->ndisusb_mtx) 217 | #define NDISUSB_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->ndisusb_mtx, t) 218 | 219 | #endif /* _IF_NDISVAR_H_ */ 220 | -------------------------------------------------------------------------------- /src/usr.sbin/ndisload/ndisload.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2011 Paul B. Mahol 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | __FBSDID("$FreeBSD$"); 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "pe_var.h" 39 | #include "loader.h" 40 | 41 | static void 42 | usage(void) 43 | { 44 | fprintf(stderr, "Usage: ndisload -p -s -n -v -d [-f ]\n"); 45 | fprintf(stderr, " ndisload -P -s -n -v -d [-f ]\n"); 46 | fprintf(stderr, " ndisload -u -s -n -v -d [-f ]\n"); 47 | 48 | exit(1); 49 | } 50 | 51 | /* 52 | * Sections within Windows PE files are defined using virtual 53 | * and physical address offsets and virtual and physical sizes. 54 | * The physical values define how the section data is stored in 55 | * the executable file while the virtual values describe how the 56 | * sections will look once loaded into memory. It happens that 57 | * the linker in the Microsoft(r) DDK will tend to generate 58 | * binaries where the virtual and physical values are identical, 59 | * which means in most cases we can just transfer the file 60 | * directly to memory without any fixups. This is not always 61 | * the case though, so we have to be prepared to handle files 62 | * where the in-memory section layout differs from the disk file 63 | * section layout. 64 | * 65 | * There are two kinds of variations that can occur: the relative 66 | * virtual address of the section might be different from the 67 | * physical file offset, and the virtual section size might be 68 | * different from the physical size (for example, the physical 69 | * size of the .data section might be 1024 bytes, but the virtual 70 | * size might be 1384 bytes, indicating that the data section should 71 | * actually use up 1384 bytes in RAM and be padded with zeros). What we 72 | * do is read the original file into memory and then make an in-memory 73 | * copy with all of the sections relocated, re-sized and zero padded 74 | * according to the virtual values specified in the section headers. 75 | * We then emit the fixed up image file for use by the if_ndis driver. 76 | * This way, we don't have to do the fixups inside the kernel. 77 | */ 78 | 79 | #define ROUND_DOWN(n, align) (((uintptr_t)n) & ~((align) - 1l)) 80 | #define ROUND_UP(n, align) ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \ 81 | (align)) 82 | static int 83 | insert_padding(void **imgbase, size_t *imglen) 84 | { 85 | struct image_section_header *sect_hdr; 86 | struct image_optional_header *opt_hdr; 87 | int ret, i, sections, curlen, offaccum = 0, oldraddr, oldrlen; 88 | uint8_t *newimg, *tmp; 89 | 90 | newimg = malloc(*imglen); 91 | if (newimg == NULL) 92 | return (ENOMEM); 93 | 94 | bcopy(*imgbase, newimg, *imglen); 95 | curlen = *imglen; 96 | 97 | if ((ret = pe_validate_header((vm_offset_t)newimg)) < 0) { 98 | free(newimg); 99 | return (ret); 100 | } 101 | sections = pe_numsections((vm_offset_t)newimg); 102 | pe_get_optional_header((vm_offset_t)newimg, &opt_hdr); 103 | pe_get_section_header((vm_offset_t)newimg, §_hdr); 104 | 105 | for (i = 0; i < sections; i++) { 106 | oldraddr = sect_hdr->pointer_to_raw_data; 107 | oldrlen = sect_hdr->size_of_raw_data; 108 | sect_hdr->pointer_to_raw_data = sect_hdr->virtual_address; 109 | offaccum += ROUND_UP(sect_hdr->virtual_address - oldraddr, 110 | opt_hdr->file_aligment); 111 | offaccum += ROUND_UP(sect_hdr->misc.virtual_size, 112 | opt_hdr->file_aligment) - 113 | ROUND_UP(sect_hdr->size_of_raw_data, 114 | opt_hdr->file_aligment); 115 | tmp = realloc(newimg, *imglen + offaccum); 116 | if (tmp == NULL) { 117 | free(newimg); 118 | return (ENOMEM); 119 | } 120 | newimg = tmp; 121 | pe_get_section_header((vm_offset_t)newimg, §_hdr); 122 | sect_hdr += i; 123 | bzero(newimg + sect_hdr->pointer_to_raw_data, 124 | ROUND_UP(sect_hdr->misc.virtual_size, 125 | opt_hdr->file_aligment)); 126 | bcopy((uint8_t *)(*imgbase) + oldraddr, 127 | newimg + sect_hdr->pointer_to_raw_data, oldrlen); 128 | sect_hdr++; 129 | } 130 | 131 | free(*imgbase); 132 | 133 | *imgbase = newimg; 134 | *imglen += offaccum; 135 | 136 | return (0); 137 | } 138 | 139 | static int 140 | load_file(char *filename, ndis_load_driver_args_t *driver) 141 | { 142 | FILE *fp; 143 | size_t size; 144 | void *image; 145 | int ret; 146 | 147 | fp = fopen(filename, "r"); 148 | if (fp == NULL) 149 | err(-1, "open(%s)", filename); 150 | fseek(fp, 0L, SEEK_END); 151 | size = ftell(fp); 152 | rewind(fp); 153 | image = calloc(size, 1); 154 | if (image == NULL) 155 | err(-1, "calloc(%zu)", size); 156 | fread(image, size, 1, fp); 157 | fclose(fp); 158 | 159 | ret = insert_padding(&image, &size); 160 | if (ret) { 161 | fprintf(stderr, "section relocation failed\n"); 162 | } else { 163 | driver->img = image; 164 | driver->len = size; 165 | } 166 | return (ret); 167 | } 168 | 169 | static void 170 | load_driver(char *filename, ndis_load_driver_args_t *driver) 171 | { 172 | int fd, ret; 173 | 174 | if (load_file(filename, driver)) 175 | err(-1, "failed to load file"); 176 | fd = open("/dev/ndis", O_RDONLY); 177 | if (fd < 0) 178 | err(-1, "ndis module not loaded"); 179 | ret = ioctl(fd, NDIS_LOAD_DRIVER, driver); 180 | if (ret < 0) 181 | err(-1, "loading driver failed"); 182 | close(fd); 183 | } 184 | 185 | int 186 | main(int argc, char *argv[]) 187 | { 188 | int ch; 189 | char *sysfile = NULL, *firmfile = NULL; 190 | char bustype; 191 | ndis_load_driver_args_t driver; 192 | 193 | bzero(&driver, sizeof(driver)); 194 | 195 | while ((ch = getopt(argc, argv, "s:f:pPuv:d:n:")) != -1) { 196 | switch (ch) { 197 | case 's': 198 | sysfile = optarg; 199 | break; 200 | case 'f': 201 | firmfile = optarg; 202 | break; 203 | case 'p': 204 | case 'P': 205 | case 'u': 206 | driver.bustype = ch; 207 | break; 208 | case 'v': 209 | driver.vendor = strtol(optarg, NULL, 0); 210 | break; 211 | case 'd': 212 | driver.device = strtol(optarg, NULL, 0); 213 | break; 214 | case 'n': 215 | driver.name = optarg; 216 | driver.namelen = strlen(optarg); 217 | break; 218 | default: 219 | usage(); 220 | } 221 | } 222 | 223 | if (sysfile == NULL || driver.bustype == 0 || driver.vendor == 0 || driver.device == 0 || driver.name == NULL) 224 | usage(); 225 | 226 | load_driver(sysfile, &driver); 227 | 228 | return (0); 229 | } 230 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/usbd_var.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * $FreeBSD$ 33 | */ 34 | 35 | #ifndef _USBD_VAR_H_ 36 | #define _USBD_VAR_H_ 37 | 38 | #define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 39 | 40 | #define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 41 | #define URB_FUNCTION_ABORT_PIPE 0x0002 42 | #define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 43 | #define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B 44 | #define URB_FUNCTION_VENDOR_DEVICE 0x0017 45 | #define URB_FUNCTION_VENDOR_INTERFACE 0x0018 46 | #define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 47 | #define URB_FUNCTION_CLASS_DEVICE 0x001A 48 | #define URB_FUNCTION_CLASS_INTERFACE 0x001B 49 | #define URB_FUNCTION_CLASS_ENDPOINT 0x001C 50 | #define URB_FUNCTION_CLASS_OTHER 0x001F 51 | #define URB_FUNCTION_VENDOR_OTHER 0x0020 52 | 53 | #define USBD_STATUS_SUCCESS 0x00000000 54 | #define USBD_STATUS_CANCELED 0x00010000 55 | #define USBD_STATUS_PENDING 0x40000000 56 | #define USBD_STATUS_NO_MEMORY 0x80000100 57 | #define USBD_STATUS_REQUEST_FAILED 0x80000500 58 | #define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 59 | #define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 60 | #define USBD_STATUS_CRC 0xC0000001 61 | #define USBD_STATUS_BTSTUFF 0xC0000002 62 | #define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 63 | #define USBD_STATUS_STALL_PID 0xC0000004 64 | #define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 65 | #define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 66 | #define USBD_STATUS_UNEXPECTED_PID 0xC0000007 67 | #define USBD_STATUS_DATA_OVERRUN 0xC0000008 68 | #define USBD_STATUS_DATA_UNDERRUN 0xC0000009 69 | #define USBD_STATUS_RESERVED1 0xC000000A 70 | #define USBD_STATUS_RESERVED2 0xC000000B 71 | #define USBD_STATUS_BUFFER_OVERRUN 0xC000000C 72 | #define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D 73 | #define USBD_STATUS_NOT_ACCESSED 0xC000000F 74 | #define USBD_STATUS_FIFO 0xC0000010 75 | #define USBD_STATUS_XACT_ERROR 0xC0000011 76 | #define USBD_STATUS_BABBLE_DETECTED 0xC0000012 77 | #define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 78 | #define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 79 | #define USBD_STATUS_TIMEOUT 0xC0006000 80 | #define USBD_STATUS_DEVICE_GONE 0xC0007000 81 | 82 | struct usbd_urb_header { 83 | uint16_t uuh_len; 84 | uint16_t uuh_func; 85 | int32_t uuh_status; 86 | void *uuh_handle; 87 | uint32_t uuh_flags; 88 | }; 89 | 90 | enum usbd_pipe_type { 91 | UsbdPipeTypeControl = UE_CONTROL, 92 | UsbdPipeTypeIsochronous = UE_ISOCHRONOUS, 93 | UsbdPipeTypeBulk = UE_BULK, 94 | UsbdPipeTypeInterrupt = UE_INTERRUPT 95 | }; 96 | 97 | struct usbd_pipe_information { 98 | uint16_t upi_maxpktsize; 99 | uint8_t upi_epaddr; 100 | uint8_t upi_interval; 101 | enum usbd_pipe_type upi_type; 102 | usb_endpoint_descriptor_t *upi_handle; 103 | uint32_t upi_maxtxsize; 104 | #define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE 105 | uint32_t upi_flags; 106 | }; 107 | 108 | struct usbd_interface_information { 109 | uint16_t uii_len; 110 | uint8_t uii_intfnum; 111 | uint8_t uii_altset; 112 | uint8_t uii_intfclass; 113 | uint8_t uii_intfsubclass; 114 | uint8_t uii_intfproto; 115 | uint8_t uii_reserved; 116 | void *uii_handle; 117 | uint32_t uii_numeps; 118 | struct usbd_pipe_information uii_pipes[1]; 119 | }; 120 | 121 | struct usbd_urb_select_interface { 122 | struct usbd_urb_header usi_hdr; 123 | void *usi_handle; 124 | struct usbd_interface_information uusi_intf; 125 | }; 126 | 127 | struct usbd_urb_select_configuration { 128 | struct usbd_urb_header usc_hdr; 129 | usb_config_descriptor_t *usc_conf; 130 | void *usc_handle; 131 | struct usbd_interface_information usc_intf; 132 | }; 133 | 134 | struct usbd_urb_pipe_request { 135 | struct usbd_urb_header upr_hdr; 136 | usb_endpoint_descriptor_t *upr_handle; 137 | }; 138 | 139 | struct usbd_hcd_area { 140 | void *reserved8[8]; 141 | }; 142 | 143 | struct usbd_urb_bulk_or_intr_transfer { 144 | struct usbd_urb_header ubi_hdr; 145 | usb_endpoint_descriptor_t *ubi_epdesc; 146 | uint32_t ubi_trans_flags; 147 | #define USBD_SHORT_TRANSFER_OK 0x00000002 148 | uint32_t ubi_trans_buflen; 149 | void *ubi_trans_buf; 150 | struct mdl *ubi_mdl; 151 | union usbd_urb *ubi_urblink; 152 | struct usbd_hcd_area ubi_hca; 153 | }; 154 | 155 | struct usbd_urb_control_descriptor_request { 156 | struct usbd_urb_header ucd_hdr; 157 | void *ucd_reserved0; 158 | uint32_t ucd_reserved1; 159 | uint32_t ucd_trans_buflen; 160 | void *ucd_trans_buf; 161 | struct mdl *ucd_mdl; 162 | union nt_urb *ucd_urblink; 163 | struct usbd_hcd_area ucd_hca; 164 | uint16_t ucd_reserved2; 165 | uint8_t ucd_idx; 166 | uint8_t ucd_desctype; 167 | uint16_t ucd_langid; 168 | uint16_t ucd_reserved3; 169 | }; 170 | 171 | struct usbd_urb_vendor_or_class_request { 172 | struct usbd_urb_header uvc_hdr; 173 | void *uvc_reserved0; 174 | uint32_t uvc_trans_flags; 175 | #define USBD_TRANSFER_DIRECTION_IN 1 176 | uint32_t uvc_trans_buflen; 177 | void *uvc_trans_buf; 178 | struct mdl *uvc_mdl; 179 | union nt_urb *uvc_urblink; 180 | struct usbd_hcd_area uvc_hca; 181 | uint8_t uvc_reserved1; 182 | uint8_t uvc_req; 183 | uint16_t uvc_value; 184 | uint16_t uvc_idx; 185 | uint16_t uvc_reserved2; 186 | }; 187 | 188 | struct usbd_interface_list_entry { 189 | usb_interface_descriptor_t *uil_intfdesc; 190 | struct usbd_interface_information *uil_intf; 191 | }; 192 | 193 | union usbd_urb { 194 | struct usbd_urb_header uu_hdr; 195 | struct usbd_urb_select_configuration uu_selconf; 196 | struct usbd_urb_bulk_or_intr_transfer uu_bulkintr; 197 | struct usbd_urb_control_descriptor_request uu_ctldesc; 198 | struct usbd_urb_vendor_or_class_request uu_vcreq; 199 | struct usbd_urb_pipe_request uu_pipe; 200 | }; 201 | 202 | #define USBD_URB_STATUS(urb) ((urb)->uu_hdr.uuh_status) 203 | 204 | #define USBDI_VERSION 0x00000500 205 | #define USB_VER_1_1 0x00000110 206 | #define USB_VER_2_0 0x00000200 207 | 208 | struct usbd_version_info { 209 | uint32_t uvi_usbdi_vers; 210 | uint32_t uvi_supported_vers; 211 | }; 212 | 213 | extern struct image_patch_table usbd_functbl[]; 214 | 215 | void usbd_libinit(void); 216 | void usbd_libfini(void); 217 | 218 | #endif /* _USBD_VAR_H_ */ 219 | -------------------------------------------------------------------------------- /src/sys/dev/if_ndis/if_ndis_pccard.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | 55 | #include "pe_var.h" 56 | #include "resource_var.h" 57 | #include "ntoskrnl_var.h" 58 | #include "ndis_var.h" 59 | #include "if_ndisvar.h" 60 | 61 | #include 62 | #include "card_if.h" 63 | 64 | MODULE_DEPEND(ndis, pccard, 1, 1, 1); 65 | 66 | static int ndis_alloc_amem(struct ndis_softc *); 67 | static int ndis_attach_pccard(device_t); 68 | static int ndis_devcompare_pccard(enum ndis_bus_type, 69 | struct ndis_device_type *, device_t); 70 | static int ndis_probe_pccard(device_t); 71 | static struct resource_list *ndis_get_resource_list(device_t, device_t); 72 | 73 | static device_method_t ndis_pccard_methods[] = { 74 | DEVMETHOD(device_probe, ndis_probe_pccard), 75 | DEVMETHOD(device_attach, ndis_attach_pccard), 76 | DEVMETHOD(device_detach, ndis_detach), 77 | DEVMETHOD(device_shutdown, ndis_shutdown), 78 | DEVMETHOD(device_suspend, ndis_suspend), 79 | DEVMETHOD(device_resume, ndis_resume), 80 | /* 81 | * This is an awful kludge, but we need it becase pccard 82 | * does not implement a bus_get_resource_list() method. 83 | */ 84 | DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 85 | DEVMETHOD_END 86 | }; 87 | 88 | driver_t ndis_pccard_driver = { 89 | "ndis", 90 | ndis_pccard_methods, 91 | sizeof(struct ndis_softc) 92 | }; 93 | 94 | DRIVER_MODULE(ndis, pccard, ndis_pccard_driver, ndis_devclass, ndisdrv_modevent, 0); 95 | 96 | static int 97 | ndis_devcompare_pccard(enum ndis_bus_type bustype, 98 | struct ndis_device_type *t, device_t dev) 99 | { 100 | uint32_t product, vendor; 101 | 102 | if (bustype != NDIS_PCMCIABUS || 103 | pccard_get_product(dev, &product) || 104 | pccard_get_vendor(dev, &vendor)) 105 | return (FALSE); 106 | 107 | for (; t->name != NULL; t++) { 108 | if ((vendor == t->vendor) && 109 | (product == t->device)) { 110 | device_set_desc(dev, t->name); 111 | return (TRUE); 112 | } 113 | } 114 | 115 | return (FALSE); 116 | } 117 | 118 | static int 119 | ndis_probe_pccard(device_t dev) 120 | { 121 | struct drvdb_ent *db; 122 | struct driver_object *drv; 123 | 124 | drv = windrv_lookup(0, "PCCARD Bus"); 125 | if (drv == NULL) 126 | return (ENXIO); 127 | 128 | db = windrv_match((matchfuncptr)ndis_devcompare_pccard, dev); 129 | if (db == NULL) 130 | return (ENXIO); 131 | return (windrv_create_pdo(drv, dev)); 132 | } 133 | 134 | static int 135 | ndis_attach_pccard(device_t dev) 136 | { 137 | struct ndis_softc *sc; 138 | struct ndis_device_type *t; 139 | struct drvdb_ent *db; 140 | uint32_t product, vendor; 141 | int devidx = 0, error = 0, rid = 0; 142 | 143 | sc = device_get_softc(dev); 144 | sc->ndis_dev = dev; 145 | 146 | db = windrv_match((matchfuncptr)ndis_devcompare_pccard, dev); 147 | if (db == NULL) 148 | return (ENXIO); 149 | sc->ndis_dobj = db->windrv_object; 150 | sc->ndis_regvals = db->windrv_regvals; 151 | resource_list_init(&sc->ndis_rl); 152 | 153 | sc->ndis_io_rid = 0; 154 | sc->ndis_res_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 155 | &sc->ndis_io_rid, RF_ACTIVE); 156 | if (sc->ndis_res_io == NULL) { 157 | device_printf(dev, "couldn't map iospace\n"); 158 | return (ENXIO); 159 | } 160 | sc->ndis_rescnt++; 161 | resource_list_add(&sc->ndis_rl, SYS_RES_IOPORT, sc->ndis_io_rid, 162 | rman_get_start(sc->ndis_res_io), rman_get_end(sc->ndis_res_io), 163 | rman_get_size(sc->ndis_res_io)); 164 | 165 | sc->ndis_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 166 | RF_SHAREABLE | RF_ACTIVE); 167 | if (sc->ndis_irq == NULL) { 168 | device_printf(dev, "couldn't map interrupt\n"); 169 | return (ENXIO); 170 | } 171 | sc->ndis_rescnt++; 172 | resource_list_add(&sc->ndis_rl, SYS_RES_IRQ, rid, 173 | rman_get_start(sc->ndis_irq), rman_get_start(sc->ndis_irq), 1); 174 | sc->ndis_bus_type = NDIS_PCMCIABUS; 175 | 176 | error = pccard_get_product(dev, &product); 177 | if (error) 178 | return (error); 179 | error = pccard_get_vendor(dev, &vendor); 180 | if (error) 181 | return (error); 182 | /* Figure out exactly which device we matched. */ 183 | for (t = db->windrv_devlist; t->name != NULL; t++, devidx++) { 184 | if ((vendor == t->vendor) && 185 | (product == t->device)) 186 | break; 187 | } 188 | sc->ndis_devidx = devidx; 189 | 190 | error = ndis_alloc_amem(sc); 191 | if (error) { 192 | ndis_free_amem(sc); 193 | return (error); 194 | } 195 | return (ndis_attach(dev)); 196 | } 197 | 198 | static struct resource_list * 199 | ndis_get_resource_list(device_t dev, device_t child) 200 | { 201 | struct ndis_softc *sc; 202 | 203 | sc = device_get_softc(dev); 204 | return (&sc->ndis_rl); 205 | } 206 | 207 | #define NDIS_AM_RID 3 208 | 209 | static int 210 | ndis_alloc_amem(struct ndis_softc *sc) 211 | { 212 | int error, rid = NDIS_AM_RID; 213 | 214 | sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 215 | &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 216 | if (sc->ndis_res_am == NULL) { 217 | device_printf(sc->ndis_dev, 218 | "failed to allocate attribute memory\n"); 219 | return (ENXIO); 220 | } 221 | sc->ndis_rescnt++; 222 | resource_list_add(&sc->ndis_rl, SYS_RES_MEMORY, rid, 223 | rman_get_start(sc->ndis_res_am), rman_get_end(sc->ndis_res_am), 224 | rman_get_size(sc->ndis_res_am)); 225 | 226 | error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 227 | sc->ndis_dev, rid, 0, NULL); 228 | if (error) { 229 | device_printf(sc->ndis_dev, 230 | "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error); 231 | return (error); 232 | } 233 | 234 | error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 235 | sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 236 | if (error) { 237 | device_printf(sc->ndis_dev, 238 | "CARD_SET_RES_FLAGS() returned 0x%x\n", error); 239 | return (error); 240 | } 241 | 242 | sc->ndis_am_rid = rid; 243 | 244 | return (0); 245 | } 246 | 247 | void 248 | ndis_free_amem(void *arg) 249 | { 250 | struct ndis_softc *sc = arg; 251 | 252 | if (sc->ndis_res_am != NULL) 253 | bus_release_resource(sc->ndis_dev, SYS_RES_MEMORY, 254 | sc->ndis_am_rid, sc->ndis_res_am); 255 | resource_list_free(&sc->ndis_rl); 256 | } 257 | -------------------------------------------------------------------------------- /src/sys/dev/if_ndis/if_ndis_pci.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | #include "pe_var.h" 59 | #include "resource_var.h" 60 | #include "ntoskrnl_var.h" 61 | #include "ndis_var.h" 62 | #include "if_ndisvar.h" 63 | 64 | MODULE_DEPEND(ndis, pci, 1, 1, 1); 65 | 66 | static int ndis_attach_pci(device_t); 67 | static int ndis_devcompare_pci(enum ndis_bus_type, 68 | struct ndis_device_type *, device_t); 69 | static int ndis_probe_pci(device_t); 70 | static struct resource_list *ndis_get_resource_list(device_t, device_t); 71 | 72 | static device_method_t ndis_pci_methods[] = { 73 | DEVMETHOD(device_probe, ndis_probe_pci), 74 | DEVMETHOD(device_attach, ndis_attach_pci), 75 | DEVMETHOD(device_detach, ndis_detach), 76 | DEVMETHOD(device_shutdown, ndis_shutdown), 77 | DEVMETHOD(device_suspend, ndis_suspend), 78 | DEVMETHOD(device_resume, ndis_resume), 79 | DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 80 | DEVMETHOD_END 81 | }; 82 | 83 | driver_t ndis_pci_driver = { 84 | "ndis", 85 | ndis_pci_methods, 86 | sizeof(struct ndis_softc) 87 | }; 88 | 89 | DRIVER_MODULE(ndis, pci, ndis_pci_driver, ndis_devclass, ndisdrv_modevent, 0); 90 | 91 | static int 92 | ndis_devcompare_pci(enum ndis_bus_type bustype, 93 | struct ndis_device_type *t, device_t dev) 94 | { 95 | 96 | if (bustype != NDIS_PCIBUS) 97 | return (FALSE); 98 | 99 | for (; t->name != NULL; t++) { 100 | if ((pci_get_vendor(dev) == t->vendor) && 101 | (pci_get_device(dev) == t->device) && 102 | ((pci_read_config(dev, PCIR_SUBVEND_0, 4) == 103 | t->subsys) || t->subsys == 0)) { 104 | device_set_desc(dev, t->name); 105 | return (TRUE); 106 | } 107 | } 108 | 109 | return (FALSE); 110 | } 111 | 112 | static int 113 | ndis_probe_pci(device_t dev) 114 | { 115 | struct drvdb_ent *db; 116 | struct driver_object *drv; 117 | 118 | drv = windrv_lookup(0, "PCI Bus"); 119 | if (drv == NULL) 120 | return (ENXIO); 121 | 122 | db = windrv_match((matchfuncptr)ndis_devcompare_pci, dev); 123 | if (db == NULL) 124 | return (ENXIO); 125 | return (windrv_create_pdo(drv, dev)); 126 | } 127 | 128 | static int 129 | ndis_attach_pci(device_t dev) 130 | { 131 | struct ndis_softc *sc; 132 | struct ndis_device_type *t; 133 | struct resource_list *rl; 134 | struct resource_list_entry *rle; 135 | struct drvdb_ent *db; 136 | uint32_t devidx = 0, defidx = 0; 137 | int error = 0, rid; 138 | 139 | sc = device_get_softc(dev); 140 | sc->ndis_dev = dev; 141 | 142 | db = windrv_match((matchfuncptr)ndis_devcompare_pci, dev); 143 | if (db == NULL) 144 | return (ENXIO); 145 | sc->ndis_dobj = db->windrv_object; 146 | sc->ndis_regvals = db->windrv_regvals; 147 | 148 | /* 149 | * Map control/status registers. 150 | */ 151 | pci_enable_busmaster(dev); 152 | rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 153 | if (rl == NULL) 154 | return (ENXIO); 155 | 156 | STAILQ_FOREACH(rle, rl, link) { 157 | switch (rle->type) { 158 | case SYS_RES_IOPORT: 159 | sc->ndis_io_rid = rle->rid; 160 | sc->ndis_res_io = bus_alloc_resource_any(dev, 161 | SYS_RES_IOPORT, &sc->ndis_io_rid, RF_ACTIVE); 162 | if (sc->ndis_res_io == NULL) { 163 | device_printf(dev, "no ioport\n"); 164 | error = ENXIO; 165 | goto fail; 166 | } 167 | break; 168 | case SYS_RES_MEMORY: 169 | if (sc->ndis_res_altmem != NULL && 170 | sc->ndis_res_mem != NULL) { 171 | device_printf(dev, "too many mem\n"); 172 | error = ENXIO; 173 | goto fail; 174 | } 175 | if (sc->ndis_res_mem) { 176 | sc->ndis_altmem_rid = rle->rid; 177 | sc->ndis_res_altmem = bus_alloc_resource_any( 178 | dev, SYS_RES_MEMORY, &sc->ndis_altmem_rid, 179 | RF_ACTIVE); 180 | if (sc->ndis_res_altmem == NULL) { 181 | device_printf(dev, "no map alt\n"); 182 | error = ENXIO; 183 | goto fail; 184 | } 185 | } else { 186 | sc->ndis_mem_rid = rle->rid; 187 | sc->ndis_res_mem = bus_alloc_resource_any(dev, 188 | SYS_RES_MEMORY, &sc->ndis_mem_rid, 189 | RF_ACTIVE); 190 | if (sc->ndis_res_mem == NULL) { 191 | device_printf(dev, "no map\n"); 192 | error = ENXIO; 193 | goto fail; 194 | } 195 | } 196 | break; 197 | case SYS_RES_IRQ: 198 | rid = rle->rid; 199 | sc->ndis_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 200 | &rid, RF_SHAREABLE | RF_ACTIVE); 201 | if (sc->ndis_irq == NULL) { 202 | device_printf(dev, "no irq\n"); 203 | error = ENXIO; 204 | goto fail; 205 | } 206 | break; 207 | default: 208 | break; 209 | } 210 | sc->ndis_rescnt++; 211 | } 212 | 213 | /* 214 | * If the BIOS did not set up an interrupt for this device, 215 | * the resource traversal code above will fail to set up 216 | * an IRQ resource. This is usually a bad thing, so try to 217 | * force the allocation of an interrupt here. If one was 218 | * not assigned to us by the BIOS, bus_alloc_resource_any() 219 | * should route one for us. 220 | */ 221 | if (sc->ndis_irq == NULL) { 222 | rid = 0; 223 | sc->ndis_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 224 | &rid, RF_SHAREABLE | RF_ACTIVE); 225 | if (sc->ndis_irq == NULL) { 226 | device_printf(dev, "couldn't route interrupt\n"); 227 | error = ENXIO; 228 | goto fail; 229 | } 230 | sc->ndis_rescnt++; 231 | } 232 | 233 | /* 234 | * Allocate the parent bus DMA tag appropriate for PCI. 235 | */ 236 | #define NDIS_NSEG_NEW 32 237 | error = bus_dma_tag_create(bus_get_dma_tag(dev),/* PCI parent */ 238 | 1, 0, /* alignment, boundary */ 239 | BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 240 | BUS_SPACE_MAXADDR, /* highaddr */ 241 | NULL, NULL, /* filter, filterarg */ 242 | MAXBSIZE, NDIS_NSEG_NEW,/* maxsize, nsegments */ 243 | BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 244 | 0, /* flags */ 245 | NULL, NULL, /* lockfunc, lockarg */ 246 | &sc->ndis_parent_tag); 247 | if (error) 248 | goto fail; 249 | 250 | sc->ndis_bus_type = NDIS_PCIBUS; 251 | 252 | /* Figure out exactly which device we matched. */ 253 | for (t = db->windrv_devlist; t->name != NULL; t++, devidx++) { 254 | if ((pci_get_vendor(dev) == t->vendor) && 255 | (pci_get_device(dev) == t->device)) { 256 | if (t->subsys == 0) 257 | defidx = devidx; 258 | else { 259 | if (t->subsys == 260 | pci_read_config(dev, PCIR_SUBVEND_0, 4)) 261 | break; 262 | } 263 | } 264 | } 265 | if (t->name == NULL) 266 | sc->ndis_devidx = defidx; 267 | else 268 | sc->ndis_devidx = devidx; 269 | 270 | error = ndis_attach(dev); 271 | fail: 272 | return (error); 273 | } 274 | 275 | static struct resource_list * 276 | ndis_get_resource_list(device_t dev, device_t child) 277 | { 278 | struct ndis_softc *sc; 279 | 280 | sc = device_get_softc(dev); 281 | 282 | return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev)); 283 | } 284 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/subr_hal.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | 51 | #include "pe_var.h" 52 | #include "resource_var.h" 53 | #include "ntoskrnl_var.h" 54 | #include "hal_var.h" 55 | #include "ndis_var.h" 56 | 57 | static uint64_t KeQueryPerformanceCounter(uint64_t *); 58 | static uint8_t KeRaiseIrqlToDpcLevel(void); 59 | static void KeStallExecutionProcessor(uint32_t); 60 | static uint32_t READ_PORT_ULONG(uint32_t *); 61 | static uint16_t READ_PORT_USHORT(uint16_t *); 62 | static uint8_t READ_PORT_UCHAR(uint8_t *); 63 | static void READ_PORT_BUFFER_ULONG(uint32_t *, uint32_t *, uint32_t); 64 | static void READ_PORT_BUFFER_USHORT(uint16_t *, uint16_t *, uint32_t); 65 | static void READ_PORT_BUFFER_UCHAR(uint8_t *, uint8_t *, uint32_t); 66 | static void WRITE_PORT_BUFFER_ULONG(uint32_t *, uint32_t *, uint32_t); 67 | static void WRITE_PORT_BUFFER_USHORT(uint16_t *, uint16_t *, uint32_t); 68 | static void WRITE_PORT_BUFFER_UCHAR(uint8_t *, uint8_t *, uint32_t); 69 | static void WRITE_PORT_ULONG(uint32_t *, uint32_t); 70 | static void WRITE_PORT_USHORT(uint16_t *, uint16_t); 71 | static void WRITE_PORT_UCHAR(uint8_t *, uint8_t); 72 | static void _KeLowerIrql(uint8_t); 73 | static void dummy(void); 74 | 75 | static struct mtx disp_lock; 76 | 77 | void 78 | hal_libinit(void) 79 | { 80 | 81 | mtx_init(&disp_lock, "HAL lock", NULL, MTX_DEF | MTX_RECURSE); 82 | windrv_wrap_table(hal_functbl); 83 | } 84 | 85 | void 86 | hal_libfini(void) 87 | { 88 | 89 | mtx_destroy(&disp_lock); 90 | windrv_unwrap_table(hal_functbl); 91 | } 92 | 93 | static void 94 | KeStallExecutionProcessor(uint32_t usecs) 95 | { 96 | TRACE(NDBG_HAL, "usecs %u\n", usecs); 97 | DELAY(usecs); 98 | } 99 | 100 | static void 101 | WRITE_PORT_ULONG(uint32_t *port, uint32_t value) 102 | { 103 | TRACE(NDBG_HAL, "port %p value %u\n", port, value); 104 | bus_space_write_4(X86_BUS_SPACE_IO, 0x0, (bus_size_t)port, value); 105 | } 106 | 107 | static void 108 | WRITE_PORT_USHORT(uint16_t *port, uint16_t value) 109 | { 110 | TRACE(NDBG_HAL, "port %p value %u\n", port, value); 111 | bus_space_write_2(X86_BUS_SPACE_IO, 0x0, (bus_size_t)port, value); 112 | } 113 | 114 | static void 115 | WRITE_PORT_UCHAR(uint8_t *port, uint8_t value) 116 | { 117 | TRACE(NDBG_HAL, "port %p value %u\n", port, value); 118 | bus_space_write_1(X86_BUS_SPACE_IO, 0x0, (bus_size_t)port, value); 119 | } 120 | 121 | static void 122 | WRITE_PORT_BUFFER_ULONG(uint32_t *port, uint32_t *buffer, uint32_t count) 123 | { 124 | TRACE(NDBG_HAL, "port %p buffer %p count %u\n", port, buffer, count); 125 | bus_space_write_multi_4(X86_BUS_SPACE_IO, 0x0, 126 | (bus_size_t)port, buffer, count); 127 | } 128 | 129 | static void 130 | WRITE_PORT_BUFFER_USHORT(uint16_t *port, uint16_t *buffer, uint32_t count) 131 | { 132 | TRACE(NDBG_HAL, "port %p buffer %p count %u\n", port, buffer, count); 133 | bus_space_write_multi_2(X86_BUS_SPACE_IO, 0x0, 134 | (bus_size_t)port, buffer, count); 135 | } 136 | 137 | static void 138 | WRITE_PORT_BUFFER_UCHAR(uint8_t *port, uint8_t *buffer, uint32_t count) 139 | { 140 | TRACE(NDBG_HAL, "port %p buffer %p count %u\n", port, buffer, count); 141 | bus_space_write_multi_1(X86_BUS_SPACE_IO, 0x0, 142 | (bus_size_t)port, buffer, count); 143 | } 144 | 145 | static uint16_t 146 | READ_PORT_USHORT(uint16_t *port) 147 | { 148 | TRACE(NDBG_HAL, "port %p\n", port); 149 | return (bus_space_read_2(X86_BUS_SPACE_IO, 0x0, (bus_size_t)port)); 150 | } 151 | 152 | static uint32_t 153 | READ_PORT_ULONG(uint32_t *port) 154 | { 155 | TRACE(NDBG_HAL, "port %p\n", port); 156 | return (bus_space_read_4(X86_BUS_SPACE_IO, 0x0, (bus_size_t)port)); 157 | } 158 | 159 | static uint8_t 160 | READ_PORT_UCHAR(uint8_t *port) 161 | { 162 | TRACE(NDBG_HAL, "port %p\n", port); 163 | return (bus_space_read_1(X86_BUS_SPACE_IO, 0x0, (bus_size_t)port)); 164 | } 165 | 166 | static void 167 | READ_PORT_BUFFER_ULONG(uint32_t *port, uint32_t *buffer, uint32_t count) 168 | { 169 | TRACE(NDBG_HAL, "port %p count %u\n", port, count); 170 | bus_space_read_multi_4(X86_BUS_SPACE_IO, 0x0, 171 | (bus_size_t)port, buffer, count); 172 | } 173 | 174 | static void 175 | READ_PORT_BUFFER_USHORT(uint16_t *port, uint16_t *buffer, uint32_t count) 176 | { 177 | TRACE(NDBG_HAL, "port %p count %u\n", port, count); 178 | bus_space_read_multi_2(X86_BUS_SPACE_IO, 0x0, 179 | (bus_size_t)port, buffer, count); 180 | } 181 | 182 | static void 183 | READ_PORT_BUFFER_UCHAR(uint8_t *port, uint8_t *buffer, uint32_t count) 184 | { 185 | TRACE(NDBG_HAL, "port %p count %u\n", port, count); 186 | bus_space_read_multi_1(X86_BUS_SPACE_IO, 0x0, 187 | (bus_size_t)port, buffer, count); 188 | } 189 | 190 | uint8_t 191 | KfAcquireSpinLock(unsigned long *lock) 192 | { 193 | uint8_t oldirql; 194 | 195 | TRACE(NDBG_HAL, "lock %p\n", lock); 196 | KeRaiseIrql(DISPATCH_LEVEL, &oldirql); 197 | KeAcquireSpinLockAtDpcLevel(lock); 198 | 199 | return (oldirql); 200 | } 201 | 202 | void 203 | KfReleaseSpinLock(unsigned long *lock, uint8_t newirql) 204 | { 205 | TRACE(NDBG_HAL, "lock %p newirql %u\n", lock, newirql); 206 | KeReleaseSpinLockFromDpcLevel(lock); 207 | KeLowerIrql(newirql); 208 | } 209 | 210 | uint8_t 211 | KeGetCurrentIrql(void) 212 | { 213 | if (mtx_owned(&disp_lock)) 214 | return (DISPATCH_LEVEL); 215 | return (PASSIVE_LEVEL); 216 | } 217 | 218 | static uint64_t 219 | KeQueryPerformanceCounter(uint64_t *freq) 220 | { 221 | TRACE(NDBG_HAL, "freq %p\n", freq); 222 | if (freq != NULL) 223 | *freq = hz; 224 | return ((uint64_t)ticks); 225 | } 226 | 227 | uint8_t 228 | KfRaiseIrql(uint8_t newirql) 229 | { 230 | uint8_t oldirql; 231 | 232 | TRACE(NDBG_HAL, "newirql %u\n", newirql); 233 | oldirql = KeGetCurrentIrql(); 234 | KASSERT(oldirql <= newirql, ("newirql not less")); 235 | if (oldirql != DISPATCH_LEVEL) 236 | mtx_lock(&disp_lock); 237 | return (oldirql); 238 | } 239 | 240 | void 241 | KfLowerIrql(uint8_t oldirql) 242 | { 243 | TRACE(NDBG_HAL, "oldirql %u\n", oldirql); 244 | if (oldirql == DISPATCH_LEVEL) 245 | return; 246 | 247 | KASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL, ("irql not greater")); 248 | mtx_unlock(&disp_lock); 249 | } 250 | 251 | static uint8_t 252 | KeRaiseIrqlToDpcLevel(void) 253 | { 254 | uint8_t irql; 255 | 256 | KeRaiseIrql(DISPATCH_LEVEL, &irql); 257 | return (irql); 258 | } 259 | 260 | static void 261 | _KeLowerIrql(uint8_t oldirql) 262 | { 263 | KeLowerIrql(oldirql); 264 | } 265 | 266 | static void 267 | dummy(void) 268 | { 269 | printf("hal dummy called...\n"); 270 | } 271 | 272 | struct image_patch_table hal_functbl[] = { 273 | IMPORT_FFUNC(KfAcquireSpinLock, 1), 274 | IMPORT_FFUNC(KfLowerIrql, 1), 275 | IMPORT_FFUNC(KfRaiseIrql, 1), 276 | IMPORT_FFUNC(KfReleaseSpinLock, 1), 277 | IMPORT_SFUNC(KeGetCurrentIrql, 0), 278 | IMPORT_SFUNC(KeQueryPerformanceCounter, 1), 279 | IMPORT_SFUNC(KeRaiseIrqlToDpcLevel, 0), 280 | IMPORT_SFUNC(KeStallExecutionProcessor, 1), 281 | IMPORT_SFUNC(READ_PORT_BUFFER_UCHAR, 3), 282 | IMPORT_SFUNC(READ_PORT_BUFFER_ULONG, 3), 283 | IMPORT_SFUNC(READ_PORT_BUFFER_USHORT, 3), 284 | IMPORT_SFUNC(READ_PORT_UCHAR, 1), 285 | IMPORT_SFUNC(READ_PORT_ULONG, 1), 286 | IMPORT_SFUNC(READ_PORT_USHORT, 1), 287 | IMPORT_SFUNC(WRITE_PORT_BUFFER_UCHAR, 3), 288 | IMPORT_SFUNC(WRITE_PORT_BUFFER_ULONG, 3), 289 | IMPORT_SFUNC(WRITE_PORT_BUFFER_USHORT, 3), 290 | IMPORT_SFUNC(WRITE_PORT_UCHAR, 2), 291 | IMPORT_SFUNC(WRITE_PORT_ULONG, 2), 292 | IMPORT_SFUNC(WRITE_PORT_USHORT, 2), 293 | #undef KeLowerIrql 294 | IMPORT_SFUNC_MAP(KeLowerIrql, _KeLowerIrql, 1), 295 | { NULL, (FUNC)dummy, NULL, 0, STDCALL }, 296 | { NULL, NULL, NULL } 297 | }; 298 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/winx_wrap.S: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * $FreeBSD$ 33 | */ 34 | 35 | /* The 'ret' macro doesn't work in this file if GPROF is enabled. */ 36 | #ifdef GPROF 37 | #undef GPROF 38 | #endif 39 | 40 | #include 41 | 42 | #ifdef __i386__ 43 | /* 44 | * This file contains assembly language wrappers for the different 45 | * calling conventions supported by Windows on the i386 architecture. 46 | * In FreeBSD, the whole OS typically use same C calling convention 47 | * everywhere, namely _cdecl. Windows, on the other hand, uses several 48 | * different C calling conventions depending on the circumstances: 49 | * 50 | * _stdcall: Used for most ordinary Windows APIs. With _stdcall, 51 | * arguments are passed on the stack, and the callee unwinds the stack 52 | * before returning control to the caller. Not suitable for variadic 53 | * functions. 54 | * 55 | * _fastcall: Used for some APIs that may be invoked frequently and 56 | * where speed is a critical factor (e.g. KeAcquireSpinLock() and 57 | * KeReleaseSpinLock()) Similar to _stdcall, except the first 2 32-bit 58 | * or smaller arguments are passed in the %ecx and %edx registers 59 | * instead of on the stack. Not suitable for variadic functions. 60 | * 61 | * _cdecl: Used for standard C library routines and for variadic 62 | * functions. 63 | * 64 | * _regparm(3): Used for certain assembly routines. All arguments 65 | * passed in %eax, %ecx and %edx. 66 | */ 67 | 68 | /* 69 | * Handle _stdcall going from Windows to UNIX. 70 | * This is frustrating, because to do it right you have to 71 | * know how many arguments the called function takes, and there's 72 | * no way to figure this out on the fly: you just have to be told 73 | * ahead of time. We assume there will be 16 arguments. I don't 74 | * think there are any Windows APIs that require this many. 75 | */ 76 | .globl x86_stdcall_wrap_call 77 | .globl x86_stdcall_wrap_arg 78 | .globl x86_stdcall_wrap_end 79 | 80 | ENTRY(x86_stdcall_wrap) 81 | push %esi 82 | push %edi 83 | sub $64,%esp 84 | mov %esp,%esi 85 | add $64+8+4,%esi 86 | mov %esp,%edi 87 | mov $16,%ecx # handle up to 16 args 88 | rep 89 | movsl 90 | 91 | x86_stdcall_wrap_call: 92 | movl $0,%eax 93 | call *%eax # jump to routine 94 | 95 | add $64,%esp # clean the stack 96 | pop %edi 97 | pop %esi 98 | x86_stdcall_wrap_arg: 99 | ret $0xFF 100 | x86_stdcall_wrap_end: 101 | 102 | 103 | /* 104 | * Handle _stdcall going from UNIX to Windows. This routine 105 | * expects to be passed the function to be called, number of 106 | * args and the arguments for the Windows function on the stack. 107 | */ 108 | ENTRY(x86_stdcall_call) 109 | push %esi # must preserve %esi 110 | push %edi # and %edi 111 | 112 | mov 16(%esp),%eax # get arg cnt 113 | mov %eax,%ecx # save as copy count 114 | mov %esp,%esi # Set source address register to point to 115 | add $20,%esi # first agument to be forwarded. 116 | shl $2,%eax # turn arg cnt into offset 117 | sub %eax,%esp # shift stack to new location 118 | mov %esp,%edi # store dest copy addr 119 | rep # do the copy 120 | movsl 121 | 122 | call *12(%edi) # branch to stdcall routine 123 | 124 | mov %edi,%esp # restore stack 125 | pop %edi # restore %edi 126 | pop %esi # and %esi 127 | ret 128 | 129 | /* 130 | * Fastcall support. Similar to _stdcall, except the first 131 | * two arguments are passed in %ecx and %edx. It happens we 132 | * only support a small number of _fastcall APIs, none of them 133 | * take more than three arguments. So to keep the code size 134 | * and complexity down, we only handle 3 arguments here. 135 | */ 136 | /* Call _fastcall function going from Windows to UNIX. */ 137 | .globl x86_fastcall_wrap_call 138 | .globl x86_fastcall_wrap_arg 139 | .globl x86_fastcall_wrap_end 140 | 141 | ENTRY(x86_fastcall_wrap) 142 | mov 4(%esp),%eax 143 | push %eax 144 | push %edx 145 | push %ecx 146 | 147 | x86_fastcall_wrap_call: 148 | mov $0,%eax 149 | call *%eax # branch to fastcall routine 150 | add $12,%esp # clean the stack 151 | x86_fastcall_wrap_arg: 152 | ret $0xFF 153 | x86_fastcall_wrap_end: 154 | 155 | /* 156 | * Call _fastcall function going from UNIX to Windows. 157 | * This routine isn't normally used since NDIS miniport drivers 158 | * only have _stdcall entry points, but it's provided anyway 159 | * to round out the API, and for testing purposes. 160 | */ 161 | ENTRY(x86_fastcall_call) 162 | mov 4(%esp),%eax 163 | push 16(%esp) 164 | 165 | mov 12(%esp),%ecx 166 | mov 16(%esp),%edx 167 | call *8(%esp) # branch to fastcall routine 168 | add $4,%esp # clean the stack 169 | ret 170 | 171 | /* 172 | * Call regparm(3) function going from Windows to UNIX. Arguments 173 | * are passed in %eax, %edx and %ecx. Note that while additional 174 | * arguments are passed on the stack, we never bother when them, 175 | * since the only regparm(3) routines we need to wrap never take 176 | * more than 3 arguments. 177 | */ 178 | .globl x86_regparm_wrap_call 179 | .globl x86_regparm_wrap_end 180 | 181 | ENTRY(x86_regparm_wrap) 182 | push %ecx 183 | push %edx 184 | push %eax 185 | 186 | x86_regparm_wrap_call: 187 | movl $0,%eax 188 | call *%eax # jump to routine 189 | 190 | add $12,%esp # restore stack 191 | ret 192 | x86_regparm_wrap_end: 193 | 194 | /* 195 | * Call regparm(3) function going from UNIX to Windows. 196 | * This routine isn't normally used since NDIS miniport drivers 197 | * only have _stdcall entry points, but it's provided anyway 198 | * to round out the API, and for testing purposes. 199 | */ 200 | ENTRY(x86_regparm_call) 201 | mov 8(%esp),%eax 202 | mov 12(%esp),%edx 203 | mov 16(%esp),%ecx 204 | call *4(%esp) # branch to fastcall routine 205 | ret 206 | 207 | #endif /* __i386__ */ 208 | #ifdef __amd64__ 209 | 210 | /* 211 | * Wrapper for handling up to 16 arguments. We can't really 212 | * know how many arguments the caller will pass us. I'm taking an 213 | * educated guess that we'll never get over 16. Handling too 214 | * few arguments is bad. Handling too many is inefficient, but 215 | * not fatal. If someone can think of a way to handle an arbitrary 216 | * number of arguments with more elegant code, freel free to let 217 | * me know. 218 | * 219 | * Standard amd64 calling conventions specify the following registers 220 | * to be used for passing the first 6 arguments: 221 | * 222 | * %rdi, %rsi, %rdx, %rcx, %r8, %r9 223 | * 224 | * Further arguments are passed on the stack (the 7th argument is 225 | * located immediately after the return address). 226 | * 227 | * Windows x86_64 calling conventions only pass the first 4 228 | * arguments in registers: 229 | * 230 | * %rcx, %rdx, %r8, %r9 231 | * 232 | * Even when arguments are passed in registers, the stack must have 233 | * space reserved for those arguments. Thus the 5th argument (the 234 | * first non-register argument) is placed 32 bytes after the return 235 | * address. Additionally, %rdi and %rsi must be preserved. (These 236 | * two registers are not scratch registers in the standard convention.) 237 | * 238 | * Note that in this template, we load a contrived 64 bit address into 239 | * %r11 to represent our jump address. This is to guarantee that the 240 | * assembler leaves enough room to patch in an absolute 64-bit address 241 | * later. The idea behind this code is that we want to avoid having to 242 | * manually create all the wrapper functions at compile time with 243 | * a bunch of macros. This is doable, but a) messy and b) requires 244 | * us to maintain two separate tables (one for the UNIX function 245 | * pointers and another with the wrappers). This means I'd have to 246 | * update two different tables each time I added a function. 247 | * 248 | * To avoid this, we create the wrappers at runtime instead. The 249 | * image patch tables now contain two pointers: one two the normal 250 | * routine, and a blank one for the wrapper. To construct a wrapper, 251 | * we allocate some memory and copy the template function into it, 252 | * then patch the function pointer for the routine we want to wrap 253 | * into the newly created wrapper. The subr_pe module can then 254 | * simply patch the wrapper routine into the jump table into the 255 | * windows image. As a bonus, the wrapper pointer not only serves 256 | * as the wrapper entry point address, it's also a data pointer 257 | * that we can pass to free() later when we unload the module. 258 | */ 259 | 260 | .globl x86_64_wrap_call 261 | .globl x86_64_wrap_end 262 | 263 | ENTRY(x86_64_wrap) 264 | push %rbp # insure that the stack 265 | mov %rsp,%rbp # is 16-byte aligned 266 | and $-16,%rsp # 267 | subq $96,%rsp # allocate space on stack 268 | mov %rsi,96-8(%rsp) # save %rsi 269 | mov %rdi,96-16(%rsp)# save %rdi 270 | mov %rcx,%r10 # temporarily save %rcx in scratch 271 | lea 56+8(%rbp),%rsi # source == old stack top (stack+56) 272 | mov %rsp,%rdi # destination == new stack top 273 | mov $10,%rcx # count == 10 quadwords 274 | rep 275 | movsq # copy old stack contents to new location 276 | mov %r10,%rdi # set up arg0 (%rcx -> %rdi) 277 | mov %rdx,%rsi # set up arg1 (%rdx -> %rsi) 278 | mov %r8,%rdx # set up arg2 (%r8 -> %rdx) 279 | mov %r9,%rcx # set up arg3 (%r9 -> %rcx) 280 | mov 40+8(%rbp),%r8 # set up arg4 (stack+40 -> %r8) 281 | mov 48+8(%rbp),%r9 # set up arg5 (stack+48 -> %r9) 282 | xor %rax,%rax # clear return value 283 | x86_64_wrap_call: 284 | mov $0xFF00FF00FF00FF00,%r11 285 | callq *%r11 # call routine 286 | mov 96-16(%rsp),%rdi# restore %rdi 287 | mov 96-8(%rsp),%rsi # restore %rsi 288 | leave # delete space on stack 289 | ret 290 | x86_64_wrap_end: 291 | 292 | /* 293 | * Functions for invoking x86_64 callbacks. In each case, the first 294 | * argument is a pointer to the function. 295 | */ 296 | 297 | ENTRY(x86_64_call1) 298 | subq $40,%rsp 299 | mov %rsi,%rcx 300 | call *%rdi 301 | addq $40,%rsp 302 | ret 303 | 304 | ENTRY(x86_64_call2) 305 | subq $40,%rsp 306 | mov %rsi,%rcx 307 | /* %rdx is already correct */ 308 | call *%rdi 309 | addq $40,%rsp 310 | ret 311 | 312 | ENTRY(x86_64_call3) 313 | subq $40,%rsp 314 | mov %rcx,%r8 315 | mov %rsi,%rcx 316 | call *%rdi 317 | addq $40,%rsp 318 | ret 319 | 320 | ENTRY(x86_64_call4) 321 | subq $40,%rsp 322 | mov %r8,%r9 323 | mov %rcx,%r8 324 | mov %rsi,%rcx 325 | call *%rdi 326 | addq $40,%rsp 327 | ret 328 | 329 | ENTRY(x86_64_call5) 330 | subq $48,%rsp 331 | mov %r9,32(%rsp) 332 | mov %r8,%r9 333 | mov %rcx,%r8 334 | mov %rsi,%rcx 335 | call *%rdi 336 | addq $48,%rsp 337 | ret 338 | 339 | ENTRY(x86_64_call6) 340 | subq $56,%rsp 341 | mov 56+8(%rsp),%rax 342 | mov %r9,32(%rsp) 343 | mov %rax,40(%rsp) 344 | mov %r8,%r9 345 | mov %rcx,%r8 346 | mov %rsi,%rcx 347 | call *%rdi 348 | addq $56,%rsp 349 | ret 350 | 351 | #endif /* __amd64__ */ 352 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/pe_var.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * $FreeBSD$ 33 | */ 34 | 35 | #ifndef _PE_VAR_H_ 36 | #define _PE_VAR_H_ 37 | 38 | /* Image Format */ 39 | #define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ 40 | #define IMAGE_OS2_SIGNATURE 0x454E /* NE */ 41 | #define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ 42 | #define IMAGE_VXD_SIGNATURE 0x454C /* LE */ 43 | #define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ 44 | 45 | struct image_dos_header { 46 | uint16_t e_magic; /* Magic number */ 47 | uint16_t e_cblp; /* Bytes on last page of file */ 48 | uint16_t e_cp; /* Pages in file */ 49 | uint16_t e_crlc; /* Relocations */ 50 | uint16_t e_cparhdr; /* Size of header in paragraphs */ 51 | uint16_t e_minalloc; /* Minimum extra paragraphs needed */ 52 | uint16_t e_maxalloc; /* Maximum extra paragraphs needed */ 53 | uint16_t e_ss; /* Initial (relative) SS value */ 54 | uint16_t e_sp; /* Initial SP value */ 55 | uint16_t e_csum; /* Checksum */ 56 | uint16_t e_ip; /* Initial IP value */ 57 | uint16_t e_cs; /* Initial (relative) CS value */ 58 | uint16_t e_lfarlc; /* File address of relocation table */ 59 | uint16_t e_ovno; /* Overlay number */ 60 | uint16_t e_res[4]; /* Reserved words */ 61 | uint16_t e_oemid; /* OEM identifier (for oeminfo) */ 62 | uint16_t e_oeminfo; /* OEM information; oemid specific */ 63 | uint16_t e_res2[10]; /* Reserved words */ 64 | uint32_t e_lfanew; /* File address of new exe header */ 65 | }; 66 | 67 | struct image_file_header { 68 | uint16_t machine; 69 | uint16_t number_of_sections; 70 | uint32_t time_date_stamp; 71 | uint32_t pointer_to_symbol_table; 72 | uint32_t number_of_symbols; 73 | uint16_t size_of_optional_header; 74 | uint16_t characteristics; 75 | }; 76 | 77 | /* Machine types */ 78 | #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 79 | #define IMAGE_FILE_MACHINE_I860 0x014d 80 | #define IMAGE_FILE_MACHINE_I386 0x014c 81 | #define IMAGE_FILE_MACHINE_R3000 0x0162 82 | #define IMAGE_FILE_MACHINE_R4000 0x0166 83 | #define IMAGE_FILE_MACHINE_R10000 0x0168 84 | #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 85 | #define IMAGE_FILE_MACHINE_ALPHA 0x0184 86 | #define IMAGE_FILE_MACHINE_SH3 0x01a2 87 | #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 88 | #define IMAGE_FILE_MACHINE_SH3E 0x01a4 89 | #define IMAGE_FILE_MACHINE_SH4 0x01a6 90 | #define IMAGE_FILE_MACHINE_SH5 0x01a8 91 | #define IMAGE_FILE_MACHINE_ARM 0x01c0 92 | #define IMAGE_FILE_MACHINE_THUMB 0x01c2 93 | #define IMAGE_FILE_MACHINE_AM33 0x01d3 94 | #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 95 | #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 96 | #define IMAGE_FILE_MACHINE_IA64 0x0200 97 | #define IMAGE_FILE_MACHINE_MIPS16 0x0266 98 | #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 99 | #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 100 | #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 101 | #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 102 | #define IMAGE_FILE_MACHINE_TRICORE 0x0520 103 | #define IMAGE_FILE_MACHINE_CEF 0x0cef 104 | #define IMAGE_FILE_MACHINE_EBC 0x0ebc 105 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 106 | #define IMAGE_FILE_MACHINE_M32R 0x9041 107 | #define IMAGE_FILE_MACHINE_CEE 0xc0ee 108 | 109 | /* Characteristics */ 110 | #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ 111 | #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 112 | #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 113 | #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 114 | #define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 115 | #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 116 | #define IMAGE_FILE_16BIT_MACHINE 0x0040 117 | #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 118 | #define IMAGE_FILE_32BIT_MACHINE 0x0100 119 | #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 120 | #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 121 | #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 122 | #define IMAGE_FILE_SYSTEM 0x1000 123 | #define IMAGE_FILE_DLL 0x2000 124 | #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 125 | #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 126 | 127 | struct image_data_directory { 128 | uint32_t virtual_address; 129 | uint32_t size; 130 | }; 131 | 132 | #define IMAGE_DIRECTORY_ENTRIES_MAX 16 133 | 134 | struct image_optional_header { 135 | /* Standard fields */ 136 | uint16_t magic; 137 | uint8_t mayor_linker_version; 138 | uint8_t minor_linker_version; 139 | uint32_t size_of_code; 140 | uint32_t size_of_initialized_data; 141 | uint32_t size_of_uninitialized_data; 142 | uint32_t address_of_entry_point; 143 | uint32_t base_of_code; 144 | #ifdef __i386__ 145 | uint32_t base_of_data; 146 | #endif 147 | /* NT-specific fields */ 148 | uintptr_t image_base; 149 | uint32_t section_aligment; 150 | uint32_t file_aligment; 151 | uint16_t mayor_operating_system_version; 152 | uint16_t minor_operating_system_version; 153 | uint16_t mayor_image_version; 154 | uint16_t minor_image_version; 155 | uint16_t mayor_subsystem_version; 156 | uint16_t minor_subsystem_version; 157 | uint32_t win32_version_value; 158 | uint32_t size_of_image; 159 | uint32_t size_of_headers; 160 | uint32_t check_sum; 161 | uint16_t subsystem; 162 | uint16_t dll_characteristics; 163 | uintptr_t size_of_stack_reserve; 164 | uintptr_t size_of_stack_commit; 165 | uintptr_t size_of_heap_reserve; 166 | uintptr_t size_of_heap_commit; 167 | uint32_t loader_flags; 168 | uint32_t number_of_rva_and_sizes; 169 | struct image_data_directory data_directory[IMAGE_DIRECTORY_ENTRIES_MAX]; 170 | }; 171 | 172 | /* Magic */ 173 | #define IMAGE_OPTIONAL_MAGIC_32 0x010B 174 | #define IMAGE_OPTIONAL_MAGIC_64 0x020B 175 | 176 | struct image_nt_header { 177 | uint32_t signature; 178 | struct image_file_header file_header; 179 | struct image_optional_header optional_header; 180 | }; 181 | 182 | enum image_directory_entry { 183 | IMAGE_DIRECTORY_ENTRY_EXPORT, 184 | IMAGE_DIRECTORY_ENTRY_IMPORT, 185 | IMAGE_DIRECTORY_ENTRY_RESOURCE, 186 | IMAGE_DIRECTORY_ENTRY_EXCEPTION, 187 | IMAGE_DIRECTORY_ENTRY_SECURITY, 188 | IMAGE_DIRECTORY_ENTRY_BASERELOC, 189 | IMAGE_DIRECTORY_ENTRY_DEBUG, 190 | IMAGE_DIRECTORY_ENTRY_COPYRIGHT, 191 | IMAGE_DIRECTORY_ENTRY_GLOBALPTR, 192 | IMAGE_DIRECTORY_ENTRY_TLS, 193 | IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, 194 | IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, 195 | IMAGE_DIRECTORY_ENTRY_IAT, 196 | IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, 197 | IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 198 | }; 199 | 200 | /* Resource types */ 201 | #define RT_CURSOR 1 202 | #define RT_BITMAP 2 203 | #define RT_ICON 3 204 | #define RT_MENU 4 205 | #define RT_DIALOG 5 206 | #define RT_STRING 6 207 | #define RT_FONTDIR 7 208 | #define RT_FONT 8 209 | #define RT_ACCELERATOR 9 210 | #define RT_RCDATA 10 211 | #define RT_MESSAGETABLE 11 212 | #define RT_GROUP_CURSOR 12 213 | #define RT_GROUP_ICON 14 214 | #define RT_VERSION 16 215 | #define RT_DLGINCLUDE 17 216 | #define RT_PLUGPLAY 19 217 | #define RT_VXD 20 218 | #define RT_ANICURSOR 21 219 | #define RT_ANIICON 22 220 | #define RT_HTML 23 221 | 222 | /* Section header format */ 223 | #define IMAGE_SHORT_NAME_LEN 8 224 | 225 | struct image_section_header { 226 | uint8_t name[IMAGE_SHORT_NAME_LEN]; 227 | union { 228 | uint32_t physical_address; 229 | uint32_t virtual_size; 230 | } misc; 231 | uint32_t virtual_address; 232 | uint32_t size_of_raw_data; 233 | uint32_t pointer_to_raw_data; 234 | uint32_t pointer_to_relocations; 235 | uint32_t pointer_to_linenumbers; 236 | uint16_t number_of_relocations; 237 | uint16_t number_of_linenumbers; 238 | uint32_t characteristics; 239 | }; 240 | 241 | /* Import format */ 242 | struct image_import_by_name { 243 | uint16_t hint; 244 | uint8_t name[1]; 245 | }; 246 | 247 | #ifdef __i386__ 248 | #define IMAGE_ORDINAL_FLAG 0x80000000 249 | #endif 250 | 251 | #ifdef __amd64__ 252 | #define IMAGE_ORDINAL_FLAG 0x8000000000000000UL 253 | #endif 254 | 255 | struct image_import_descriptor { 256 | union { 257 | uint32_t characteristics; 258 | uint32_t original_first_thunk; 259 | } u; 260 | uint32_t time_data_stamp; 261 | uint32_t forward_chain; 262 | uint32_t name; 263 | uint32_t first_thunk; 264 | }; 265 | 266 | struct image_base_relocation { 267 | uint32_t virtual_address; 268 | uint32_t size_of_block; 269 | uint16_t type_offset[1]; 270 | }; 271 | 272 | #define IMR_RELTYPE(x) ((x >> 12) & 0xF) 273 | #define IMR_RELOFFSET(x) (x & 0xFFF) 274 | 275 | /* Generic relocation types */ 276 | #define IMAGE_REL_BASED_ABSOLUTE 0 277 | #define IMAGE_REL_BASED_HIGH 1 278 | #define IMAGE_REL_BASED_LOW 2 279 | #define IMAGE_REL_BASED_HIGHLOW 3 280 | #define IMAGE_REL_BASED_HIGHADJ 4 281 | #define IMAGE_REL_BASED_MIPS_JMPADDR 5 282 | #define IMAGE_REL_BASED_SECTION 6 283 | #define IMAGE_REL_BASED_REL 7 284 | #define IMAGE_REL_BASED_MIPS_JMPADDR16 9 285 | #define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ 286 | #define IMAGE_REL_BASED_DIR64 10 287 | #define IMAGE_REL_BASED_HIGH3ADJ 11 288 | 289 | struct image_resource_directory_entry { 290 | uint32_t name; 291 | uint32_t dataoff; 292 | }; 293 | 294 | #define RESOURCE_NAME_STR 0x80000000 295 | #define RESOURCE_DIR_FLAG 0x80000000 296 | 297 | struct image_resource_directory { 298 | uint32_t characteristics; 299 | uint32_t time_date_stamp; 300 | uint16_t major_version; 301 | uint16_t minor_version; 302 | uint16_t number_of_named_entries; 303 | uint16_t number_of_id_entries; 304 | /* struct image_resource_directory_entry directory_entries[1]; */ 305 | }; 306 | 307 | struct image_resource_directory_string { 308 | uint16_t length; 309 | char name_string[1]; 310 | }; 311 | 312 | struct image_resource_data_entry { 313 | uint32_t offset_to_data; 314 | uint32_t size; 315 | uint32_t code_page; 316 | uint32_t reserved; 317 | }; 318 | 319 | struct message_resource_data { 320 | uint32_t numblocks; 321 | /* struct message_resource_block blocks[1]; */ 322 | }; 323 | 324 | struct message_resource_block { 325 | uint32_t lowid; 326 | uint32_t highid; 327 | uint32_t entryoff; 328 | }; 329 | 330 | struct message_resource_entry { 331 | uint16_t len; 332 | uint16_t flags; 333 | char text[]; 334 | }; 335 | 336 | #define MESSAGE_RESOURCE_UNICODE 0x0001 337 | 338 | struct image_patch_table { 339 | char *name; 340 | void (*func)(void); 341 | void (*wrap)(void); 342 | uint8_t argcnt; 343 | uint8_t ftype; 344 | }; 345 | 346 | /* 347 | * AMD64 support. Microsoft uses a different calling convention 348 | * than everyone else on the amd64 platform. Sadly, gcc has no 349 | * built-in support for it (yet). 350 | * 351 | * The three major differences we're concerned with are: 352 | * 353 | * - The first 4 register-sized arguments are passed in the 354 | * %rcx, %rdx, %r8 and %r9 registers, and the rest are pushed 355 | * onto the stack. (The ELF ABI uses 6 registers, not 4). 356 | * 357 | * - The caller must reserve space on the stack for the 4 358 | * register arguments in case the callee has to spill them. 359 | * 360 | * - The stack must be 16-byte aligned by the time the caller 361 | * executes. A call instruction implicitly pushes an 8 byte 362 | * return address onto the stack. We have to make sure that 363 | * the amount of space we consume, plus the return address, 364 | * is a multiple of 16 bytes in size. This means that in 365 | * some cases, we may need to chew up an extra 8 bytes on 366 | * the stack that will be unused. 367 | * 368 | * On the bright side, Microsoft seems to be using just the one 369 | * calling convention for all functions on amd64, unlike x86 where 370 | * they use a mix of _stdcall, _fastcall and _cdecl. 371 | */ 372 | 373 | #define FUNC void(*)(void) 374 | 375 | #ifdef __amd64__ 376 | uint64_t x86_64_call1(void *, uint64_t); 377 | uint64_t x86_64_call2(void *, uint64_t, uint64_t); 378 | uint64_t x86_64_call3(void *, uint64_t, uint64_t, uint64_t); 379 | uint64_t x86_64_call4(void *, uint64_t, uint64_t, uint64_t, uint64_t); 380 | uint64_t x86_64_call5(void *, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); 381 | uint64_t x86_64_call6(void *, uint64_t, uint64_t, uint64_t, uint64_t, 382 | uint64_t, uint64_t); 383 | 384 | uint64_t _x86_64_call1(void *, uint64_t); 385 | uint64_t _x86_64_call2(void *, uint64_t, uint64_t); 386 | uint64_t _x86_64_call3(void *, uint64_t, uint64_t, uint64_t); 387 | uint64_t _x86_64_call4(void *, uint64_t, uint64_t, uint64_t, uint64_t); 388 | uint64_t _x86_64_call5(void *, uint64_t, uint64_t, uint64_t, uint64_t, 389 | uint64_t); 390 | uint64_t _x86_64_call6(void *, uint64_t, uint64_t, uint64_t, uint64_t, 391 | uint64_t, uint64_t); 392 | 393 | #define MSCALL1(fn, a) \ 394 | _x86_64_call1((fn), (uint64_t)(a)) 395 | #define MSCALL2(fn, a, b) \ 396 | _x86_64_call2((fn), (uint64_t)(a), (uint64_t)(b)) 397 | #define MSCALL3(fn, a, b, c) \ 398 | _x86_64_call3((fn), (uint64_t)(a), (uint64_t)(b), (uint64_t)(c)) 399 | #define MSCALL4(fn, a, b, c, d) \ 400 | _x86_64_call4((fn), (uint64_t)(a), (uint64_t)(b), \ 401 | (uint64_t)(c), (uint64_t)(d)) 402 | #define MSCALL5(fn, a, b, c, d, e) \ 403 | _x86_64_call5((fn), (uint64_t)(a), (uint64_t)(b), \ 404 | (uint64_t)(c), (uint64_t)(d), (uint64_t)(e)) 405 | #define MSCALL6(fn, a, b, c, d, e, f) \ 406 | _x86_64_call6((fn), (uint64_t)(a), (uint64_t)(b), \ 407 | (uint64_t)(c), (uint64_t)(d), (uint64_t)(e), (uint64_t)(f)) 408 | 409 | #define IMPORT_CFUNC(x, y) { #x, (FUNC)x, NULL, y, AMD64 } 410 | #define IMPORT_CFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, AMD64 } 411 | #define IMPORT_FFUNC(x, y) { #x, (FUNC)x, NULL, y, AMD64 } 412 | #define IMPORT_FFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, AMD64 } 413 | #define IMPORT_RFUNC(x, y) { #x, (FUNC)x, NULL, y, AMD64 } 414 | #define IMPORT_RFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, AMD64 } 415 | #define IMPORT_SFUNC(x, y) { #x, (FUNC)x, NULL, y, AMD64 } 416 | #define IMPORT_SFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, AMD64 } 417 | #endif /* __amd64__ */ 418 | 419 | #ifdef __i386__ 420 | uint32_t x86_stdcall_call(void *, int, ...); 421 | 422 | #define MSCALL1(fn, a) x86_stdcall_call(fn, 1, (a)) 423 | #define MSCALL2(fn, a, b) x86_stdcall_call(fn, 2, (a), (b)) 424 | #define MSCALL3(fn, a, b, c) x86_stdcall_call(fn, 3, (a), (b), (c)) 425 | #define MSCALL4(fn, a, b, c, d) x86_stdcall_call(fn, 4, (a), (b), (c), (d)) 426 | #define MSCALL5(fn, a, b, c, d, e) \ 427 | x86_stdcall_call(fn, 5, (a), (b), (c), (d), (e)) 428 | #define MSCALL6(fn, a, b, c, d, e, f) \ 429 | x86_stdcall_call(fn, 6, (a), (b), (c), (d), (e), (f)) 430 | 431 | #define IMPORT_CFUNC(x, y) { #x, (FUNC)x, NULL, y, CDECL } 432 | #define IMPORT_CFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, CDECL } 433 | #define IMPORT_FFUNC(x, y) { #x, (FUNC)x, NULL, y, FASTCALL } 434 | #define IMPORT_FFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, FASTCALL } 435 | #define IMPORT_RFUNC(x, y) { #x, (FUNC)x, NULL, y, REGPARM } 436 | #define IMPORT_RFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, REGPARM } 437 | #define IMPORT_SFUNC(x, y) { #x, (FUNC)x, NULL, y, STDCALL } 438 | #define IMPORT_SFUNC_MAP(x, y, z) { #x, (FUNC)y, NULL, z, STDCALL } 439 | #endif /* __i386__ */ 440 | 441 | void pe_get_optional_header(vm_offset_t, struct image_optional_header **); 442 | void pe_get_section_header(vm_offset_t, struct image_section_header **); 443 | int pe_get_message(vm_offset_t, uint32_t, char **, int *, uint16_t *); 444 | int pe_patch_imports(vm_offset_t, const char *, struct image_patch_table *); 445 | int pe_numsections(vm_offset_t); 446 | int pe_relocate(vm_offset_t); 447 | int pe_validate_header(vm_offset_t); 448 | vm_offset_t pe_translate_addr(vm_offset_t, vm_offset_t); 449 | 450 | #endif /* _PE_VAR_H_ */ 451 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/subr_pe.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | /* 37 | * This file contains routines for relocating and dynamically linking 38 | * executable object code files in the Windows(r) PE (Portable Executable) 39 | * format. In Windows, anything with a .EXE, .DLL or .SYS extention is 40 | * considered an executable, and all such files have some structures in 41 | * common. The PE format was apparently based largely on COFF but has 42 | * mutated significantly over time. We are mainly concerned with .SYS files, 43 | * so this module implements only enough routines to be able to parse the 44 | * headers and sections of a .SYS object file and perform the necessary 45 | * relocations and jump table patching to allow us to call into it 46 | * (and to have it call back to us). Note that while this module can handle 47 | * fixups for imported symbols, it knows nothing about exporting them. 48 | */ 49 | 50 | #include 51 | #include 52 | #ifdef _KERNEL 53 | #include 54 | #else 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | #define KASSERT(exp, msg) do { \ 62 | if (!(exp)) \ 63 | return (EINVAL); \ 64 | } while (0) 65 | #endif 66 | 67 | #include "pe_var.h" 68 | 69 | static int pe_is_nt_image(vm_offset_t); 70 | static void pe_get_nt_header(vm_offset_t, struct image_nt_header **); 71 | static void pe_get_file_header(vm_offset_t, struct image_file_header **); 72 | static int pe_get_section(vm_offset_t, struct image_section_header **, 73 | const char *); 74 | static int pe_get_import_descriptor(vm_offset_t, 75 | struct image_import_descriptor **, const char *); 76 | static int pe_get_messagetable(vm_offset_t, 77 | struct message_resource_data **); 78 | static vm_offset_t pe_imagebase(vm_offset_t); 79 | static vm_offset_t pe_directory_offset(vm_offset_t, enum image_directory_entry); 80 | static vm_offset_t pe_functbl_match(struct image_patch_table *, const char *); 81 | 82 | /* 83 | * Verify that this image has a Windows NT PE signature. 84 | */ 85 | static int 86 | pe_is_nt_image(vm_offset_t imgbase) 87 | { 88 | uint32_t signature; 89 | struct image_dos_header *dos_hdr; 90 | 91 | KASSERT(imgbase != 0, ("bad imgbase")); 92 | 93 | signature = *(uint16_t *)imgbase; 94 | if (signature == IMAGE_DOS_SIGNATURE) { 95 | dos_hdr = (struct image_dos_header *)imgbase; 96 | signature = *(uint32_t *)(imgbase + dos_hdr->e_lfanew); 97 | if (signature == IMAGE_NT_SIGNATURE) 98 | return (0); 99 | } 100 | 101 | return (ENOEXEC); 102 | } 103 | 104 | static void 105 | pe_get_nt_header(vm_offset_t imgbase, struct image_nt_header **hdr) 106 | { 107 | struct image_dos_header *dos_hdr; 108 | 109 | dos_hdr = (struct image_dos_header *)(imgbase); 110 | *hdr = (struct image_nt_header *)(imgbase + dos_hdr->e_lfanew); 111 | } 112 | 113 | void 114 | pe_get_section_header(vm_offset_t imgbase, struct image_section_header **hdr) 115 | { 116 | struct image_nt_header *nt_hdr; 117 | 118 | pe_get_nt_header(imgbase, &nt_hdr); 119 | *hdr = ((struct image_section_header *)((vm_offset_t)(nt_hdr) + 120 | offsetof(struct image_nt_header, optional_header) + 121 | ((struct image_nt_header *)(nt_hdr))->file_header.size_of_optional_header)); 122 | } 123 | 124 | void 125 | pe_get_optional_header(vm_offset_t imgbase, struct image_optional_header **hdr) 126 | { 127 | struct image_nt_header *nt_hdr; 128 | 129 | pe_get_nt_header(imgbase, &nt_hdr); 130 | *hdr = &nt_hdr->optional_header; 131 | } 132 | 133 | static void 134 | pe_get_file_header(vm_offset_t imgbase, struct image_file_header **hdr) 135 | { 136 | struct image_nt_header *nt_hdr; 137 | 138 | pe_get_nt_header(imgbase, &nt_hdr); 139 | *hdr = &nt_hdr->file_header; 140 | } 141 | 142 | int 143 | pe_validate_header(vm_offset_t imgbase) 144 | { 145 | struct image_file_header *file_hdr; 146 | struct image_optional_header *opt_hdr; 147 | 148 | if (pe_is_nt_image(imgbase)) 149 | return (EINVAL); 150 | pe_get_file_header(imgbase, &file_hdr); 151 | if (!(file_hdr->characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) 152 | return (ENOEXEC); 153 | if (file_hdr->characteristics & IMAGE_FILE_RELOCS_STRIPPED) 154 | return (ENOEXEC); 155 | #ifdef __amd64__ 156 | if (file_hdr->machine != IMAGE_FILE_MACHINE_AMD64) 157 | return (ENOEXEC); 158 | #endif 159 | #ifdef __i386__ 160 | if (file_hdr->machine != IMAGE_FILE_MACHINE_I386) 161 | return (ENOEXEC); 162 | #endif 163 | if (file_hdr->number_of_sections == 0) 164 | return (ENOEXEC); 165 | pe_get_optional_header(imgbase, &opt_hdr); 166 | #ifdef __amd64__ 167 | if (opt_hdr->magic != IMAGE_OPTIONAL_MAGIC_64) 168 | return (ENOEXEC); 169 | #endif 170 | #ifdef __i386__ 171 | if (opt_hdr->magic != IMAGE_OPTIONAL_MAGIC_32) 172 | return (ENOEXEC); 173 | #endif 174 | return (0); 175 | } 176 | 177 | /* 178 | * Return the number of sections in this executable. 179 | */ 180 | int 181 | pe_numsections(vm_offset_t imgbase) 182 | { 183 | struct image_file_header *file_hdr; 184 | 185 | pe_get_file_header(imgbase, &file_hdr); 186 | 187 | return (file_hdr->number_of_sections); 188 | } 189 | 190 | /* 191 | * Return the base address that this image was linked for. 192 | * This helps us calculate relocation addresses later. 193 | */ 194 | static vm_offset_t 195 | pe_imagebase(vm_offset_t imgbase) 196 | { 197 | struct image_optional_header *optional_hdr; 198 | 199 | pe_get_optional_header(imgbase, &optional_hdr); 200 | 201 | return (optional_hdr->image_base); 202 | } 203 | 204 | /* 205 | * Return the offset of a given directory structure within the 206 | * image. Directories reside within sections. 207 | */ 208 | static vm_offset_t 209 | pe_directory_offset(vm_offset_t imgbase, enum image_directory_entry diridx) 210 | { 211 | struct image_optional_header *opt_hdr; 212 | vm_offset_t dir; 213 | 214 | pe_get_optional_header(imgbase, &opt_hdr); 215 | if (diridx >= opt_hdr->number_of_rva_and_sizes) 216 | return (0); 217 | dir = opt_hdr->data_directory[diridx].virtual_address; 218 | 219 | return (pe_translate_addr(imgbase, dir)); 220 | } 221 | 222 | vm_offset_t 223 | pe_translate_addr(vm_offset_t imgbase, vm_offset_t rva) 224 | { 225 | struct image_optional_header *opt_hdr; 226 | struct image_section_header *sect_hdr; 227 | int i = 0, sections, fixedlen; 228 | 229 | sections = pe_numsections(imgbase); 230 | pe_get_optional_header(imgbase, &opt_hdr); 231 | pe_get_section_header(imgbase, §_hdr); 232 | 233 | /* 234 | * The test here is to see if the RVA falls somewhere 235 | * inside the section, based on the section's start RVA 236 | * and its length. However it seems sometimes the 237 | * virtual length isn't enough to cover the entire 238 | * area of the section. We fudge by taking into account 239 | * the section alignment and rounding the section length 240 | * up to a page boundary. 241 | */ 242 | while (i++ < sections) { 243 | fixedlen = sect_hdr->misc.virtual_size; 244 | fixedlen += ((opt_hdr->section_aligment - 1) - 245 | sect_hdr->misc.virtual_size) & 246 | (opt_hdr->section_aligment - 1); 247 | if (sect_hdr->virtual_address <= (uint32_t)rva && 248 | (sect_hdr->virtual_address + fixedlen) > (uint32_t)rva) 249 | break; 250 | sect_hdr++; 251 | } 252 | 253 | if (i > sections) 254 | return (0); 255 | 256 | return ((vm_offset_t)(imgbase + rva - sect_hdr->virtual_address + 257 | sect_hdr->pointer_to_raw_data)); 258 | } 259 | 260 | /* 261 | * Get the section header for a particular section. Note that 262 | * section names can be anything, but there are some standard 263 | * ones (.text, .data, .rdata, .reloc). 264 | */ 265 | static int 266 | pe_get_section(vm_offset_t imgbase, struct image_section_header **hdr, 267 | const char *name) 268 | { 269 | struct image_section_header *sect_hdr; 270 | int i, sections; 271 | 272 | sections = pe_numsections(imgbase); 273 | pe_get_section_header(imgbase, §_hdr); 274 | for (i = 0; i < sections; i++) { 275 | if (!strcmp((char *)§_hdr->name, name)) { 276 | *hdr = sect_hdr; 277 | return (0); 278 | } else 279 | sect_hdr++; 280 | } 281 | return (ENOEXEC); 282 | } 283 | 284 | /* 285 | * Apply the base relocations to this image. The relocation table resides 286 | * within the .reloc section. Relocations are specified in blocks which refer 287 | * to a particular page. We apply the relocations one page block at a time. 288 | */ 289 | int 290 | pe_relocate(vm_offset_t imgbase) 291 | { 292 | struct image_section_header *sect; 293 | struct image_base_relocation *relhdr; 294 | vm_offset_t base, txt; 295 | vm_size_t delta; 296 | uint64_t *qloc; 297 | uint32_t *lloc; 298 | uint16_t rel, *sloc; 299 | int i, count; 300 | 301 | base = pe_imagebase(imgbase); 302 | if (pe_get_section(imgbase, §, ".text")) 303 | return (ENOEXEC); 304 | txt = pe_translate_addr(imgbase, sect->virtual_address); 305 | delta = (uint32_t)(txt) - base - sect->virtual_address; 306 | 307 | if (pe_get_section(imgbase, §, ".reloc")) 308 | return (ENOEXEC); 309 | relhdr = (struct image_base_relocation *)(imgbase + 310 | sect->pointer_to_raw_data); 311 | 312 | do { 313 | count = (relhdr->size_of_block - 314 | (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 315 | for (i = 0; i < count; i++) { 316 | rel = relhdr->type_offset[i]; 317 | switch (IMR_RELTYPE(rel)) { 318 | case IMAGE_REL_BASED_ABSOLUTE: 319 | break; 320 | case IMAGE_REL_BASED_HIGHLOW: 321 | lloc = (uint32_t *)pe_translate_addr(imgbase, 322 | relhdr->virtual_address + 323 | IMR_RELOFFSET(rel)); 324 | *lloc = pe_translate_addr(imgbase, (*lloc - base)); 325 | break; 326 | case IMAGE_REL_BASED_HIGH: 327 | sloc = (uint16_t *)pe_translate_addr(imgbase, 328 | relhdr->virtual_address + 329 | IMR_RELOFFSET(rel)); 330 | *sloc += (delta & 0xFFFF0000) >> 16; 331 | break; 332 | case IMAGE_REL_BASED_LOW: 333 | sloc = (uint16_t *)pe_translate_addr(imgbase, 334 | relhdr->virtual_address + 335 | IMR_RELOFFSET(rel)); 336 | *sloc += (delta & 0xFFFF); 337 | break; 338 | case IMAGE_REL_BASED_DIR64: 339 | qloc = (uint64_t *)pe_translate_addr(imgbase, 340 | relhdr->virtual_address + 341 | IMR_RELOFFSET(rel)); 342 | *qloc = pe_translate_addr(imgbase, (*qloc - base)); 343 | break; 344 | default: 345 | printf("[%d]reloc type: %d\n", i, IMR_RELTYPE(rel)); 346 | break; 347 | } 348 | } 349 | relhdr = (struct image_base_relocation *)((vm_offset_t)relhdr + 350 | relhdr->size_of_block); 351 | } while (relhdr->size_of_block); 352 | 353 | return (0); 354 | } 355 | 356 | /* 357 | * Return the import descriptor for a particular module. An image 358 | * may be linked against several modules, typically HAL.dll, ntoskrnl.exe 359 | * and NDIS.SYS. For each module, there is a list of imported function 360 | * names and their addresses. 361 | * 362 | * Note: module names are case insensitive! 363 | */ 364 | static int 365 | pe_get_import_descriptor(vm_offset_t imgbase, 366 | struct image_import_descriptor **desc, const char *module) 367 | { 368 | struct image_import_descriptor *imp_desc; 369 | vm_offset_t offset; 370 | char *modname; 371 | 372 | KASSERT(module != NULL, ("no module")); 373 | 374 | offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 375 | if (offset == 0) 376 | return (ENOENT); 377 | 378 | for (imp_desc = (void *)offset; imp_desc->name; imp_desc++) { 379 | modname = (char *)pe_translate_addr(imgbase, imp_desc->name); 380 | if (!strncasecmp(module, modname, strlen(module))) { 381 | *desc = imp_desc; 382 | return (0); 383 | } 384 | } 385 | return (ENOENT); 386 | } 387 | 388 | static int 389 | pe_get_messagetable(vm_offset_t imgbase, struct message_resource_data **md) 390 | { 391 | struct image_resource_directory *rdir, *rtype; 392 | struct image_resource_directory_entry *dent, *dent2; 393 | struct image_resource_data_entry *rent; 394 | vm_offset_t offset; 395 | int i; 396 | 397 | offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 398 | if (offset == 0) 399 | return (ENOENT); 400 | 401 | rdir = (struct image_resource_directory *)offset; 402 | dent = (struct image_resource_directory_entry *)(offset + 403 | sizeof(struct image_resource_directory)); 404 | 405 | for (i = 0; i < rdir->number_of_id_entries; i++) { 406 | if (dent->name != RT_MESSAGETABLE) { 407 | dent++; 408 | continue; 409 | } 410 | dent2 = dent; 411 | while (dent2->dataoff & RESOURCE_DIR_FLAG) { 412 | rtype = (struct image_resource_directory *)(offset + 413 | (dent2->dataoff & ~RESOURCE_DIR_FLAG)); 414 | dent2 = (struct image_resource_directory_entry *) 415 | ((uintptr_t)rtype + 416 | sizeof(struct image_resource_directory)); 417 | } 418 | rent = (struct image_resource_data_entry *)(offset + 419 | dent2->dataoff); 420 | *md = (struct message_resource_data *)pe_translate_addr(imgbase, 421 | rent->offset_to_data); 422 | return (0); 423 | } 424 | 425 | return (ENOENT); 426 | } 427 | 428 | int 429 | pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len, 430 | uint16_t *flags) 431 | { 432 | struct message_resource_data *md; 433 | struct message_resource_block *mb; 434 | struct message_resource_entry *me; 435 | uint32_t i; 436 | 437 | if (pe_get_messagetable(imgbase, &md)) 438 | return (ENOENT); 439 | 440 | mb = (struct message_resource_block *)((uintptr_t)md + 441 | sizeof(struct message_resource_data)); 442 | 443 | for (i = 0; i < md->numblocks; i++) { 444 | if (id >= mb->lowid && id <= mb->highid) { 445 | me = (struct message_resource_entry *)((uintptr_t)md + 446 | mb->entryoff); 447 | for (i = id - mb->lowid; i > 0; i--) 448 | me = (struct message_resource_entry *) 449 | ((uintptr_t)me + me->len); 450 | *str = me->text; 451 | *len = me->len; 452 | *flags = me->flags; 453 | return (0); 454 | } 455 | mb++; 456 | } 457 | 458 | return (ENOENT); 459 | } 460 | 461 | /* 462 | * Find the function that matches a particular name. This doesn't 463 | * need to be particularly speedy since it's only run when loading 464 | * a module for the first time. 465 | */ 466 | static vm_offset_t 467 | pe_functbl_match(struct image_patch_table *functbl, const char *name) 468 | { 469 | struct image_patch_table *p; 470 | 471 | KASSERT(functbl != NULL, ("no functbl")); 472 | KASSERT(name != NULL, ("no name")); 473 | 474 | for (p = functbl; p->name != NULL; p++) { 475 | if (!strcmp(p->name, name)) { 476 | #ifdef _KERNEL 477 | if (bootverbose) 478 | printf("NDIS: match for %s\n", name); 479 | #endif 480 | /* 481 | * Return the wrapper pointer for this routine. 482 | * For x86, this is the same as the funcptr. 483 | * For amd64, this points to a wrapper routine 484 | * that does calling convention translation and 485 | * then invokes the underlying routine. 486 | */ 487 | return ((vm_offset_t)p->wrap); 488 | } 489 | } 490 | printf("NDIS: no match for %s\n", name); 491 | 492 | /* 493 | * Same as above but for dummy routine: 494 | * the one which is not implemented yet. 495 | */ 496 | return ((vm_offset_t)p->wrap); 497 | } 498 | 499 | /* 500 | * Patch the imported function addresses for a given module. 501 | * The caller must specify the module name and provide a table 502 | * of function pointers that will be patched into the jump table. 503 | * Note that there are actually two copies of the jump table: one 504 | * copy is left alone. In a .SYS file, the jump tables are usually 505 | * merged into the INIT segment. 506 | */ 507 | int 508 | pe_patch_imports(vm_offset_t imgbase, const char *module, 509 | struct image_patch_table *functbl) 510 | { 511 | struct image_import_descriptor *imp_desc; 512 | char *name; 513 | vm_offset_t *nptr, *fptr; 514 | 515 | KASSERT(module != NULL, ("no module")); 516 | KASSERT(functbl != NULL, ("no functbl")); 517 | 518 | if (pe_get_import_descriptor(imgbase, &imp_desc, module)) 519 | return (ENOEXEC); 520 | 521 | nptr = (vm_offset_t *)pe_translate_addr(imgbase, 522 | imp_desc->u.original_first_thunk); 523 | fptr = (vm_offset_t *)pe_translate_addr(imgbase, imp_desc->first_thunk); 524 | 525 | while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { 526 | name = (char *)pe_translate_addr(imgbase, 527 | (*nptr & ~IMAGE_ORDINAL_FLAG) + 2); 528 | *fptr = pe_functbl_match(functbl, name); 529 | nptr++; 530 | fptr++; 531 | } 532 | 533 | return (0); 534 | } 535 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/kern_windrv.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #ifdef __amd64__ 56 | #include 57 | #endif 58 | 59 | #include 60 | 61 | #include "pe_var.h" 62 | #include "resource_var.h" 63 | #include "ntoskrnl_var.h" 64 | #include "ndis_var.h" 65 | #include "hal_var.h" 66 | #include "usbd_var.h" 67 | #include "loader.h" 68 | 69 | extern devclass_t ndis_devclass; 70 | extern driver_t ndis_pccard_driver; 71 | extern driver_t ndis_pci_driver; 72 | extern driver_t ndis_usb_driver; 73 | 74 | static d_ioctl_t windrv_ioctl; 75 | 76 | static struct cdev *ndis_dev; 77 | 78 | static struct cdevsw ndis_cdevsw = { 79 | .d_version = D_VERSION, 80 | .d_ioctl = windrv_ioctl, 81 | .d_name = "ndis", 82 | }; 83 | 84 | #ifdef __amd64__ 85 | struct fpu_cc_ent { 86 | struct fpu_kern_ctx *ctx; 87 | LIST_ENTRY(fpu_cc_ent) entries; 88 | }; 89 | static LIST_HEAD(fpu_ctx_free, fpu_cc_ent) fpu_free_head = 90 | LIST_HEAD_INITIALIZER(fpu_free_head); 91 | static LIST_HEAD(fpu_ctx_busy, fpu_cc_ent) fpu_busy_head = 92 | LIST_HEAD_INITIALIZER(fpu_busy_head); 93 | static struct mtx fpu_free_mtx; 94 | static struct mtx fpu_busy_mtx; 95 | #endif 96 | 97 | static struct mtx drvdb_mtx; 98 | static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head; 99 | 100 | static struct driver_object fake_pci_driver; /* serves both PCI and cardbus */ 101 | static struct driver_object fake_pccard_driver; 102 | 103 | MALLOC_DEFINE(M_NDIS_WINDRV, "ndis_windrv", "ndis_windrv buffers"); 104 | 105 | #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path" 106 | 107 | void 108 | windrv_libinit(void) 109 | { 110 | STAILQ_INIT(&drvdb_head); 111 | mtx_init(&drvdb_mtx, "drvdb_mtx", NULL, MTX_DEF); 112 | 113 | #ifdef __amd64__ 114 | LIST_INIT(&fpu_free_head); 115 | LIST_INIT(&fpu_busy_head); 116 | mtx_init(&fpu_free_mtx, "free fpu context list lock", NULL, MTX_DEF); 117 | mtx_init(&fpu_busy_mtx, "busy fpu context list lock", NULL, MTX_DEF); 118 | #endif 119 | 120 | ndis_dev = make_dev_credf(0, &ndis_cdevsw, 0, NULL, 121 | UID_ROOT, GID_WHEEL, 0600, "ndis"); 122 | /* 123 | * PCI and pccard devices don't need to use IRPs to 124 | * interact with their bus drivers (usually), so our 125 | * emulated PCI and pccard drivers are just stubs. 126 | * USB devices, on the other hand, do all their I/O 127 | * by exchanging IRPs with the USB bus driver, so 128 | * for that we need to provide emulator dispatcher 129 | * routines, which are in a separate module. 130 | */ 131 | windrv_bus_attach(&fake_pci_driver, "PCI Bus"); 132 | windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus"); 133 | } 134 | 135 | void 136 | windrv_libfini(void) 137 | { 138 | struct drvdb_ent *d; 139 | #ifdef __amd64__ 140 | struct fpu_cc_ent *ent; 141 | #endif 142 | 143 | destroy_dev(ndis_dev); 144 | 145 | mtx_lock(&drvdb_mtx); 146 | while (STAILQ_FIRST(&drvdb_head) != NULL) { 147 | d = STAILQ_FIRST(&drvdb_head); 148 | STAILQ_REMOVE_HEAD(&drvdb_head, link); 149 | if (d->windrv_devlist) { 150 | free(d->windrv_object->driver_extension, M_NDIS_WINDRV); 151 | free(d->windrv_object->driver_start, M_NDIS_WINDRV); 152 | free(d->windrv_object, M_NDIS_WINDRV); 153 | free(d->windrv_devlist->name, M_NDIS_WINDRV); 154 | free(d->windrv_devlist, M_NDIS_WINDRV); 155 | } 156 | free(d, M_NDIS_WINDRV); 157 | } 158 | mtx_unlock(&drvdb_mtx); 159 | 160 | RtlFreeUnicodeString(&fake_pci_driver.driver_name); 161 | RtlFreeUnicodeString(&fake_pccard_driver.driver_name); 162 | 163 | mtx_destroy(&drvdb_mtx); 164 | 165 | #ifdef __amd64__ 166 | while ((ent = LIST_FIRST(&fpu_free_head)) != NULL) { 167 | LIST_REMOVE(ent, entries); 168 | fpu_kern_free_ctx(ent->ctx); 169 | free(ent, M_DEVBUF); 170 | } 171 | mtx_destroy(&fpu_free_mtx); 172 | 173 | ent = LIST_FIRST(&fpu_busy_head); 174 | KASSERT(ent == NULL, ("busy fpu context list is not empty")); 175 | mtx_destroy(&fpu_busy_mtx); 176 | #endif 177 | } 178 | 179 | /* 180 | * Given the address of a driver image, find its corresponding driver_object. 181 | */ 182 | struct driver_object * 183 | windrv_lookup(vm_offset_t img, const char *name) 184 | { 185 | struct unicode_string us; 186 | struct ansi_string as; 187 | struct drvdb_ent *d; 188 | 189 | bzero((char *)&us, sizeof(us)); 190 | 191 | if (name != NULL) { 192 | RtlInitAnsiString(&as, name); 193 | if (RtlAnsiStringToUnicodeString(&us, &as, TRUE)) 194 | return (NULL); 195 | } 196 | 197 | mtx_lock(&drvdb_mtx); 198 | STAILQ_FOREACH(d, &drvdb_head, link) { 199 | if (d->windrv_object->driver_start == (void *)img || 200 | (bcmp((char *)d->windrv_object->driver_name.buf, 201 | (char *)us.buf, us.len) == 0 && us.len)) { 202 | mtx_unlock(&drvdb_mtx); 203 | if (name != NULL) 204 | RtlFreeUnicodeString(&us); 205 | return (d->windrv_object); 206 | } 207 | } 208 | mtx_unlock(&drvdb_mtx); 209 | 210 | if (name != NULL) 211 | RtlFreeUnicodeString(&us); 212 | 213 | return (NULL); 214 | } 215 | 216 | struct drvdb_ent * 217 | windrv_match(matchfuncptr matchfunc, void *ctx) 218 | { 219 | struct drvdb_ent *d; 220 | 221 | mtx_lock(&drvdb_mtx); 222 | STAILQ_FOREACH(d, &drvdb_head, link) { 223 | if (d->windrv_devlist == NULL) 224 | continue; 225 | if (matchfunc(d->windrv_bustype, d->windrv_devlist, ctx)) { 226 | mtx_unlock(&drvdb_mtx); 227 | return (d); 228 | } 229 | } 230 | mtx_unlock(&drvdb_mtx); 231 | 232 | return (NULL); 233 | } 234 | 235 | /* 236 | * Remove a driver_object from our datatabase and destroy it. Throw 237 | * away any custom driver extension info that may have been added. 238 | */ 239 | static int 240 | windrv_unload(vm_offset_t img) 241 | { 242 | struct drvdb_ent *db, *r = NULL; 243 | struct driver_object *drv; 244 | struct device_object *pdo; 245 | device_t dev; 246 | struct list_entry *e; 247 | 248 | drv = windrv_lookup(img, NULL); 249 | 250 | /* 251 | * When we unload a driver image, we need to force a 252 | * detach of any devices that might be using it. We 253 | * need the PDOs of all attached devices for this. 254 | * Getting at them is a little hard. We basically 255 | * have to walk the device lists of all our bus 256 | * drivers. 257 | */ 258 | mtx_lock(&drvdb_mtx); 259 | STAILQ_FOREACH(db, &drvdb_head, link) { 260 | /* 261 | * Fake bus drivers have no devlist info. 262 | * If this driver has devlist info, it's 263 | * a loaded Windows driver and has no PDOs, 264 | * so skip it. 265 | */ 266 | if (db->windrv_devlist != NULL) 267 | continue; 268 | pdo = db->windrv_object->device_object; 269 | while (pdo != NULL) { 270 | if (pdo->attacheddev->drvobj != drv) { 271 | pdo = pdo->nextdev; 272 | continue; 273 | } 274 | dev = pdo->devext; 275 | pdo = pdo->nextdev; 276 | mtx_unlock(&drvdb_mtx); 277 | device_detach(dev); 278 | mtx_lock(&drvdb_mtx); 279 | } 280 | } 281 | 282 | STAILQ_FOREACH(db, &drvdb_head, link) { 283 | if (db->windrv_object->driver_start == (void *)img) { 284 | r = db; 285 | STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link); 286 | break; 287 | } 288 | } 289 | mtx_unlock(&drvdb_mtx); 290 | 291 | if (r == NULL || drv == NULL) 292 | return (ENOENT); 293 | 294 | /* Destroy any custom extensions that may have been added. */ 295 | drv = r->windrv_object; 296 | while (!IsListEmpty(&drv->driver_extension->usrext)) { 297 | e = RemoveHeadList(&drv->driver_extension->usrext); 298 | ExFreePool(e); 299 | } 300 | 301 | free(drv->driver_extension, M_NDIS_WINDRV); 302 | RtlFreeUnicodeString(&drv->driver_name); 303 | free(drv->driver_start, M_NDIS_WINDRV); 304 | free(drv, M_NDIS_WINDRV); 305 | free(r->windrv_devlist->name, M_NDIS_WINDRV); 306 | free(r->windrv_devlist, M_NDIS_WINDRV); 307 | free(r, M_NDIS_WINDRV); /* Free our DB handle */ 308 | 309 | return (0); 310 | } 311 | 312 | #ifdef __amd64__ 313 | static void 314 | patch_user_shared_data_address(vm_offset_t img, size_t len) 315 | { 316 | unsigned long i, n, max_addr, *addr; 317 | 318 | n = len - sizeof(unsigned long); 319 | max_addr = KI_USER_SHARED_DATA + sizeof(struct kuser_shared_data); 320 | for (i = 0; i < n; i++) { 321 | addr = (unsigned long *)(img + i); 322 | if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { 323 | *addr -= KI_USER_SHARED_DATA; 324 | *addr += (unsigned long)&kuser_data; 325 | } 326 | } 327 | } 328 | #endif 329 | 330 | /* 331 | * Loader routine for actual Windows driver modules, ultimately 332 | * calls the driver's DriverEntry() routine. 333 | */ 334 | static int 335 | windrv_load(vm_offset_t img, size_t len, 336 | uint32_t bustype, void *devlist, void *regvals) 337 | { 338 | struct ansi_string as; 339 | struct image_optional_header *opt_hdr; 340 | driver_entry entry; 341 | struct drvdb_ent *new; 342 | struct driver_object *drv; 343 | int32_t ret; 344 | 345 | if (pe_validate_header(img)) 346 | return (ENOEXEC); 347 | /* 348 | * First step: try to relocate and dynalink the executable 349 | * driver image. 350 | */ 351 | 352 | /* Perform text relocation */ 353 | if (pe_relocate(img)) 354 | return (ENOEXEC); 355 | 356 | /* Dynamically link the NDIS.SYS routines -- required. */ 357 | if (pe_patch_imports(img, "NDIS", ndis_functbl)) 358 | return (ENOEXEC); 359 | 360 | /* Dynamically link the HAL.dll routines -- optional. */ 361 | pe_patch_imports(img, "HAL", hal_functbl); 362 | 363 | /* Dynamically link ntoskrnl.exe -- optional. */ 364 | pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl); 365 | 366 | /* Dynamically link USBD.SYS -- optional */ 367 | pe_patch_imports(img, "USBD", usbd_functbl); 368 | #ifdef __amd64__ 369 | patch_user_shared_data_address(img, len); 370 | #endif 371 | /* Next step: find the driver entry point. */ 372 | pe_get_optional_header(img, &opt_hdr); 373 | entry = (driver_entry)pe_translate_addr(img, 374 | opt_hdr->address_of_entry_point); 375 | 376 | /* Next step: allocate and store a driver object. */ 377 | new = malloc(sizeof(struct drvdb_ent), M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 378 | if (new == NULL) 379 | return (ENOMEM); 380 | 381 | drv = malloc(sizeof(struct driver_object), M_NDIS_WINDRV, 382 | M_NOWAIT|M_ZERO); 383 | if (drv == NULL) { 384 | free (new, M_NDIS_WINDRV); 385 | return (ENOMEM); 386 | } 387 | 388 | /* Allocate a driver extension structure too. */ 389 | drv->driver_extension = malloc(sizeof(struct driver_extension), 390 | M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 391 | if (drv->driver_extension == NULL) { 392 | free(new, M_NDIS_WINDRV); 393 | free(drv, M_NDIS_WINDRV); 394 | return (ENOMEM); 395 | } 396 | 397 | InitializeListHead(&drv->driver_extension->usrext); 398 | 399 | drv->driver_start = (void *)img; 400 | drv->driver_size = len; 401 | 402 | RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH); 403 | if (RtlAnsiStringToUnicodeString(&drv->driver_name, &as, TRUE)) { 404 | free(drv->driver_extension, M_NDIS_WINDRV); 405 | free(drv, M_NDIS_WINDRV); 406 | free(new, M_NDIS_WINDRV); 407 | return (ENOMEM); 408 | } 409 | 410 | /* Now call the DriverEntry() function. */ 411 | ret = MSCALL2(entry, drv, &drv->driver_name); 412 | if (ret) { 413 | RtlFreeUnicodeString(&drv->driver_name); 414 | free(drv->driver_extension, M_NDIS_WINDRV); 415 | free(drv, M_NDIS_WINDRV); 416 | free(new, M_NDIS_WINDRV); 417 | printf("NDIS: driver entry failed; status: 0x%08X\n", ret); 418 | return (ENODEV); 419 | } 420 | 421 | new->windrv_object = drv; 422 | new->windrv_regvals = regvals; 423 | new->windrv_devlist = devlist; 424 | new->windrv_bustype = bustype; 425 | 426 | mtx_lock(&drvdb_mtx); 427 | STAILQ_INSERT_HEAD(&drvdb_head, new, link); 428 | mtx_unlock(&drvdb_mtx); 429 | 430 | return (0); 431 | } 432 | 433 | /* ARGSUSED */ 434 | static int 435 | windrv_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, 436 | int flags __unused, struct thread *td __unused) 437 | { 438 | int ret; 439 | ndis_load_driver_args_t *l; 440 | ndis_unload_driver_args_t *u; 441 | enum ndis_bus_type bustype; 442 | struct ndis_device_type *devlist; 443 | void *image; 444 | char *name; 445 | driver_t *driver = NULL; 446 | devclass_t bus_devclass; 447 | 448 | switch (cmd) { 449 | case NDIS_LOAD_DRIVER: 450 | l = (ndis_load_driver_args_t *)data; 451 | switch (l->bustype) { 452 | case 'p': 453 | bustype = NDIS_PCIBUS; 454 | driver = &ndis_pci_driver; 455 | bus_devclass = devclass_find("pci"); 456 | break; 457 | case 'P': 458 | bustype = NDIS_PCMCIABUS; 459 | driver = &ndis_pccard_driver; 460 | bus_devclass = devclass_find("pccard"); 461 | break; 462 | case 'u': 463 | bustype = NDIS_PNPBUS; 464 | driver = &ndis_usb_driver; 465 | bus_devclass = devclass_find("uhub"); 466 | break; 467 | default: 468 | return (EINVAL); 469 | break; 470 | } 471 | if (l->img == NULL || l->len == 0 || l->namelen == 0 || 472 | l->vendor == 0 || l->device == 0 || l->name == NULL) 473 | return (EINVAL); 474 | 475 | image = malloc(l->len, M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 476 | if (image == NULL) 477 | return (ENOMEM); 478 | 479 | ret = copyin(l->img, image, l->len); 480 | if (ret) { 481 | free(image, M_NDIS_WINDRV); 482 | return (ret); 483 | } 484 | 485 | name = malloc(l->namelen, M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 486 | if (name == NULL) { 487 | free(image, M_NDIS_WINDRV); 488 | return (ENOMEM); 489 | } 490 | 491 | ret = copyin(l->name, name, l->namelen); 492 | if (ret) { 493 | free(name, M_NDIS_WINDRV); 494 | free(image, M_NDIS_WINDRV); 495 | return (ret); 496 | } 497 | 498 | devlist = malloc(sizeof(struct ndis_device_type), M_NDIS_WINDRV, 499 | M_NOWAIT|M_ZERO); 500 | if (devlist == NULL) { 501 | free(name, M_NDIS_WINDRV); 502 | free(image, M_NDIS_WINDRV); 503 | return (ENOMEM); 504 | } 505 | devlist->vendor = l->vendor; 506 | devlist->device = l->device; 507 | devlist->name = name; 508 | ret = windrv_load((vm_offset_t)image, l->len, 509 | bustype, devlist, NULL); 510 | if (ret) { 511 | free(name, M_NDIS_WINDRV); 512 | free(image, M_NDIS_WINDRV); 513 | free(devlist, M_NDIS_WINDRV); 514 | return (ret); 515 | } 516 | mtx_lock(&Giant); 517 | ret = devclass_add_driver(bus_devclass, driver, __INT_MAX, &ndis_devclass); 518 | mtx_unlock(&Giant); 519 | break; 520 | case NDIS_UNLOAD_DRIVER: 521 | u = (ndis_unload_driver_args_t *)data; 522 | ret = windrv_unload((vm_offset_t)u->img); 523 | break; 524 | default: 525 | ret = EINVAL; 526 | break; 527 | } 528 | return (ret); 529 | } 530 | 531 | /* 532 | * Make a new Physical Device Object for a device that was detected/plugged in. 533 | * For us, the PDO is just a way to get at the device_t. 534 | */ 535 | int32_t 536 | windrv_create_pdo(struct driver_object *drv, device_t bsddev) 537 | { 538 | struct device_object *dev; 539 | int32_t ret; 540 | 541 | /* 542 | * This is a new physical device object, which technically 543 | * is the "top of the stack." Consequently, we don't do 544 | * an IoAttachDeviceToDeviceStack() here. 545 | */ 546 | mtx_lock(&drvdb_mtx); 547 | ret = IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev); 548 | mtx_unlock(&drvdb_mtx); 549 | 550 | if (ret) 551 | return (ret); 552 | dev->devext = bsddev; /* Stash pointer to our BSD device handle. */ 553 | return (NDIS_STATUS_SUCCESS); 554 | } 555 | 556 | void 557 | windrv_destroy_pdo(struct driver_object *drv, device_t bsddev) 558 | { 559 | struct device_object *pdo; 560 | 561 | pdo = windrv_find_pdo(drv, bsddev); 562 | if (pdo == NULL) 563 | return; 564 | pdo->devext = NULL; 565 | 566 | mtx_lock(&drvdb_mtx); 567 | IoDeleteDevice(pdo); 568 | mtx_unlock(&drvdb_mtx); 569 | } 570 | 571 | /* 572 | * Given a device_t, find the corresponding PDO in a driver's device list. 573 | */ 574 | struct device_object * 575 | windrv_find_pdo(const struct driver_object *drv, device_t bsddev) 576 | { 577 | struct device_object *pdo; 578 | 579 | mtx_lock(&drvdb_mtx); 580 | for (pdo = drv->device_object; pdo != NULL; pdo = pdo->nextdev) { 581 | if (pdo->devext == bsddev) { 582 | mtx_unlock(&drvdb_mtx); 583 | return (pdo); 584 | } 585 | } 586 | mtx_unlock(&drvdb_mtx); 587 | 588 | return (NULL); 589 | } 590 | 591 | /* 592 | * Add an internally emulated driver to the database. We need this 593 | * to set up an emulated bus driver so that it can receive IRPs. 594 | */ 595 | int 596 | windrv_bus_attach(struct driver_object *drv, const char *name) 597 | { 598 | struct ansi_string as; 599 | struct drvdb_ent *new; 600 | 601 | new = malloc(sizeof(struct drvdb_ent), M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 602 | if (new == NULL) 603 | return (ENOMEM); 604 | 605 | RtlInitAnsiString(&as, name); 606 | if (RtlAnsiStringToUnicodeString(&drv->driver_name, &as, TRUE)) { 607 | free(new, M_NDIS_WINDRV); 608 | return (ENOMEM); 609 | } 610 | 611 | /* 612 | * Set up a fake image pointer to avoid false matches 613 | * in windrv_lookup(). 614 | */ 615 | drv->driver_start = (void *)0xFFFFFFFF; 616 | 617 | new->windrv_object = drv; 618 | new->windrv_devlist = NULL; 619 | new->windrv_regvals = NULL; 620 | 621 | mtx_lock(&drvdb_mtx); 622 | STAILQ_INSERT_HEAD(&drvdb_head, new, link); 623 | mtx_unlock(&drvdb_mtx); 624 | 625 | return (0); 626 | } 627 | 628 | #ifdef __amd64__ 629 | extern void x86_64_wrap(void); 630 | extern void x86_64_wrap_call(void); 631 | extern void x86_64_wrap_end(void); 632 | 633 | void 634 | windrv_wrap(funcptr func, funcptr *wrap, uint8_t argcnt, 635 | enum windrv_wrap_type type) 636 | { 637 | vm_offset_t *calladdr, wrapstart, wrapend, wrapcall; 638 | funcptr p; 639 | 640 | wrapstart = (vm_offset_t)&x86_64_wrap; 641 | wrapend = (vm_offset_t)&x86_64_wrap_end; 642 | wrapcall = (vm_offset_t)&x86_64_wrap_call; 643 | 644 | /* Allocate a new wrapper instance. */ 645 | p = malloc(wrapend - wrapstart, M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 646 | if (p == NULL) 647 | panic("failed to allocate new wrapper instance"); 648 | 649 | /* Copy over the code. */ 650 | bcopy((char *)wrapstart, p, wrapend - wrapstart); 651 | 652 | /* Insert the function address into the new wrapper instance. */ 653 | calladdr = (vm_offset_t *)((char *)p + (wrapcall - wrapstart) + 2); 654 | *calladdr = (vm_offset_t)func; 655 | 656 | *wrap = p; 657 | } 658 | 659 | static struct fpu_cc_ent * 660 | request_fpu_cc_ent(void) 661 | { 662 | struct fpu_cc_ent *ent; 663 | 664 | mtx_lock(&fpu_free_mtx); 665 | if ((ent = LIST_FIRST(&fpu_free_head)) != NULL) { 666 | LIST_REMOVE(ent, entries); 667 | mtx_unlock(&fpu_free_mtx); 668 | mtx_lock(&fpu_busy_mtx); 669 | LIST_INSERT_HEAD(&fpu_busy_head, ent, entries); 670 | mtx_unlock(&fpu_busy_mtx); 671 | return (ent); 672 | } 673 | mtx_unlock(&fpu_free_mtx); 674 | 675 | if ((ent = malloc(sizeof(struct fpu_cc_ent), M_DEVBUF, M_NOWAIT | 676 | M_ZERO)) != NULL) { 677 | ent->ctx = fpu_kern_alloc_ctx(FPU_KERN_NORMAL | 678 | FPU_KERN_NOWAIT); 679 | if (ent->ctx != NULL) { 680 | mtx_lock(&fpu_busy_mtx); 681 | LIST_INSERT_HEAD(&fpu_busy_head, ent, entries); 682 | mtx_unlock(&fpu_busy_mtx); 683 | } else { 684 | free(ent, M_DEVBUF); 685 | ent = NULL; 686 | } 687 | } 688 | 689 | return (ent); 690 | } 691 | 692 | static void 693 | release_fpu_cc_ent(struct fpu_cc_ent *ent) 694 | { 695 | mtx_lock(&fpu_busy_mtx); 696 | LIST_REMOVE(ent, entries); 697 | mtx_unlock(&fpu_busy_mtx); 698 | mtx_lock(&fpu_free_mtx); 699 | LIST_INSERT_HEAD(&fpu_free_head, ent, entries); 700 | mtx_unlock(&fpu_free_mtx); 701 | } 702 | 703 | uint64_t 704 | _x86_64_call1(void *fn, uint64_t a) 705 | { 706 | struct fpu_cc_ent *ent; 707 | uint64_t ret; 708 | 709 | if ((ent = request_fpu_cc_ent()) == NULL) 710 | return (ENOMEM); 711 | fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL); 712 | ret = x86_64_call1(fn, a); 713 | fpu_kern_leave(curthread, ent->ctx); 714 | release_fpu_cc_ent(ent); 715 | 716 | return (ret); 717 | } 718 | 719 | uint64_t 720 | _x86_64_call2(void *fn, uint64_t a, uint64_t b) 721 | { 722 | struct fpu_cc_ent *ent; 723 | uint64_t ret; 724 | 725 | if ((ent = request_fpu_cc_ent()) == NULL) 726 | return (ENOMEM); 727 | fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL); 728 | ret = x86_64_call2(fn, a, b); 729 | fpu_kern_leave(curthread, ent->ctx); 730 | release_fpu_cc_ent(ent); 731 | 732 | return (ret); 733 | } 734 | 735 | uint64_t 736 | _x86_64_call3(void *fn, uint64_t a, uint64_t b, uint64_t c) 737 | { 738 | struct fpu_cc_ent *ent; 739 | uint64_t ret; 740 | 741 | if ((ent = request_fpu_cc_ent()) == NULL) 742 | return (ENOMEM); 743 | fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL); 744 | ret = x86_64_call3(fn, a, b, c); 745 | fpu_kern_leave(curthread, ent->ctx); 746 | release_fpu_cc_ent(ent); 747 | 748 | return (ret); 749 | } 750 | 751 | uint64_t 752 | _x86_64_call4(void *fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d) 753 | { 754 | struct fpu_cc_ent *ent; 755 | uint64_t ret; 756 | 757 | if ((ent = request_fpu_cc_ent()) == NULL) 758 | return (ENOMEM); 759 | fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL); 760 | ret = x86_64_call4(fn, a, b, c, d); 761 | fpu_kern_leave(curthread, ent->ctx); 762 | release_fpu_cc_ent(ent); 763 | 764 | return (ret); 765 | } 766 | 767 | uint64_t 768 | _x86_64_call5(void *fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d, 769 | uint64_t e) 770 | { 771 | struct fpu_cc_ent *ent; 772 | uint64_t ret; 773 | 774 | if ((ent = request_fpu_cc_ent()) == NULL) 775 | return (ENOMEM); 776 | fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL); 777 | ret = x86_64_call5(fn, a, b, c, d, e); 778 | fpu_kern_leave(curthread, ent->ctx); 779 | release_fpu_cc_ent(ent); 780 | 781 | return (ret); 782 | } 783 | 784 | uint64_t 785 | _x86_64_call6(void *fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d, 786 | uint64_t e, uint64_t f) 787 | { 788 | struct fpu_cc_ent *ent; 789 | uint64_t ret; 790 | 791 | if ((ent = request_fpu_cc_ent()) == NULL) 792 | return (ENOMEM); 793 | fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL); 794 | ret = x86_64_call6(fn, a, b, c, d, e, f); 795 | fpu_kern_leave(curthread, ent->ctx); 796 | release_fpu_cc_ent(ent); 797 | 798 | return (ret); 799 | } 800 | #endif /* __amd64__ */ 801 | #ifdef __i386__ 802 | static void windrv_wrap_fastcall(funcptr, funcptr *, uint8_t); 803 | static void windrv_wrap_stdcall(funcptr, funcptr *, uint8_t); 804 | static void windrv_wrap_regparm(funcptr, funcptr *); 805 | 806 | extern void x86_fastcall_wrap(void); 807 | extern void x86_fastcall_wrap_arg(void); 808 | extern void x86_fastcall_wrap_call(void); 809 | extern void x86_fastcall_wrap_end(void); 810 | 811 | static void 812 | windrv_wrap_fastcall(funcptr func, funcptr *wrap, uint8_t argcnt) 813 | { 814 | vm_offset_t *calladdr, wrapstart, wrapend, wrapcall, wraparg; 815 | funcptr p; 816 | uint8_t *argaddr; 817 | 818 | wrapstart = (vm_offset_t)&x86_fastcall_wrap; 819 | wrapend = (vm_offset_t)&x86_fastcall_wrap_end; 820 | wrapcall = (vm_offset_t)&x86_fastcall_wrap_call; 821 | wraparg = (vm_offset_t)&x86_fastcall_wrap_arg; 822 | 823 | /* Allocate a new wrapper instance. */ 824 | p = malloc(wrapend - wrapstart, M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 825 | if (p == NULL) 826 | panic("failed to allocate new wrapper instance"); 827 | 828 | /* Copy over the code. */ 829 | bcopy((char *)wrapstart, p, (wrapend - wrapstart)); 830 | 831 | /* Insert the function address into the new wrapper instance. */ 832 | calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); 833 | *calladdr = (vm_offset_t)func; 834 | 835 | if (argcnt < 3) 836 | argcnt = 0; 837 | else 838 | argcnt -= 2; 839 | 840 | argaddr = (uint8_t *)((char *)p + ((wraparg - wrapstart) + 1)); 841 | *argaddr = argcnt * sizeof(uint32_t); 842 | 843 | *wrap = p; 844 | } 845 | 846 | extern void x86_stdcall_wrap(void); 847 | extern void x86_stdcall_wrap_call(void); 848 | extern void x86_stdcall_wrap_arg(void); 849 | extern void x86_stdcall_wrap_end(void); 850 | 851 | static void 852 | windrv_wrap_stdcall(funcptr func, funcptr *wrap, uint8_t argcnt) 853 | { 854 | vm_offset_t *calladdr, wrapstart, wrapend, wrapcall, wraparg; 855 | funcptr p; 856 | uint8_t *argaddr; 857 | 858 | wrapstart = (vm_offset_t)&x86_stdcall_wrap; 859 | wrapend = (vm_offset_t)&x86_stdcall_wrap_end; 860 | wrapcall = (vm_offset_t)&x86_stdcall_wrap_call; 861 | wraparg = (vm_offset_t)&x86_stdcall_wrap_arg; 862 | 863 | /* Allocate a new wrapper instance. */ 864 | p = malloc(wrapend - wrapstart, M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 865 | if (p == NULL) 866 | panic("failed to allocate new wrapper instance"); 867 | 868 | /* Copy over the code. */ 869 | bcopy((char *)wrapstart, p, wrapend - wrapstart); 870 | 871 | /* Insert the function address into the new wrapper instance. */ 872 | calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); 873 | *calladdr = (vm_offset_t)func; 874 | 875 | argaddr = (uint8_t *)((char *)p + ((wraparg - wrapstart) + 1)); 876 | *argaddr = argcnt * sizeof(uint32_t); 877 | 878 | *wrap = p; 879 | } 880 | 881 | extern void x86_regparm_wrap(void); 882 | extern void x86_regparm_wrap_call(void); 883 | extern void x86_regparm_wrap_end(void); 884 | 885 | static void 886 | windrv_wrap_regparm(funcptr func, funcptr *wrap) 887 | { 888 | funcptr p; 889 | vm_offset_t *calladdr, wrapstart, wrapend, wrapcall; 890 | 891 | wrapstart = (vm_offset_t)&x86_regparm_wrap; 892 | wrapend = (vm_offset_t)&x86_regparm_wrap_end; 893 | wrapcall = (vm_offset_t)&x86_regparm_wrap_call; 894 | 895 | /* Allocate a new wrapper instance. */ 896 | p = malloc(wrapend - wrapstart, M_NDIS_WINDRV, M_NOWAIT|M_ZERO); 897 | if (p == NULL) 898 | panic("failed to allocate new wrapper instance"); 899 | 900 | /* Copy over the code. */ 901 | bcopy((char *)wrapstart, p, wrapend - wrapstart); 902 | 903 | /* Insert the function address into the new wrapper instance. */ 904 | calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); 905 | *calladdr = (vm_offset_t)func; 906 | 907 | *wrap = p; 908 | } 909 | 910 | void 911 | windrv_wrap(funcptr func, funcptr *wrap, uint8_t argcnt, 912 | enum windrv_wrap_type type) 913 | { 914 | switch (type) { 915 | case FASTCALL: 916 | windrv_wrap_fastcall(func, wrap, argcnt); 917 | break; 918 | case STDCALL: 919 | windrv_wrap_stdcall(func, wrap, argcnt); 920 | break; 921 | case REGPARM: 922 | windrv_wrap_regparm(func, wrap); 923 | break; 924 | case CDECL: 925 | windrv_wrap_stdcall(func, wrap, 0); 926 | break; 927 | default: 928 | break; 929 | } 930 | } 931 | #endif /* __i386__ */ 932 | 933 | void 934 | windrv_unwrap(funcptr func) 935 | { 936 | free(func, M_NDIS_WINDRV); 937 | } 938 | 939 | void 940 | windrv_wrap_table(struct image_patch_table *table) 941 | { 942 | struct image_patch_table *p; 943 | 944 | for (p = table; p->func != NULL; p++) 945 | windrv_wrap(p->func, &p->wrap, p->argcnt, p->ftype); 946 | } 947 | 948 | void 949 | windrv_unwrap_table(struct image_patch_table *table) 950 | { 951 | struct image_patch_table *p; 952 | 953 | for (p = table; p->func != NULL; p++) 954 | windrv_unwrap(p->wrap); 955 | } 956 | -------------------------------------------------------------------------------- /src/sys/compat/ndis/kern_ndis.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 3 | * Bill Paul . All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by Bill Paul. 16 | * 4. Neither the name of the author nor the names of any co-contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | * THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | __FBSDID("$FreeBSD$"); 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | #include 63 | #include 64 | 65 | #include "pe_var.h" 66 | #include "resource_var.h" 67 | #include "ntoskrnl_var.h" 68 | #include "ndis_var.h" 69 | #include "hal_var.h" 70 | #include "usbd_var.h" 71 | #include "if_ndisvar.h" 72 | 73 | #define NDIS_FLAG_RDONLY 1 74 | 75 | #ifdef NDIS_DEBUG 76 | int ndis_debug = 0; 77 | SYSCTL_INT(_debug, OID_AUTO, ndis, CTLFLAG_RW, &ndis_debug, 78 | 0, "control debugging printfs"); 79 | #endif 80 | 81 | static void ndis_create_sysctls(struct ndis_softc *); 82 | static void ndis_flush_sysctls(struct ndis_softc *); 83 | static void ndis_free_bufs(struct mdl *); 84 | static void NdisMIndicateStatus(struct ndis_miniport_block *, int32_t, 85 | void *, uint32_t); 86 | static void NdisMIndicateStatusComplete(struct ndis_miniport_block *); 87 | static void NdisMSetInformationComplete(struct ndis_miniport_block *, 88 | int32_t); 89 | static void NdisMQueryInformationComplete(struct ndis_miniport_block *, 90 | int32_t); 91 | static void NdisMResetComplete(struct ndis_miniport_block *, int32_t, 92 | uint8_t); 93 | static void NdisMSendResourcesAvailable(struct ndis_miniport_block *); 94 | static void ndis_interrupt_setup(struct nt_kdpc *, struct device_object *, 95 | struct irp *, struct ndis_softc *); 96 | static void ndis_return_packet_nic(struct device_object *, 97 | struct ndis_miniport_block *); 98 | 99 | static struct image_patch_table kernndis_functbl[] = { 100 | IMPORT_SFUNC(NdisMIndicateStatus, 4), 101 | IMPORT_SFUNC(NdisMIndicateStatusComplete, 1), 102 | IMPORT_SFUNC(NdisMSetInformationComplete, 2), 103 | IMPORT_SFUNC(NdisMQueryInformationComplete, 2), 104 | IMPORT_SFUNC(NdisMResetComplete, 3), 105 | IMPORT_SFUNC(NdisMSendResourcesAvailable, 1), 106 | IMPORT_SFUNC(ndis_interrupt_setup, 4), 107 | IMPORT_SFUNC(ndis_return_packet_nic, 1), 108 | { NULL, NULL, NULL } 109 | }; 110 | 111 | static struct nd_head ndis_devhead; 112 | 113 | MALLOC_DEFINE(M_NDIS_KERN, "ndis_kern", "ndis_kern buffers"); 114 | 115 | /* 116 | * This allows us to export our symbols to other modules. 117 | * Note that we call ourselves 'ndisapi' to avoid a namespace 118 | * collision with if_ndis.ko, which internally calls itself 119 | * 'ndis.' 120 | * 121 | * Note: some of the subsystems depend on each other, so the 122 | * order in which they're started is important. The order of 123 | * importance is: 124 | * 125 | * HAL - spinlocks and IRQL manipulation 126 | * ntoskrnl - DPC and worker threads, object waiting 127 | * windrv - driver/device registration 128 | * 129 | * The HAL should also be the last thing shut down, since 130 | * the ntoskrnl subsystem will use spinlocks right up until 131 | * the DPC and worker threads are terminated. 132 | */ 133 | static int 134 | ndis_modevent(module_t mod, int cmd, void *arg) 135 | { 136 | 137 | switch (cmd) { 138 | case MOD_LOAD: 139 | hal_libinit(); 140 | ntoskrnl_libinit(); 141 | windrv_libinit(); 142 | ndis_libinit(); 143 | usbd_libinit(); 144 | 145 | windrv_wrap_table(kernndis_functbl); 146 | 147 | TAILQ_INIT(&ndis_devhead); 148 | break; 149 | case MOD_SHUTDOWN: 150 | break; 151 | case MOD_UNLOAD: 152 | usbd_libfini(); 153 | ndis_libfini(); 154 | windrv_libfini(); 155 | ntoskrnl_libfini(); 156 | hal_libfini(); 157 | 158 | windrv_unwrap_table(kernndis_functbl); 159 | break; 160 | default: 161 | return (EINVAL); 162 | } 163 | 164 | return (0); 165 | } 166 | DEV_MODULE(ndisapi, ndis_modevent, NULL); 167 | MODULE_VERSION(ndisapi, 3); 168 | 169 | static void 170 | NdisMSendResourcesAvailable(struct ndis_miniport_block *block) 171 | { 172 | } 173 | 174 | static void 175 | NdisMIndicateStatus(struct ndis_miniport_block *block, int32_t status, 176 | void *sbuf, uint32_t slen) 177 | { 178 | } 179 | 180 | static void 181 | NdisMIndicateStatusComplete(struct ndis_miniport_block *block) 182 | { 183 | } 184 | 185 | static void 186 | NdisMSetInformationComplete(struct ndis_miniport_block *block, int32_t status) 187 | { 188 | block->setstat = status; 189 | KeSetEvent(&block->setevent, IO_NO_INCREMENT, FALSE); 190 | } 191 | 192 | static void 193 | NdisMQueryInformationComplete(struct ndis_miniport_block *block, int32_t status) 194 | { 195 | block->getstat = status; 196 | KeSetEvent(&block->getevent, IO_NO_INCREMENT, FALSE); 197 | } 198 | 199 | static void 200 | NdisMResetComplete(struct ndis_miniport_block *block, int32_t status, 201 | uint8_t addressingreset) 202 | { 203 | block->resetstat = status; 204 | KeSetEvent(&block->resetevent, IO_NO_INCREMENT, FALSE); 205 | } 206 | 207 | static void 208 | ndis_create_sysctls(struct ndis_softc *sc) 209 | { 210 | struct ndis_cfg *cfg = sc->ndis_regvals; 211 | char buf[32]; 212 | struct sysctl_oid *oidp; 213 | struct sysctl_ctx_entry *e; 214 | 215 | TAILQ_INIT(&sc->ndis_cfglist_head); 216 | 217 | /* Add the driver-specific registry keys. */ 218 | for (; cfg != NULL;) { 219 | if (cfg->key == NULL) 220 | break; 221 | if (cfg->idx != sc->ndis_devidx) { 222 | cfg++; 223 | continue; 224 | } 225 | 226 | /* See if we already have a sysctl with this name */ 227 | oidp = NULL; 228 | TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 229 | oidp = e->entry; 230 | if (strcasecmp(oidp->oid_name, cfg->key) == 0) 231 | break; 232 | oidp = NULL; 233 | } 234 | if (oidp != NULL) { 235 | cfg++; 236 | continue; 237 | } 238 | 239 | ndis_add_sysctl(sc, cfg->key, cfg->desc, cfg->val, CTLFLAG_RW); 240 | cfg++; 241 | } 242 | 243 | /* Now add a couple of builtin keys. */ 244 | /* 245 | * Environment can be either Windows (0) or WindowsNT (1). 246 | * We qualify as the latter. 247 | */ 248 | ndis_add_sysctl(sc, "Environment", "Environment", "1", NDIS_FLAG_RDONLY); 249 | /* NDIS version should be 5.1. */ 250 | ndis_add_sysctl(sc, "NdisVersion", "NDIS API Version", 251 | "0x00050001", NDIS_FLAG_RDONLY); 252 | ndis_add_sysctl(sc, "SlotNumber", "Slot Number", "01", NDIS_FLAG_RDONLY); 253 | ndis_add_sysctl(sc, "NetCfgInstanceId", "NetCfgInstanceId", 254 | "{12345678-1234-5678-CAFE-123456789ABC}", NDIS_FLAG_RDONLY); 255 | ndis_add_sysctl(sc, "DriverDesc", "Driver Description", 256 | "NDIS Network Adapter", NDIS_FLAG_RDONLY); 257 | /* Bus type (PCI, PCMCIA, etc...) */ 258 | sprintf(buf, "%d", sc->ndis_bus_type); 259 | ndis_add_sysctl(sc, "BusType", "Bus Type", buf, NDIS_FLAG_RDONLY); 260 | if (sc->ndis_res_io != NULL) { 261 | sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 262 | ndis_add_sysctl(sc, "IOBaseAddress", 263 | "Base I/O Address", buf, NDIS_FLAG_RDONLY); 264 | } 265 | if (sc->ndis_irq != NULL) { 266 | sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 267 | ndis_add_sysctl(sc, "InterruptNumber", 268 | "Interrupt Number", buf, NDIS_FLAG_RDONLY); 269 | } 270 | } 271 | 272 | int 273 | ndis_add_sysctl(struct ndis_softc *sc, char *key, char *desc, char *val, 274 | int flag_rdonly) 275 | { 276 | struct ndis_cfglist *cfg; 277 | 278 | cfg = malloc(sizeof(struct ndis_cfglist), M_NDIS_KERN, M_NOWAIT|M_ZERO); 279 | if (cfg == NULL) 280 | return (ENOMEM); 281 | cfg->ndis_cfg.key = strdup(key, M_NDIS_KERN); 282 | if (desc == NULL) { 283 | cfg->ndis_cfg.desc = NULL; 284 | } else 285 | cfg->ndis_cfg.desc = strdup(desc, M_NDIS_KERN); 286 | cfg->ndis_cfg.val = strdup(val, M_NDIS_KERN); 287 | 288 | TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 289 | if (flag_rdonly != 0) { 290 | cfg->ndis_oid = 291 | SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 292 | SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 293 | OID_AUTO, cfg->ndis_cfg.key, CTLFLAG_RD, 294 | cfg->ndis_cfg.val, sizeof(cfg->ndis_cfg.val), 295 | cfg->ndis_cfg.desc); 296 | } else { 297 | cfg->ndis_oid = 298 | SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 299 | SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 300 | OID_AUTO, cfg->ndis_cfg.key, CTLFLAG_RW, 301 | cfg->ndis_cfg.val, sizeof(cfg->ndis_cfg.val), 302 | cfg->ndis_cfg.desc); 303 | } 304 | return (0); 305 | } 306 | 307 | static void 308 | ndis_flush_sysctls(struct ndis_softc *sc) 309 | { 310 | struct ndis_cfglist *cfg; 311 | struct sysctl_ctx_list *clist; 312 | 313 | clist = device_get_sysctl_ctx(sc->ndis_dev); 314 | 315 | while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 316 | cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 317 | TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 318 | sysctl_ctx_entry_del(clist, cfg->ndis_oid); 319 | sysctl_remove_oid(cfg->ndis_oid, 1, 0); 320 | free(cfg->ndis_cfg.key, M_NDIS_KERN); 321 | free(cfg->ndis_cfg.desc, M_NDIS_KERN); 322 | free(cfg->ndis_cfg.val, M_NDIS_KERN); 323 | free(cfg, M_NDIS_KERN); 324 | } 325 | } 326 | 327 | void * 328 | ndis_get_routine_address(struct image_patch_table *functbl, char *name) 329 | { 330 | int i; 331 | 332 | for (i = 0; functbl[i].name != NULL; i++) 333 | if (strcmp(name, functbl[i].name) == 0) 334 | return (functbl[i].wrap); 335 | return (NULL); 336 | } 337 | 338 | static void 339 | ndis_return_packet_nic(struct device_object *dobj, 340 | struct ndis_miniport_block *block) 341 | { 342 | struct ndis_miniport_characteristics *ch; 343 | struct ndis_packet *p; 344 | uint8_t irql; 345 | struct list_entry *l; 346 | 347 | KASSERT(block != NULL, ("no block")); 348 | KASSERT(block->miniport_adapter_ctx != NULL, ("no adapter")); 349 | ch = IoGetDriverObjectExtension(dobj->drvobj, (void *)1); 350 | KASSERT(ch->return_packet_func != NULL, ("no return_packet")); 351 | KeAcquireSpinLock(&block->returnlock, &irql); 352 | while (!IsListEmpty(&block->returnlist)) { 353 | l = RemoveHeadList(&block->returnlist); 354 | p = CONTAINING_RECORD(l, struct ndis_packet, list); 355 | InitializeListHead(&p->list); 356 | KeReleaseSpinLock(&block->returnlock, irql); 357 | MSCALL2(ch->return_packet_func, block->miniport_adapter_ctx, p); 358 | KeAcquireSpinLock(&block->returnlock, &irql); 359 | } 360 | KeReleaseSpinLock(&block->returnlock, irql); 361 | } 362 | 363 | void 364 | ndis_return_packet(struct mbuf *m, void *buf, void *arg) 365 | { 366 | struct ndis_packet *p = arg; 367 | struct ndis_miniport_block *block; 368 | 369 | p->refcnt--; 370 | if (p->refcnt) 371 | return; 372 | 373 | block = ((struct ndis_softc *)p->softc)->ndis_block; 374 | KeAcquireSpinLockAtDpcLevel(&block->returnlock); 375 | InitializeListHead(&p->list); 376 | InsertHeadList(&block->returnlist, &p->list); 377 | KeReleaseSpinLockFromDpcLevel(&block->returnlock); 378 | 379 | IoQueueWorkItem(block->returnitem, 380 | (io_workitem_func)kernndis_functbl[7].wrap, CRITICAL, block); 381 | 382 | return; 383 | } 384 | 385 | static void 386 | ndis_free_bufs(struct mdl *b0) 387 | { 388 | struct mdl *next; 389 | 390 | while (b0 != NULL) { 391 | next = b0->next; 392 | IoFreeMdl(b0); 393 | b0 = next; 394 | } 395 | } 396 | 397 | void 398 | ndis_free_packet(struct ndis_packet *p) 399 | { 400 | KASSERT(p != NULL, ("no packet")); 401 | ndis_free_bufs(p->private.head); 402 | NdisFreePacket(p); 403 | } 404 | 405 | int 406 | ndis_convert_res(struct ndis_softc *sc) 407 | { 408 | struct cm_partial_resource_list *rl = NULL; 409 | struct cm_partial_resource_desc *prd = NULL; 410 | struct resource_list *brl; 411 | struct resource_list_entry *brle; 412 | 413 | rl = malloc(sizeof(struct cm_partial_resource_list) + 414 | (sizeof(struct cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 415 | M_NDIS_KERN, M_NOWAIT|M_ZERO); 416 | if (rl == NULL) 417 | return (ENOMEM); 418 | 419 | rl->version = 1; 420 | rl->revision = 1; 421 | rl->count = sc->ndis_rescnt; 422 | prd = rl->partial_descs; 423 | 424 | brl = BUS_GET_RESOURCE_LIST(sc->ndis_dev, sc->ndis_dev); 425 | if (brl != NULL) { 426 | STAILQ_FOREACH(brle, brl, link) { 427 | switch (brle->type) { 428 | case SYS_RES_IOPORT: 429 | prd->type = CmResourceTypePort; 430 | prd->flags = CM_RESOURCE_PORT_IO; 431 | prd->sharedisp = 432 | CM_RESOURCE_SHARE_DEVICE_EXCLUSIVE; 433 | prd->u.port.start = brle->start; 434 | prd->u.port.len = brle->count; 435 | break; 436 | case SYS_RES_MEMORY: 437 | prd->type = CmResourceTypeMemory; 438 | prd->flags = CM_RESOURCE_MEMORY_READ_WRITE; 439 | prd->sharedisp = 440 | CM_RESOURCE_SHARE_DEVICE_EXCLUSIVE; 441 | prd->u.mem.start = brle->start; 442 | prd->u.mem.len = brle->count; 443 | break; 444 | case SYS_RES_IRQ: 445 | prd->type = CmResourceTypeInterrupt; 446 | prd->flags = 0; 447 | /* 448 | * Always mark interrupt resources as 449 | * shared, since in our implementation, 450 | * they will be. 451 | */ 452 | prd->sharedisp = CM_RESOURCE_SHARE_SHARED; 453 | prd->u.intr.level = brle->start; 454 | prd->u.intr.vector = brle->start; 455 | prd->u.intr.affinity = 0; 456 | break; 457 | default: 458 | break; 459 | } 460 | prd++; 461 | } 462 | } 463 | 464 | sc->ndis_block->rlist = rl; 465 | 466 | return (0); 467 | } 468 | 469 | /* 470 | * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 471 | * packet, it will hand it to us in the form of an ndis_packet, 472 | * which we need to convert to an mbuf that is then handed off 473 | * to the stack. Note: we configure the mbuf list so that it uses 474 | * the memory regions specified by the mdl structures in 475 | * the ndis_packet as external storage. In most cases, this will 476 | * point to a memory region allocated by the driver (either by 477 | * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 478 | * the driver to handle free()ing this region for us, so we set up 479 | * a dummy no-op free handler for it. 480 | */ 481 | int 482 | ndis_ptom(struct mbuf **m0, struct ndis_packet *p) 483 | { 484 | struct mbuf *m = NULL, *prev = NULL; 485 | struct mdl *buf; 486 | struct ndis_packet_private *priv; 487 | uint32_t totlen = 0; 488 | struct ifnet *ifp; 489 | struct ether_header *eh; 490 | int diff; 491 | 492 | KASSERT(p != NULL, ("no packet")); 493 | priv = &p->private; 494 | p->refcnt = 0; 495 | 496 | for (buf = priv->head; buf != NULL; buf = buf->next) { 497 | if (buf == priv->head) 498 | MGETHDR(m, M_NOWAIT, MT_HEADER); 499 | else 500 | MGET(m, M_NOWAIT, MT_DATA); 501 | if (m == NULL) { 502 | m_freem(*m0); 503 | *m0 = NULL; 504 | return (ENOBUFS); 505 | } 506 | m->m_len = MmGetMdlByteCount(buf); 507 | m->m_data = MmGetMdlVirtualAddress(buf); 508 | MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 509 | m->m_data, p, 0, EXT_NET_DRV); 510 | p->refcnt++; 511 | 512 | totlen += m->m_len; 513 | if (m->m_flags & M_PKTHDR) 514 | *m0 = m; 515 | else 516 | prev->m_next = m; 517 | prev = m; 518 | } 519 | 520 | /* 521 | * This is a hack to deal with the Marvell 8335 driver 522 | * which, when associated with an AP in WPA-PSK mode, 523 | * seems to overpad its frames by 8 bytes. I don't know 524 | * that the extra 8 bytes are for, and they're not there 525 | * in open mode, so for now clamp the frame size at 1514 526 | * until I can figure out how to deal with this properly, 527 | * otherwise if_ethersubr() will spank us by discarding 528 | * the 'oversize' frames. 529 | */ 530 | eh = mtod((*m0), struct ether_header *); 531 | ifp = ((struct ndis_softc *)p->softc)->ndis_ifp; 532 | if (totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) { 533 | diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE); 534 | totlen -= diff; 535 | m->m_len -= diff; 536 | } 537 | (*m0)->m_pkthdr.len = totlen; 538 | 539 | return (0); 540 | } 541 | 542 | /* 543 | * Create an NDIS packet from an mbuf chain. 544 | * This is used mainly when transmitting packets, where we need 545 | * to turn an mbuf off an interface's send queue and transform it 546 | * into an NDIS packet which will be fed into the NDIS driver's 547 | * send routine. 548 | * 549 | * NDIS packets consist of two parts: an ndis_packet structure, 550 | * which is vaguely analagous to the pkthdr portion of an mbuf, 551 | * and one or more mdl structures, which define the 552 | * actual memory segments in which the packet data resides. 553 | * We need to allocate one mdl for each mbuf in a chain, 554 | * plus one ndis_packet as the header. 555 | */ 556 | int 557 | ndis_mtop(struct mbuf *m0, struct ndis_packet **p) 558 | { 559 | struct mbuf *m; 560 | struct mdl *buf = NULL, *prev = NULL; 561 | struct ndis_packet_private *priv; 562 | 563 | KASSERT(*p != NULL, ("no packet")); 564 | priv = &(*p)->private; 565 | priv->total_length = m0->m_pkthdr.len; 566 | 567 | for (m = m0; m != NULL; m = m->m_next) { 568 | if (m->m_len == 0) 569 | continue; 570 | buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 571 | if (buf == NULL) { 572 | ndis_free_packet(*p); 573 | *p = NULL; 574 | return (ENOMEM); 575 | } 576 | MmBuildMdlForNonPagedPool(buf); 577 | 578 | if (priv->head == NULL) 579 | priv->head = buf; 580 | else 581 | prev->next = buf; 582 | prev = buf; 583 | } 584 | 585 | priv->tail = buf; 586 | 587 | return (0); 588 | } 589 | 590 | static int 591 | ndis_request_info(uint32_t req, struct ndis_softc *sc, uint32_t oid, 592 | void *buf, uint32_t buflen, uint32_t *written, uint32_t *needed) 593 | { 594 | int64_t duetime; 595 | int32_t rval, w = 0, n = 0; 596 | 597 | if (!written) 598 | written = &w; 599 | if (!needed) 600 | needed = &n; 601 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 602 | KASSERT(sc->ndis_block != NULL, ("no block")); 603 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 604 | KASSERT(sc->ndis_chars->query_info_func != NULL, ("no query_info")); 605 | KASSERT(sc->ndis_chars->set_info_func != NULL, ("no set_info")); 606 | /* 607 | * According to the NDIS spec, MiniportQueryInformation() 608 | * and MiniportSetInformation() requests are handled serially: 609 | * once one request has been issued, we must wait for it to 610 | * finish before allowing another request to proceed. 611 | */ 612 | if (req == NDIS_REQUEST_QUERY_INFORMATION) { 613 | KeAcquireSpinLockAtDpcLevel(&sc->ndis_block->lock); 614 | rval = MSCALL6(sc->ndis_chars->query_info_func, 615 | sc->ndis_block->miniport_adapter_ctx, 616 | oid, buf, buflen, written, needed); 617 | if (rval == NDIS_STATUS_PENDING) { 618 | duetime = (5 * 1000000) * -10; 619 | KeWaitForSingleObject(&sc->ndis_block->getevent, 620 | 0, 0, FALSE, &duetime); 621 | rval = sc->ndis_block->getstat; 622 | } 623 | KeReleaseSpinLockFromDpcLevel(&sc->ndis_block->lock); 624 | TRACE(NDBG_GET, "req %u sc %p oid %08X buf %p buflen %u " 625 | "written %u needed %u rval %08X\n", 626 | req, sc, oid, buf, buflen, *written, *needed, rval); 627 | } else if (req == NDIS_REQUEST_SET_INFORMATION) { 628 | KeAcquireSpinLockAtDpcLevel(&sc->ndis_block->lock); 629 | rval = MSCALL6(sc->ndis_chars->set_info_func, 630 | sc->ndis_block->miniport_adapter_ctx, 631 | oid, buf, buflen, written, needed); 632 | if (rval == NDIS_STATUS_PENDING) { 633 | duetime = (5 * 1000000) * -10; 634 | KeWaitForSingleObject(&sc->ndis_block->setevent, 635 | 0, 0, FALSE, &duetime); 636 | rval = sc->ndis_block->setstat; 637 | } 638 | KeReleaseSpinLockFromDpcLevel(&sc->ndis_block->lock); 639 | TRACE(NDBG_SET, "req %u sc %p oid %08X buf %p buflen %u " 640 | "written %u needed %u rval %08X\n", 641 | req, sc, oid, buf, buflen, *written, *needed, rval); 642 | } else 643 | return (NDIS_STATUS_NOT_SUPPORTED); 644 | return (rval); 645 | } 646 | 647 | int 648 | ndis_get(struct ndis_softc *sc, uint32_t oid, void *val, uint32_t len) 649 | { 650 | return (ndis_request_info(NDIS_REQUEST_QUERY_INFORMATION, 651 | sc, oid, val, len, NULL, NULL)); 652 | } 653 | 654 | int 655 | ndis_get_int(struct ndis_softc *sc, uint32_t oid, uint32_t *val) 656 | { 657 | return (ndis_request_info(NDIS_REQUEST_QUERY_INFORMATION, 658 | sc, oid, val, sizeof(uint32_t), NULL, NULL)); 659 | } 660 | 661 | int 662 | ndis_get_info(struct ndis_softc *sc, uint32_t oid, void *buf, uint32_t buflen, 663 | uint32_t *written, uint32_t *needed) 664 | { 665 | return (ndis_request_info(NDIS_REQUEST_QUERY_INFORMATION, 666 | sc, oid, buf, buflen, written, needed)); 667 | } 668 | 669 | int 670 | ndis_set(struct ndis_softc *sc, uint32_t oid, void *val, uint32_t len) 671 | { 672 | return (ndis_request_info(NDIS_REQUEST_SET_INFORMATION, 673 | sc, oid, val, len, NULL, NULL)); 674 | } 675 | 676 | int 677 | ndis_set_int(struct ndis_softc *sc, uint32_t oid, uint32_t val) 678 | { 679 | return (ndis_request_info(NDIS_REQUEST_SET_INFORMATION, 680 | sc, oid, &val, sizeof(uint32_t), NULL, NULL)); 681 | } 682 | 683 | int 684 | ndis_set_info(struct ndis_softc *sc, uint32_t oid, void *buf, uint32_t buflen, 685 | uint32_t *written, uint32_t *needed) 686 | { 687 | return (ndis_request_info(NDIS_REQUEST_SET_INFORMATION, 688 | sc, oid, buf, buflen, written, needed)); 689 | } 690 | 691 | void 692 | ndis_send_packets(struct ndis_softc *sc, struct ndis_packet **packets, 693 | uint32_t cnt) 694 | { 695 | int i; 696 | struct ndis_packet *p; 697 | uint8_t irql = 0; 698 | 699 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 700 | KASSERT(sc->ndis_block != NULL, ("no block")); 701 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 702 | KASSERT(sc->ndis_block->send_done_func != NULL, ("no send_done")); 703 | KASSERT(sc->ndis_chars->send_packets_func != NULL, ("no send_packets")); 704 | if (NDIS_SERIALIZED(sc->ndis_block)) 705 | KeAcquireSpinLock(&sc->ndis_block->lock, &irql); 706 | MSCALL3(sc->ndis_chars->send_packets_func, 707 | sc->ndis_block->miniport_adapter_ctx, packets, cnt); 708 | for (i = 0; i < cnt; i++) { 709 | p = packets[i]; 710 | /* 711 | * Either the driver already handed the packet to 712 | * ndis_txeof() due to a failure, or it wants to keep 713 | * it and release it asynchronously later. Skip to the 714 | * next one. 715 | */ 716 | if (p == NULL || p->oob.status == NDIS_STATUS_PENDING) 717 | continue; 718 | MSCALL3(sc->ndis_block->send_done_func, 719 | sc->ndis_block, p, p->oob.status); 720 | } 721 | if (NDIS_SERIALIZED(sc->ndis_block)) 722 | KeReleaseSpinLock(&sc->ndis_block->lock, irql); 723 | } 724 | 725 | int32_t 726 | ndis_send_packet(struct ndis_softc *sc, struct ndis_packet *packet) 727 | { 728 | int32_t status; 729 | uint8_t irql = 0; 730 | 731 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 732 | KASSERT(sc->ndis_block != NULL, ("no block")); 733 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 734 | KASSERT(sc->ndis_block->send_done_func != NULL, ("no send_done")); 735 | KASSERT(sc->ndis_chars->send_func != NULL, ("no send")); 736 | if (NDIS_SERIALIZED(sc->ndis_block)) 737 | KeAcquireSpinLock(&sc->ndis_block->lock, &irql); 738 | status = MSCALL3(sc->ndis_chars->send_func, 739 | sc->ndis_block->miniport_adapter_ctx, packet, 740 | packet->private.flags); 741 | if (status == NDIS_STATUS_PENDING) { 742 | if (NDIS_SERIALIZED(sc->ndis_block)) 743 | KeReleaseSpinLock(&sc->ndis_block->lock, irql); 744 | return (0); 745 | } 746 | MSCALL3(sc->ndis_block->send_done_func, sc->ndis_block, packet, status); 747 | if (NDIS_SERIALIZED(sc->ndis_block)) 748 | KeReleaseSpinLock(&sc->ndis_block->lock, irql); 749 | return (status); 750 | } 751 | 752 | int 753 | ndis_init_dma(struct ndis_softc *sc) 754 | { 755 | int i; 756 | 757 | sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 758 | M_NDIS_KERN, M_NOWAIT|M_ZERO); 759 | if (sc->ndis_tmaps == NULL) 760 | return (ENOMEM); 761 | for (i = 0; i < sc->ndis_maxpkts; i++) { 762 | if (bus_dmamap_create(sc->ndis_ttag, 0, 763 | &sc->ndis_tmaps[i]) != 0) { 764 | free(sc->ndis_tmaps, M_NDIS_KERN); 765 | return (ENODEV); 766 | } 767 | } 768 | return (0); 769 | } 770 | 771 | void 772 | ndis_destroy_dma(struct ndis_softc *sc) 773 | { 774 | int i; 775 | 776 | for (i = 0; i < sc->ndis_maxpkts; i++) { 777 | if (sc->ndis_txarray[i] != NULL) 778 | ndis_free_packet(sc->ndis_txarray[i]); 779 | bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 780 | } 781 | free(sc->ndis_tmaps, M_NDIS_KERN); 782 | bus_dma_tag_destroy(sc->ndis_ttag); 783 | } 784 | 785 | int32_t 786 | ndis_reset_nic(struct ndis_softc *sc) 787 | { 788 | int32_t rval; 789 | uint8_t addressing_reset; 790 | uint8_t irql = 0; 791 | 792 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 793 | KASSERT(sc->ndis_block != NULL, ("no block")); 794 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 795 | KASSERT(sc->ndis_chars->reset_func != NULL, ("no reset")); 796 | if (NDIS_SERIALIZED(sc->ndis_block)) 797 | KeAcquireSpinLock(&sc->ndis_block->lock, &irql); 798 | rval = MSCALL2(sc->ndis_chars->reset_func, 799 | &addressing_reset, sc->ndis_block->miniport_adapter_ctx); 800 | if (NDIS_SERIALIZED(sc->ndis_block)) 801 | KeReleaseSpinLock(&sc->ndis_block->lock, irql); 802 | if (rval == NDIS_STATUS_PENDING) { 803 | KeWaitForSingleObject(&sc->ndis_block->resetevent, 0, 0, 804 | FALSE, NULL); 805 | rval = sc->ndis_block->resetstat; 806 | } 807 | if (rval) 808 | device_printf(sc->ndis_dev, "failed to reset device; " 809 | "status: 0x%08X\n", rval); 810 | return (rval); 811 | } 812 | 813 | uint8_t 814 | ndis_check_for_hang_nic(struct ndis_softc *sc) 815 | { 816 | 817 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 818 | KASSERT(sc->ndis_block != NULL, ("no block")); 819 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 820 | if (sc->ndis_chars->check_hang_func == NULL) 821 | return (FALSE); 822 | return (MSCALL1(sc->ndis_chars->check_hang_func, 823 | sc->ndis_block->miniport_adapter_ctx)); 824 | } 825 | 826 | void 827 | ndis_disable_interrupts_nic(struct ndis_softc *sc) 828 | { 829 | 830 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 831 | KASSERT(sc->ndis_block != NULL, ("no block")); 832 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 833 | if (sc->ndis_chars->disable_interrupts_func != NULL) 834 | MSCALL1(sc->ndis_chars->disable_interrupts_func, 835 | sc->ndis_block->miniport_adapter_ctx); 836 | } 837 | 838 | void 839 | ndis_enable_interrupts_nic(struct ndis_softc *sc) 840 | { 841 | 842 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 843 | KASSERT(sc->ndis_block != NULL, ("no block")); 844 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 845 | if (sc->ndis_chars->enable_interrupts_func != NULL) 846 | MSCALL1(sc->ndis_chars->enable_interrupts_func, 847 | sc->ndis_block->miniport_adapter_ctx); 848 | } 849 | 850 | void 851 | ndis_halt_nic(struct ndis_softc *sc) 852 | { 853 | 854 | flush_queue(); 855 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 856 | KASSERT(sc->ndis_block != NULL, ("no block")); 857 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 858 | KASSERT(sc->ndis_chars->halt_func != NULL, ("no halt")); 859 | KASSERT(sc->ndis_block->device_ctx != NULL, ("already halted")); 860 | NDIS_LOCK(sc); 861 | sc->ndis_block->device_ctx = NULL; 862 | NDIS_UNLOCK(sc); 863 | MSCALL1(sc->ndis_chars->halt_func, sc->ndis_block->miniport_adapter_ctx); 864 | } 865 | 866 | void 867 | ndis_shutdown_nic(struct ndis_softc *sc) 868 | { 869 | 870 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 871 | KASSERT(sc->ndis_block != NULL, ("no block")); 872 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 873 | KASSERT(sc->ndis_chars->shutdown_func != NULL, ("no shutdown")); 874 | if (sc->ndis_chars->reserved0 == NULL) 875 | MSCALL1(sc->ndis_chars->shutdown_func, 876 | sc->ndis_block->miniport_adapter_ctx); 877 | else 878 | MSCALL1(sc->ndis_chars->shutdown_func, 879 | sc->ndis_chars->reserved0); 880 | } 881 | 882 | void 883 | ndis_pnp_event_nic(struct ndis_softc *sc, uint32_t event, uint32_t profile) 884 | { 885 | 886 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 887 | KASSERT(sc->ndis_block != NULL, ("no block")); 888 | KASSERT(sc->ndis_block->miniport_adapter_ctx != NULL, ("no adapter")); 889 | if (sc->ndis_chars->pnp_event_notify_func == NULL) 890 | return; 891 | switch (event) { 892 | case NDIS_DEVICE_PNP_EVENT_SURPRISE_REMOVED: 893 | if (sc->ndis_block->flags & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) 894 | MSCALL4(sc->ndis_chars->pnp_event_notify_func, 895 | sc->ndis_block->miniport_adapter_ctx, 896 | event, NULL, 0); 897 | break; 898 | case NDIS_DEVICE_PNP_EVENT_POWER_PROFILE_CHANGED: 899 | MSCALL4(sc->ndis_chars->pnp_event_notify_func, 900 | sc->ndis_block->miniport_adapter_ctx, 901 | event, &profile, sizeof(profile)); 902 | break; 903 | default: 904 | break; 905 | } 906 | } 907 | 908 | int32_t 909 | ndis_init_nic(struct ndis_softc *sc) 910 | { 911 | int32_t rval, status = 0; 912 | enum ndis_medium medium_array[] = { NDIS_MEDIUM_802_3 }; 913 | uint32_t chosen_medium = 0; 914 | 915 | KASSERT(sc->ndis_chars != NULL, ("no chars")); 916 | KASSERT(sc->ndis_block != NULL, ("no block")); 917 | KASSERT(sc->ndis_chars->init_func != NULL, ("no init")); 918 | KASSERT(sc->ndis_block->device_ctx == NULL, ("already initialized")); 919 | rval = MSCALL6(sc->ndis_chars->init_func, &status, &chosen_medium, 920 | medium_array, sizeof(medium_array) / sizeof(medium_array[0]), 921 | sc->ndis_block, sc->ndis_block); 922 | NDIS_LOCK(sc); 923 | if (rval == NDIS_STATUS_SUCCESS) 924 | sc->ndis_block->device_ctx = sc; 925 | else { 926 | device_printf(sc->ndis_dev, "failed to initialize device; " 927 | "status: 0x%08X\n", rval); 928 | } 929 | NDIS_UNLOCK(sc); 930 | return (rval); 931 | } 932 | 933 | static void 934 | ndis_interrupt_setup(struct nt_kdpc *dpc, struct device_object *dobj, 935 | struct irp *ip, struct ndis_softc *sc) 936 | { 937 | struct ndis_miniport_interrupt *intr; 938 | 939 | KASSERT(sc->ndis_block != NULL, ("no block")); 940 | KASSERT(sc->ndis_block->interrupt != NULL, ("no interrupt")); 941 | intr = sc->ndis_block->interrupt; 942 | KeAcquireSpinLockAtDpcLevel(&intr->dpc_count_lock); 943 | KeResetEvent(&intr->dpc_completed_event); 944 | if (KeInsertQueueDpc(&intr->interrupt_dpc, NULL, NULL) == TRUE) 945 | intr->dpc_count++; 946 | KeReleaseSpinLockFromDpcLevel(&intr->dpc_count_lock); 947 | } 948 | 949 | int32_t 950 | ndis_load_driver(struct driver_object *drv, struct device_object *pdo) 951 | { 952 | struct device_object *fdo; 953 | struct ndis_miniport_block *block; 954 | struct ndis_softc *sc; 955 | int32_t status; 956 | 957 | sc = device_get_softc(pdo->devext); 958 | ndis_create_sysctls(sc); 959 | if (sc->ndis_bus_type == NDIS_PCMCIABUS || 960 | sc->ndis_bus_type == NDIS_PCIBUS) { 961 | status = bus_setup_intr(sc->ndis_dev, sc->ndis_irq, 962 | INTR_TYPE_NET|INTR_MPSAFE, NULL, ntoskrnl_intr, NULL, 963 | &sc->ndis_intrhand); 964 | if (status) { 965 | device_printf(sc->ndis_dev, "couldn't setup" 966 | "interrupt; (%d)\n", status); 967 | return (NDIS_STATUS_FAILURE); 968 | } 969 | } 970 | 971 | status = IoCreateDevice(drv, sizeof(struct ndis_miniport_block), NULL, 972 | FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 973 | if (status != NDIS_STATUS_SUCCESS) 974 | return (status); 975 | 976 | block = fdo->devext; 977 | block->filter_dbs.ethdb = block; 978 | block->filter_dbs.trdb = block; 979 | block->filter_dbs.fddidb = block; 980 | block->filter_dbs.arcdb = block; 981 | block->deviceobj = fdo; 982 | block->physdeviceobj = pdo; 983 | block->nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 984 | KeInitializeSpinLock(&block->lock); 985 | KeInitializeSpinLock(&block->returnlock); 986 | KeInitializeEvent(&block->getevent, SYNCHRONIZATION_EVENT, FALSE); 987 | KeInitializeEvent(&block->setevent, SYNCHRONIZATION_EVENT, FALSE); 988 | KeInitializeEvent(&block->resetevent, SYNCHRONIZATION_EVENT, FALSE); 989 | InitializeListHead(&block->parmlist); 990 | InitializeListHead(&block->returnlist); 991 | block->returnitem = IoAllocateWorkItem(fdo); 992 | 993 | /* 994 | * Stash pointers to the miniport block and miniport 995 | * characteristics info in the if_ndis softc so the 996 | * UNIX wrapper driver can get to them later. 997 | */ 998 | sc->ndis_block = block; 999 | sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 1000 | 1001 | /* 1002 | * If the driver has a MiniportTransferData() function, 1003 | * we should allocate a private RX packet pool. 1004 | */ 1005 | if (sc->ndis_chars->transfer_data_func != NULL) { 1006 | NdisAllocatePacketPool(&status, &block->rxpool, 1007 | 32, PROTOCOL_RESERVED_SIZE_IN_PACKET); 1008 | if (status != NDIS_STATUS_SUCCESS) { 1009 | IoDetachDevice(block->nextdeviceobj); 1010 | IoDeleteDevice(fdo); 1011 | return (status); 1012 | } 1013 | InitializeListHead(&block->packet_list); 1014 | } 1015 | 1016 | /* Give interrupt handling priority over timers. */ 1017 | IoInitializeDpcRequest(fdo, kernndis_functbl[6].wrap); 1018 | KeSetImportanceDpc(&fdo->dpc, IMPORTANCE_HIGH); 1019 | 1020 | /* Finish up BSD-specific setup. */ 1021 | block->status_func = (ndis_status_func)kernndis_functbl[0].wrap; 1022 | block->status_done_func = (ndis_status_done_func)kernndis_functbl[1].wrap; 1023 | block->set_done_func = kernndis_functbl[2].wrap; 1024 | block->query_done_func = kernndis_functbl[3].wrap; 1025 | block->reset_done_func = kernndis_functbl[4].wrap; 1026 | block->send_rsrc_func = kernndis_functbl[5].wrap; 1027 | 1028 | TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1029 | 1030 | return (NDIS_STATUS_SUCCESS); 1031 | } 1032 | 1033 | void 1034 | ndis_unload_driver(struct ndis_softc *sc) 1035 | { 1036 | KASSERT(sc->ndis_block->device_ctx == NULL, ("device present")); 1037 | if (sc->ndis_intrhand) /* FIXME: doesn't belong here */ 1038 | bus_teardown_intr(sc->ndis_dev, 1039 | sc->ndis_irq, sc->ndis_intrhand); 1040 | 1041 | if (sc->ndis_block->rlist != NULL) 1042 | free(sc->ndis_block->rlist, M_NDIS_KERN); 1043 | 1044 | TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1045 | if (sc->ndis_chars->transfer_data_func != NULL) 1046 | NdisFreePacketPool(sc->ndis_block->rxpool); 1047 | IoFreeWorkItem(sc->ndis_block->returnitem); 1048 | IoDetachDevice(sc->ndis_block->nextdeviceobj); 1049 | IoDeleteDevice(sc->ndis_block->deviceobj); 1050 | ndis_flush_sysctls(sc); 1051 | } 1052 | --------------------------------------------------------------------------------